大二下学期就已经看完了这本书,但是一直没有小结,最近在看UNP2,涉及到这一块,乘机总结一下.。
-
信号实质是一个软中断,每一个信号都有一个名字,SIGXXX。 首先,我信号分为实时信号(可靠信号),不可靠信号。
可靠信号指的是有实时行为的,即
1:信号是排队的
2:当有多个SIGRTMIN到SIGRTMAX的信号范围的解阻塞信号排队时,较小的值优先与较大的值。
3:当非实时信号提交时,信号处理函数只需要该信号的值,但是实时信号需要更多的内容 比如实时处理函数的原型是:
void func(int signo, siginfo_t*, void* context); typedef struct { int si_sigo; int si_code; union sigval si_value; } siginfo_t
其中,si_code 表示信号产生源,比如SI_ASYNCIO(表示有某个异步IO请求的的完成产生),si_value 是application -specific value
而信号处理函数的注册,却不仅仅是signal函数,而是sigaction函数,其原型是:
#include<signal.h> int signation(int sigo, const struct sigaction * restrict act, struct sigaction * restrict oact ); struct sigaction { void (*sa_handler)(int); //addr of singal handler; sigset_t sa_mask; //addition singal to block; int sa_flags; // singal option: SA_XXX void (*sa_sigaction)(int , siginfo_t* , void* ); //addr of signal handler if SA_SIGINFO set; }
这个是信号里面的实时信号的内容。(按照UNP2第五章内容理解的,上一学期只是看了,并未有这么比较清楚的例子) 下面我按照书本的顺序,总结一下。 函数signal
原型: void (*signal (int signal, void (*func)(int))) (int);
这个函数有点复杂。简化如下:
typedef void Sigfunc(int); Sigfunc* signal(int, Sigfunc(int));
其中 有以下几个定义;
#define SIG_ERR (void (*) ()) -1; #define SIG_DFL (void(*) ()) 0; #define SIG_IGN (void (*)()) 1;
这些都是很常规的函数。
考虑当函数中执行exec函数,那么新的代码段的信号处理函数和以前的需要变化吗?即以前注册的信号处理函数会怎么办? 当执行力exec函数后,以前注册的信号处理函数全部变为默认的,以前SIG_DEL的保持不变。 以前注册的函数地址,在执行exec后很有可能变得没有意义。。。所以要变为默认的。
在执行fork函数后,应为子进程在开始时候复制了子进程内存映像,所以函数地址还是有意义的。 中断的系统调用
早期unix系统的一个特性是; 当进程在执行一个低速系统调用而阻塞期间捕获到一个信号,则该系统调用就被中断,不再执行,该系统调用出错,其erron设置为EINTR; 低速系统调用是指可能会使进程永远阻塞的一类系统调用。
1,如某些类型文件数据不存在(如读管道,终端设备,网络设备),则读操作可能会使调用者永远阻塞。也就是阻塞到读上面. 2,如果数据不能被相同的文件类型接受,则写操作可能会被调用者永远阻塞。也就是写阻塞。 3.在某种条件发生之间打开某些类型文件 4.pause 5.ioctl
6.进程间通讯函数。比如FIFO中,read在不设置阻塞的情况下会阻塞,知道有数据写入。 这里值得注意的是,有些系统引入自动重启功能。 这在各个系统中有不同的定义。但是新的函数sigaction函数里面提供了是否字段重启的选项(但并非每个实现都是这样);
可重入函数
可重入函数是指在中断函数调用的函数,其调用不会影响被中断的函数。 函数不可重用的原因有三: 1.使用静态数据结构 2.调用malloc或free 3.标准IO SIGCLD
这个主要讲的是在的system V中,对SIGCLD处理有点不同。 1)如果进程明确的将信号配置位SIG_IGN,那么调用进程将不产生僵尸进程。虽然其SIG_DEL的处理方式是“忽略”掉该信号,但两者不同。如果设置了SIG_IGN,那么wait函数将会一直阻塞知道所有子进程终止,然后返回-1,errno设置为ECHILD. 2)如果将ISIGCLD 配置为捕捉,那么内核立即检查是否有子进程准备好被等待,如果是这样,那么调用SIGCLD. 但是在有些系统上SIGCLD和SIGCHLD定义是一样的。不会出现上述的行为,是一个普通信号。