信号相当于DOS下的Int或者Windows下的消息。
用Kill –l命令可以查看各种信号信息。
用man 7 signal可查看各个信号的具体解释。
软件原因和硬件原因都会产生信号。
常用的发信号的函数包括:
kill
raise
alarm
setitimer
kill(pid_t pid , int sig)
调用kill可以向任何进程组或者进程发送任何信号。
Raise用来向自己发送信号sig,它等于kill(getpid(),sig)
Alarm函数在seconds秒后向自己发送一个SIGALRM信号。比如下面程序:
#include <stdio.h>
#include <unistd.h>
main()
{
unsigned int i;
alarm(1);
for(i = 0; 1 ; i++)
printf("I = %d",i);
}
SIGALRM的缺省操作是结束进程,因此1秒钟以后,你可以看到最后的I值是多少。
使用信号屏蔽可以使进程不受到信号的打扰。信号屏蔽用到几个函数:
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
int sigismember(sigset_t *set,int signo);
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);
下面例子演示了函数的使用:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
double y;
sigset_t intmask;
int i;
int repeat_factor;
if(argc != 2)
{
fprintf(stderr,"Usage:%s repeat_factor\n\a",argv[0]);
exit(1);
}
if((repeat_factor = atoi(argv[1])) < 1)
repeat_factor = 10;
sigemptyset(&intmask); //Initializes the signal set given by set to empty.
sigaddset(&intmask,SIGINT); //Add signal of INT Ctrl+C
while(1)
{
//Block signal and no saveed signal set.
sigprocmask(SIG_BLOCK,&intmask,NULL);
fprintf(stderr,"SIGINT signal blocked\n");
for(i = 0; i<repeat_factor ; i++)
fprintf(stderr,"blocked calculation is finished\n");
//UnBlock signal
sigprocmask(SIG_UNBLOCK,&intmask,NULL);
fprintf(stderr,"SIGINT signal unblocked\n");
for(i = 0; 1<repeat_factor ; i++)
fprintf(stderr,"Unblocked calculation is finished\n");
}
exit(0);
}
另一个有用的函数是sigaction,用来指定一个信号的处理行为。下面例子捕捉Ctrl+C的信号,并输出一个提示。
//function sigaction test.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define PROMPT "Do you want to exit this program?"
char * prompt = PROMPT;
void ctrl_c_op(int signo)
{
write(STDERR_FILENO,prompt,strlen(prompt));
}
int main(int argc,char **argv)
{
struct sigaction act;
act.sa_handler = ctrl_c_op;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGINT,&act,NULL) < 0)
{
fprintf(stderr,"Install Signal Action Error:%s\n\a",strerror(errno));
exit(1);
}
while(1);
exit(0);
}
还有一些很用于的关于信号方面的函数,比如:
pause
sigsuspend
sigsetjmp
siglongjmp
上面一些函数对于信号处理来说能够应付一般需要,其实信号的处理远非这些。
PS –A
Man命令是Linux下常用的参考文档。有两个配合使用的命令,就是whatis和。Apropos。whatis是全匹配,apropos是关键字匹配。比如,manager这个词,如果“whatis man”,就匹配不到,但apropos man则能够匹配到。
sysconf函数用来查询运行时的权能。比如,对传递给一个新程序的字符串参数的长度进行限制,可以保护系统不被任意分配内存的要求所破坏。比如下面代码:
#include <stdio.h>
#include <unistd.h>
main()
{
printf("The number of clock ticks per second: %d\n",sysconf(_SC_CLK_TCK));
printf("The maximum length of the arguments to the exec() family of functions: %d\n",sysconf(_SC_ARG_MAX));
printf("The maximum number of files that a process can have open at any time: %d\n",sysconf(_SC_OPEN_MAX));
exit(0);
}
使用uname函数。
下面是一段测试代码,代码破坏了三种内存区域:
l malloc从动态内存池中分配的内存
l 在程序堆上分配的本地变量
l 在程序启动时候被静态分配的并保存在分散内存区域中的全局变量
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char global[5];
int broken(void)
{
char * dyn;
char local[5];
dyn = malloc(5);
strcpy(dyn,"12345");
printf("1: %s \n",dyn);
free(dyn);
dyn = malloc(5);
strcpy(dyn,"12345678");
printf("2: %s \n",dyn);
*(dyn - 1) = '\0';
printf("3: %s \n",dyn);
strcpy(local,"12345");
printf("4: %s \n",local);
local[-1] = '\0';
printf("5: %s \n",local);
strcpy(global,"12345");
printf("6: %s \n",global);
global[-1] = '\0';
printf("7: %s \n",global);
return 0;
}
int main(void)
{
return broken();
}
尽管从代码中已经发现问题,但实际上程序运行得很好。下面是结果。
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 364.5pt; HEIGHT: 123pt" type="#_x0000_t75"><imagedata o:title="001" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msoclip1/01/clip_image001.jpg"></imagedata></shape>
为了发现问题,需要借助调试工具:
MALLOC_CHECK_,工具用于进行堆数据结构得一致性检查。有几种调试参数:
MALLOC_CHECK_=0 ./broken
MALLOC_CHECK_=1 ./broken
MALLOC_CHECK_=2 ./broken
最有用的是最后一句,一旦发现错误,工具将把我们带到错误发生点最近的地方。
这样用则更好:
$ MALLOC_CHECK_2 gdb ./broken
下面是部分调试信息:
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public Licen se, and you are
welcome to change it and/or distribute copies of it under cer tain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty " for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) r
Starting program: /home/lx/csource/bugtest/broken
1: 12345
Program received signal SIGABRT, Aborted.
0xffffe002 in ?? ()
(gdb) where
#0 0xffffe002 in ?? ()
#1 0x42028a73 in abort () from /lib/tls/libc.so.6
#2 0x42075e09 in free_check () from /lib/tls/libc.so.6
#3 0x42073485 in free () from /lib/tls/libc.so.6
#4 0x0804840b in broken ()
#5 0x08048500 in main ()
#6 0x42015574 in __libc_start_main ()
from /lib/tls/libc.so.6
(gdb)
另一种调试方法是链接mcheck库函数,方法是:
[lx@ssss bugtest]$ gcc -ggdb -o broken broken.c -lmcheck
[lx@ssss bugtest]$ ./broken
1: 12345
memory clobbered past end of allocated block
mcheck只能打印错误信息,并不能指明错误所在,因此需要在gdb内运行程序。
带奇数的内核版本(即 2.3、2.5、2.7 等)是实验性的开发版内核。稳定的发行版内核的版本号是偶数(即 2.4、2.6、2.8 等)。
=待续=