信号

信号的产生、阻塞以及捕捉

用kill -l命令可以查看系统定义的信号列表:

spacer.gifwKioL1ebTirhzKZ6AAEYpHnSCJY134.png-wh_50

一、产生信号

1、如何产生信号?

(1)通过终端按键产生信号

    SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且 Core Dump,那么到底什么是Core Dump?

    当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常是core,这叫做Core Dump。进程异常终止通常是因为有 Bug,比如非法内存访问导致段错误,事后可以用调试器检查core文件以查清错误原因,这叫做 Post-mortem Debug。一个进程允许产生多大的core文件取决于进程的Resource Limit(这 个信息保存在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文 件。

    首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K:

wKioL1ebTp6CZzxYAADAv6iRZlw540.png-wh_50

    测试代码:

:wKioL1ebTrby25PHAADY9HuK0zE515.png-wh_50

(2)调用系统函数向进程发信号

    如:

    1、kill函数:给指定的进程发送指定的信号

wKiom1ebT3rTkFHnAABBahNgb9M571.png-wh_50

    2、raise函数:可给当前进程发送指定的信号(自己给自己发送信号)

wKioL1ebT-mR7sN8AAArzLDltyg913.png-wh_50

    3、abort函数:使当前进程接受到SIGABRT信号而异常终止

wKiom1ebT_jQ34nXAABATWT1rTs713.png-wh_50

    4、signal函数:设置某一信号的对应动作

wKioL1ebUDizZi6rAAAbUxachsA820.png-wh_50

    测试代码:

wKioL1ebUF2A1gPhAABCcRIHgpA353.png-wh_50wKiom1ebUF3TgZE6AAAQ8heDCcI530.png-wh_50

(3)由软件条件产生信号

    如:alarm函数:在seconds秒后给当前进程发送SIGALRM信号,默认终止当前进程。

wKiom1ebURORiohwAABbzywuhwg450.png-wh_50

wKioL1ebURTChVYaAACk3HOf6OE223.png-wh_50

wKiom1ebURSy5oEdAAAJOkSl5bc169.png-wh_50

(4)kill命令行命令,如下:

wKioL1ebUbTx8sYQAAANuyxdpEM692.png-wh_50

2、如何处理信号

     (1)忽略此信号

     (2)执行该信号的默认处理动作

     (3)提供一个信号处理函数,要求内核在处理该信号是切换时切换到用户态执行这个处理函数,也称捕捉一个信号。


二、阻塞信号

    实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞 (Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞, 才执行递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

    信号在内核中的表示示意图:

wKiom1ebUeiCi9sDAABi2Oj6Btw744.png-wh_50

    每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。

    1、SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。

    2、SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没 有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

    3、SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。

     每个信号只有一个bit的未决标志和阻塞标志,非0即1,不记录该信号产生的次数。因此,未决和阻塞标志可以用相同的数据类型sigset_t储存,sigset_t称为信号集。这个类型表示信号的有效和无效状态。在阻塞信号集(信号屏蔽字)中即block表,1表示信号阻塞,0表示不阻塞。在未决信号集即pending表,1表示信号产生未决状态,0表示没有产生信号。阻塞信号集也称为当前进程的信号屏蔽字(Singal Mask)。这里的屏蔽应该理解为阻塞而不是忽略。


注:不可使用位操作操作信号集,有专有的函数操作

    信号集操作函数:

wKioL1ebUozRcchWAAAzFUQs8Qg439.png-wh_50

    sigemptyset函数:初始化set所指向的信号集,将其中所有的信号对应的bit位清零,表示该信号集不包含任何有效信号。

    sigfillset函数:初始化set所指向的信号集,使其中所有的信号对应的bit置位,表示该信号集的有效信号包括系统支持的所有信号。

    sigaddset函数:在该信号集中添加某一信号。

    sigdelset函数:在该信号集中删除某一个信号。

    sigismember函数:判断某一个信号是否在该信号集中。

    注意:在使用sigset_t类型的变量之前,一定要调用sigemptyset和sigfillset做初始化处理,使信号集处于确定的状态。初始化之后就可以在该信号集中增加,删除某种有效信号等操作。


    sigprocmask函数:读取或更改进程中的信号屏蔽字(即阻塞信号集)

wKioL1ebUxDAHByiAABBzvE463s289.png-wh_50

    如果set是非空指针,则读取进程的当前信号屏蔽字通过oldset参数传出。

wKiom1ebUy_Ck59XAAFu2XGn4fA550.png-wh_50

    sigpending函数:读取当前信号集的未决信号集

wKioL1ebU5yiz47xAAAOW5fm45Q714.png-wh_50

    测试代码:

wKiom1ebU7HzChSKAABCeViWVH8284.png-wh_50

wKioL1ebU7Lj9KymAADWFfO6hyA287.png-wh_50

    运行效果:

wKiom1ebU7Kgp1KzAABfQg3MnMA384.png-wh_50


三、捕捉信号

     一次信号捕捉的过程需要进行4次权限的切换。

wKiom1ebVDTQdI-mAAICzOgEHa4908.png-wh_50

    当一个进程接受到信号时,并不是立即进行处理,而是在合适的时候处理,所谓合适是指从内核态返回用户态时切换处理信号。当内核处理完异常或中断时,会先检查当前进程中是否有可以被递达的信号,若有,且信号的处理动作是自定义的信号处理函数,则从内核调到用户态执行代码,之后进入内核态,从内核态返回用户态即上次被中断或异常的地方,若信号的处理方式是默认,则终止进程,若忽略,则从penging表中删除该信号,即将1变为0,直接跳到用户态。


    sigaction函数:读取和修改与指定信号相关联的处理动作。

wKioL1ebVF_hSRX-AABEC4idXfo863.png-wh_50

    参数:

    signo:信号的编号

    act:非空时,根据act修改该信号的处理动作

    oact:非空时,传出该信号原来的处理动作

    act和oact结构体如下:

wKioL1ebVI_z0Ub5AAAo_f5-9Uk180.png-wh_50

    将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL 表示执行系统默认动作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册 了一个信号处理函数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信 号的编号,这样就可以用同一个函数处理多种信号。显然,这也是个回调函数,不是被main 函数调用,而是被系统所调用。

sa_mask:需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

sa_flags:包含一些选项


    pause函数:使调用的进程挂起直到有信号递达。

wKioL1ebVOuyxJK9AAAnimfkCGs254.png-wh_50

    1、信号的处理动作是终止,则进程终止,不执行pause(即来不及执行该函数)。

    2、信号的处理动作是忽略,则进程继续处于挂起,pause不返回。

    3、信号的处理动作是捕捉,则调用信号处理函数后返回-1.


    测试代码:

wKiom1ebVRjDXLunAAA_Oh0Ek-Q265.png-wh_50

wKiom1ebVRigTnhmAAAYQKatoIo036.png-wh_50

    运行效果:

wKioL1ebVRjTvMbiAAAWRRZbc4Y265.png-wh_50

    

测试普通信号中哪些可以被捕捉到,哪些不能被捕捉到。

    测试代码:

wKioL1ebVbXh5xvDAABMGAJ4U30950.png-wh_50

wKiom1ebVbXAuPTpAAA8yWZfQQA181.png-wh_50

wKiom1ebVbXB4n0VAABJjGbs_LU801.png-wh_50

    结论:除了9和19号信号,其他的普通信号都可以被捕捉到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章