2011-11-24 第十章 信号
第一节
第二节
1,linux将信号定义在<bits/signum.h>中。signal函数声明在<signal.h>中。<signal.h>include<bits/signum.h>。
2,程序要求内核对信号的处理可以是三种方式:忽略,捕捉和默认。
3,SIGKILL和SIGSTOP信号不能忽略,也不能捕捉。
第三节
1,signal在linux的声明
typedef void (*__sighandler_t) (int);
extern __sighandler_t signal (int __sig, __sighandler_t __handler)
__THROW;
2,SIG_ERR,SIG_DFL和SIG_IGN的定义
#define SIG_ERR
((__sighandler_t) -1)
/* Error return. */
#define SIG_DFL
((__sighandler_t) 0)
/* Default action. */
#define SIG_IGN
((__sighandler_t) 1)
/* Ignore signal. */
怀疑书上有错:
”如果查看系统的头文件<signal.h>,则很可能会找到下列形式的声明:
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1
“
似乎应该是 (void (*)(int))这个函数指针类型。
第四节 不可靠信号
1,早期的unix版本,信号是不可靠的。
两个原因:
一,信号动作自动复位为默认值。若信号处理期间重新进行信号动作注册,则会存在一个时间窗口。该时间窗口可能会让信号的默认动作终止程序。
二,不能阻塞信号。若自定义信号发生标记,同样存在一个时间窗口。
第五节 中断的系统调用
1,低速系统调用是可能会使进程永远阻塞的一类系统调用。
2,早期unix特性:如果进程执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用就被中断不再继续执行。
3,为了帮助应用程序使其不必处理被中断的系统调用,4.2BSD引入了某些被中断系统调用的自动重启动。
第六节 可重入函数
1,可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。(百度百科)
第七节 SIGCLD语义
1,linux平台上,SIGCLD等价于SIGCHLD。
2,linux平台,如果调用signal或者sigset将SIGCHLD的配置设置为忽略,则绝不会产生僵死子进程。
3,当进程安排捕捉SIGCHLD,并且已经有进程准备好由其父进程等待时,该系统并不调用SIGCHLD信号的处理程序。
第八节 可靠信号术语和语义
1,内核在递送一个原来被阻塞的信号给进程时(而不是在产生该信号时),才决定对它的处理方式。
2,在信号产生和递送之间的时间间隔内,称信号是未决的。
3,如果在进程解除对某个信号的阻塞之前,这种信号发生了多次,则除非支持POSIX.1实时扩展,否则大多数UNIX并不对信号排队,代之以UNIX内核只递送这种信号一次。
4,POSIX.1并没有规定当多个信号要递送给一个进程的时候该如何处理,但POSIX.1的Rationale建议,优先递送与进程状态有关的信号。
第九节 kill和raise函数
1,kill函数将信号发送给进程或进程组,raise函数则允许进程向自身发送信号。
2,如果调用kill使其为调用者产生信号,并且如果该信号是不被阻塞的,则在kill返回前该信号或某个未决的非阻塞信号递送给该进程。
第十节 alarm和pause函数
1,如果不忽略或不捕捉SIGALRM信号,则其默认动作是终止调用该alarm函数的进程。
2,每个进程只能有一个闹钟时钟。
3,每次调用alarm,均以新参数重新计时,返回上次闹钟余值。以0参数调用alarm,则取消闹钟并返回闹钟余值。
4,pause函数使调用进程挂起直到捕捉到一个信号。
5,alarm函数可能引起的问题:
a,可能擦除前一次的alarm。
b,修改了对SIGALRM的信号处理配置。
c,alarm其后的语句执行有竞争条件,期间程序可能挂起,使alarm超时。
d,可以使用setjmp解决问题c,但是又引入了另一个问题:longjmp可能提前终止其他信号处理程序。
e,对于自动重启的低速系统调用,alarm并不起作用。
第十一节 信号集
1,信号集:一个表示多个信号的数据类型。
2,linux信号集sigset_t在<signal.h>如下定义:
# define _SIGSET_NWORDS
(1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;
...
typedef __sigset_t sigset_t;
3,处理信号集的五个函数:
#include <signal.h>
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(const sigset_t *set,int signo);
第十二节 sigprocmask函数
1,信号屏蔽字:当前阻塞而不能递送给该进程的信号集。(个人理解:当信号产生的时候,不递送给进程的信号的集合。)
2,函数sigprocmask可以检测或(和)更改其信号屏蔽字。
第十三节 sigpending函数
1,信号阻塞:信号在当前信号屏蔽字里,则称该信号是阻塞的。(个人理解)
2,如果产生了一个被设置为阻塞的信号,则称该信号是未决的,直到该信号被设置为非阻塞或者忽略。
3,使用sigprocmask将某些信号设置为非阻塞,则在该函数返回前,至少会有一个信号递送给进程。
4,ubuntu11.04没有对信号进行排队。
5,未决信号集(个人概念):使用sigpending获得的一个信号集,该信号集必定是当前信号屏蔽字的一个子集。该信号集内的信号都必定是已经产生了的。
5,
《unix环境高级编程第二版》10.13 sigpending函数:
有这样一段描述:
中文版-在休眠期间如果产生了退出信号,那么此时信号是未决的,但是不再受阻塞,所以在...
英文版-If we generate the quit signal during this sleep period, the signal is now pending and unblocked, so it is...
我觉得,这个时候的信号依然是阻塞的!不然,按这样的描述,书上就有点矛盾了。
第十四节 sigaction函数
1,该函数是检测和修改信号相关联的处理动作,其标记参数提供了比signal函数更多的选项功能。
第十五节 sigsetjmp和siglongjmp函数
1,如果参数savemask非0,则sigsetjmp在env中保存进程的当前信号屏蔽。调用siglongjmp时,如果带非0savemask的sigsetjmp调用已经保存了env,则siglongjmp从其中恢复保存的信号屏蔽字。
2,要注意采用保护机制,使得在jmpbuf尚未由sigsetjmp初始化时,调用信号处理程序。
第十六节 sigsuspend函数
1,sigsuspend函数在一个原子性操作中,先设置其参数指定的信号屏蔽字,然后使进程休眠。如果捕捉到一个信号(不属于屏蔽字的)而且从信号处理程序返回,则sigsuspend返回,并将信号屏蔽字恢复为调用sigsuspend之前的值。
2,如果在等待信号发生的时候希望去休眠,则使用sigsuspend函数是非常适合的。
3,如果在等待信号期间希望调用其他系统函数,那么在单线程环境下对此问题没有妥善的解决办法。(未懂解析原因)
第十七节 abort函数
1,POSIX.1说明abort并不理会进程对SIGABRT信号的阻塞和忽略。
2,如果进程捕捉SIGABRT而且不在信号处理程序中终止自己,POSIX.1声明当信号处理程序返回的时候,abort终止进程。
3,POSIX.1要求如果abort调用终止进程,则它对所有打开标准I/O流的效果应当与进程终止前对每个流调用fclose相同。
第十八节 system函数
1,POSIX.1要求system忽略SIGINT和SIGQUIT,阻塞SIGCHLD。
2,因为system执行的命令可能是交互式命令,以及因为system的调用着在程序执行时放弃了控制,等待改执行程序的结束,所以system的调用着就不应当接收这两个终端产生的信号。
3,system的返回值是shell的返回值,但是shell的终止状态并不总是执行命令字符串的终止状态。
4,Bourne shell的终止状态是128加上一个信号编号,该信号终止了正在执行的命令。
5,仅当shell本身异常终止的时候,system的返回值才报告一个异常终止。
6,在编写使用system函数的程序的时候,一定要正确解析返回值。如果直接调用fork,exec和wait,则终止状态与调用system是不同的。
第十九节 sleep函数
1,此函数使调用进程被挂起,直到满足以下条件之一:
a,已经过了参数所指定的墙上时钟时间,返回0。
b,调用进程捕捉到一个信号并从信号处理程序返回,此时返回未休眠够的秒数。
如果alarm信号一样,由于其他系统活动,实际返回时间比所要求的会迟一些。
2,FreeBSD 5.2.1,linux 2.4.22和Mac OS X 10.3使用nanosleep提供时间延迟,该函数由Single UNIX Specification的实时扩展说明,它提供的时间延迟是高分辨率的,该函数可以使sleep的实现与信号无关。
第二十节 作业控制信号
1,当对一个进程产生四种停止信号(SIGTSTP,SIGSTOP,SIGTTIN或SIGTTOU)中的任意一种时,对同一进程的任一未决SIGCONT信号将被丢弃。与此类似,当对一个进程产生SIGCONT信号时,对同一进程的任一未决停止信号将被丢弃。
2,如果进程是停止的,SIGCONT的默认动作是继续运行该进程,否则忽略此信号。通常,对该信号无需做任何事情。当对一个停止的进程产生一个SIGCONT信号时,该进程就继续运行,即使该信号是被阻塞或忽略的也是如此。
第二十一节 其他特征
1,信号名字相关:char *sys_siglist[],void psignal(int signo,const char *msg),char *strsignal(int signo).
第二十二节 小结
PS:每天晚上熄灯之后看一点,半个多月的时间终于把这章看完了第一遍。2011-12-4