当前位置: 首页 > 科技观察

linux下如何捕获信号

时间:2023-03-11 23:20:58 科技观察

信号的处理方式有以下三种:忽略信号默认的处理动作来捕获信号如果信号的处理动作是用户自定义函数,调用这个用户自定义函数传递信号时,这称为捕获信号。进程收到信号后,不会立即处理,而是会在合适的时候处理!也就是在内核态回到用户态之前!但是由于信号处理函数的代码在用户空间,这就增加了内核处理信号捕获的复杂度。内核实现信号捕获的步骤:用户为某个信号注册一个信号处理函数sighandler。当前正在执行主程序。这时由于中断、异常或系统调用进入内核态。在处理完异常返回用户态主程序前,检查是否有未处理的信号,发现该信号需要根据用户自定义函数进行处理。内核决定返回用户态执行sighandler函数,而不是恢复main函数的上下文继续执行!(sighandler和main函数使用不同的栈空间,它们之间没有调用和被调用的关系,是两个独立的控制进程)sighandler函数返回后,从用户态执行一个特殊的系统调用sigreturn到内核态检查是否有其他信号需要传递。如果不是,则返回用户态,恢复主程序的上下文信息继续执行。signal为某个进程的某个信号(标为signum)注册对应的处理函数,即修改信号的默认处理动作,修改为handler函数指向的方式;#includetypedefvoid(*sighandler_t)(int);sighandler_tsignal(intsignum,sighandler_thandler);
//即:
void(*signal(int,void(*)(int)))(int);signal函数接受两个参数:整数信号编号和指向用户定义的信号处理程序的指针。另外,信号函数的返回值是一个指针,用来调用用户自定义的信号处理函数。sigactionsigaction函数可以读取和修改与指定信号关联的处理动作。#includeintsigaction(intsignum,conststructsgaction*act,structsigaction*oldact);structsgaction{void(*sa_handler)(int);//信号处理方法void(*sa_sigaction)(int,siginfo_t*,void*);//实时信号的处理方法暂且不谈sigset_tsa_mask;//附加屏蔽信号intsa_flags;void(*sa_restorer)(void);};signum为指定信号的个数。处理方法:如果act指针不为空,根据act结构体中的信号处理函数修改信号处理动作。如果oact指针不为空,信号的原始处理动作将通过oact传递。现在把原来的处理动作备份到oact,然后根据act修改信号处理动作。(注意:最后两个参数既是输入参数也是输出参数!)sa_handler有3种选择:给sigaction赋一个常量SIG_IGN,表示忽略信号;赋一个常量SIG_DFL表示执行系统的默认动作;分配一个函数指针来指示使用自定义函数来捕获信号,或者向内核注册一个信号处理函数。这个函数的返回值为void,可以带一个int参数。通过参数可以知道当前信号的个数,这样就可以使用同一个函数来处理多个信号。(注意:这是一个回调函数,不是被主函数调用,而是被系统调用)当一个信号处理函数被调用时,内核自动将当前信号添加到进程的信号掩码字中,当信号processing函数返回在处理某个信号时自动恢复原来的信号掩码字,这样如果在处理某个信号时再次产生该信号,就会阻塞直到本次处理结束。pausepause函数暂停调用进程,直到信号到达!#includeintpause(void);处理方式:如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;如果信号是忽略处理动作,则进程继续挂起,pause不返回;如果信号处理动作是捕获,pause在调用信号处理函数后返回-1,errno设置为EINTR。所以pause只有一个错误返回值(类似于exec函数族)。错误代码EINTR表示“被信号中断”。举个栗子来定义一个闹钟。在约定的times秒后,内核向进程发送SIGALRM信号;调用pause函数暂停进程,内核切换到另一个进程运行;times秒后,内核向进程发送SIGALRM信号,发现其处理动作是自定义函数,于是切换回用户态执行自定义处理函数;进入sig_alrm函数时自动屏蔽SIGALRM信号,从sig_alrm函数返回时自动取消屏蔽SIGALRM信号。然后自动执行特殊系统调用sigreturn再次进入内核,然后回到用户态继续进程的主控制流程(main函数调用的mytest函数)。pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号前的处理动作。/********************************************************************************>FileName:Pause.c>Author:Lynn-Zhang>Mail:iynu17@yeah.net>CreatedTime:Sun14Aug201612:27:03PMCST**********************************************************************************/#include#include#includevoidsig_alarm(intsignum){printf("Iamacustomhandler!\n");}voidmysleep(unsignedinttimes){//注册两个信号处理动作structsigactionnew,old;new.sa_handler=sig_alarm;//信号处理函数sigemptyset(&new.sa_mask);//不屏蔽任何信号Shieldwordnew.sa_flags=0;//修改SIGALRM信号的默认处理动作为自定义处理动作sigaction(SIGALRM,&new,&old);alarm(times);pause();//暂停等待闹钟(1);sleep(2);alarm(0);//取消闹钟//恢复SIGALRM信号为默认处理动作sigaction(SIGALRM,&old,NULL);alarm(1);sleep(2);}intmain(){while(1){mysleep(2);printf("manysecondspassed\n");printf("####################\n");}return0;}定义一个闹钟,暂停等待。收到信号后,执行自定义处理动作。在恢复默认处理动作之前,SIGALRM信号将按照其自定义的处理函数进行处理。恢复自定义处理动作后,如果收到SIGALRM信号,会执行默认的处理动作,终止进程!