1:不可靠信号:信号值小于SIGRTMIN 可以用kill -l 查询,不可靠信号可能会丢了,也就是不支持排队。SIGRTMIN和SIGRTMAX之间的信号支持排队。信号是不是可靠信号与信号安装方式signal或者sigaction无关。
2:信号注册:软中断:给进程表项的信号域设置对应的信号位,如果当前进程可被中断则唤醒,否则仅仅置位。本进程的未决信号:
struct sigpending{
struct sigqueue *head, *tail; // 未决信号信息链首尾,保存信号携带的信息
sigset_t signal; //未决信号集
};
struct sigqueue{ //该信号所携带的信息
struct sigqueue *next;
siginfo_t info;
};
siginfo_t {
int si_signo; /* 信号值,对所有信号有意义*/
int si_errno; /* errno值,对所有信号有意义*/
int si_code; /* 信号产生的原因,对所有信号有意义*/
union{ /* 联合数据结构,不同成员适应不同信号 */
//确保分配足够大的存储空间
int _pad[SI_PAD_SIZE];
//对SIGKILL有意义的结构
struct{
...
}...
信号在进程中注册就是把信号加入到未决信号集中,他的信息保存到sigqueue节点中,只要信号在未决信号集中就表明进程已经知道该信号了但是还没来得及处理或者被阻塞。
实时信号就是不管这个信号是不是已经注册进去,都会再注册一次所以不会丢失。非实时信号就是如果这个信号已经在队列中(被注册一次了)就不在注册了,所以会造成信号丢失。
3:信号执行和注销
内核处理信号是在该信号产生的上下文中,从内核态返回到用户空间时会检测是否有信号等待处理,如果有则在调用相应信号处理函数之前先把信号从未决信号链中删掉。如果非实时信号,先删除节点再handle,如果是实时信号,则全部handles处理完再集中删除。
当所有未决信号都处理完即可返回用户态,对于被屏蔽的信号,如果取消屏蔽则返回用户态时会再次检测同上。
如果进程受到一个要捕捉的信号,在进程从内核态转换到用户态时执行用户定义函数【内核在用户栈上创建一个新的层,该层将返回的地址设置成用户定义的handles函数地址,handle函数返回之后弹出栈顶时,返回原来进入内核地方:目的用户自定义处理函数不能在内核态下运行】。
对于32位系统(每个字32位),信号最多有32种,对于64位系统(每个字64位)信号最多有64种(/include/asm/signal.h)。内核中中断的响应和处理都是在内核态,信号的响应在内核态,处理在用户态。内核中不存在信号优先级,的那个多个信号发出时进程以任意顺序处理信号。
4:信号安装:
signal(signum, signal_handle_fun)
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
s第二、三参数为NULL时候可检测信号。igaction结构定义如下:
struct sigaction {
union{
__sighandler_t _sa_handler; //
void (*_sa_sigaction)(int,struct siginfo *, void *); //信号处理函数,siginfo携带了信号的详细信息的结构体
}_u
sigset_t sa_mask; //信号屏蔽字
unsigned long sa_flags; //信号标志位
}
5信号发送:kill(pid_t pid, signo) pid = 0:同一个进程组进程、= -1:除进程以外所有>1的进程、signo=0检测进程是否存在是否有发送权限等等。【非root只能向同一个用户发送信号:errno=EINVAL:信号无效,ESRCH:进程无效,EPERM:进程无权限发信号】
sigqueue(pid_t pid, int sig, const union sigval val)与sigaction配合使用。
setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)函数:
struct itimerval {
struct timeval it_interval; /* 下一次的取值:下次计时值,如果是0下次停止*/
struct timeval it_value; /* 本次的设定值:本次计时结束发送一个ALRM信号,之后该变量被设置为it_interval值*/
};
该结构中timeval结构定义如下:
struct timeval {
long tv_sec; /* 秒 */
long tv_usec; /* 微秒,1秒 = 1000000 微秒*/
};
eg:>>>>>>>>>>>>>>>>>>>>>>>>>>>>
signal(SIGVTALRM, sigroutine);
value.it_value.tv_sec = 1;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 1;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue);
eg:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
信号集及其操作函数:
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t
信号集屏蔽的作用:就是将不用的信号暂时遮掩起来等用的时候或者恢复环境时候在拿去遮掩。
实例:不同进程之间传递信号:
信号接收程序:
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{ struct sigaction act;
int sig;
pid_t pid;
pid=getpid();
sig=atoi(argv[1]);
sigemptyset(&act.sa_mask);
act.sa_sigaction=new_op;
act.sa_flags=SA_SIGINFO;
if(sigaction(sig,&act,NULL)<0)
{
printf("install sigal error\n");
}
while(1)
{
sleep(2);
printf("wait for the signal\n");
}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
printf("the int value is %d \n",info->si_int);
}
信号发送程序:
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
main(int argc,char**argv)
{
pid_t pid;
int signum;
union sigval mysigval;
signum=atoi(argv[1]);
pid=(pid_t)atoi(argv[2]);
mysigval.sival_int=8;//不代表具体含义,只用于说明问题
if(sigqueue(pid,signum,mysigval)==-1)
printf("send error\n");
sleep(2);
}