linux调用信号处理程序后返回,如何在Linux上执行异步信号处理程序?

本文详细解析了Linux中单线程和多线程环境下信号的传递规则,强调了线程组的概念、信号处理方式(如sigwaitinfo和tgkill)、信号阻塞与挂起,以及处理程序的执行流程。Linux与SCOUnix的区别也做了对比,特别提到了信号调度代码在内核中的实现细节。
摘要由CSDN通过智能技术生成

Source#1(Andries Brouwer)对于单线程进程是正确的 . 源#2(SCO Unix)对于Linux是错误的,因为Linux不喜欢sigwait中的线程(2) . 关于第一个可用的线程,Moshe Bar是正确的 .

Which thread gets the signal? Linux的手册页是一个很好的参考 . 进程使用带有CLONE_THREAD的clone(2)来创建多个线程 . 这些线程属于"thread group"并共享一个进程ID . 克隆手册(2)说,

可以使用kill(2)将信号作为整体(即,TGID)发送到线程组,或者使用tgkill(2)发送到特定线程(即,TID) . 信号处理和操作在整个过程中:如果未处理的信号被传递给线程,那么它将影响(终止,停止,继续,被忽略)线程组的所有成员 . 每个线程都有自己的信号掩码,由sigprocmask(2)设置,但信号可以是挂起的:对于整个进程(即,可传递给线程组的任何成员),当与kill(2)一起发送时;或者与tgkill(2)一起发送的单个线程 . 对sigpending(2)的调用返回一个信号集,该信号集是整个过程中待处理的信号和为调用线程挂起的信号的并集 . 如果使用kill(2)向线程组发送信号,并且线程组已经为信号安装了一个处理程序,那么将在没有阻塞该线程组的线程组中任意选择的一个成员中调用该处理程序 . 信号 . 如果组中的多个线程正在等待使用sigwaitinfo(2)接受相同的信号,则内核将任意选择其中一个线程来接收使用kill(2)发送的信号 .

Linux不是SCO Unix,因为Linux可能会向任何线程发出信号,即使是某些线程线程正在等待信号(使用sigwaitinfo,sigtimedwait或sigwait),而某些线程则没有 . sigwaitinfo(2)的手册警告说,

在正常使用中,调用程序通过事先调用sigprocmask(2)来阻塞set中的信号(这样,如果它们在连续调用sigwaitinfo()或sigtimedwait()之间变为挂起,则不会发生这些信号的默认处置)并且不为这些信号 Build 处理程序 . 在多线程程序中,应该在所有线程中阻塞信号,以防止信号在调用sigwaitinfo()或sigtimedwait()之外的线程中根据其默认处置进行处理 .

为信号选择线程的代码位于linux/kernel/signal.c(链接指向GitHub 's mirror). See the functions wants_signal() and completes_signal(). The code picks the first available thread for the signal. An available thread is one that doesn' t阻塞信号并且队列中没有其他信号 . 代码首先检查主线程,然后检查其他线程如果没有线程可用,那么信号会被卡住,直到某个线程解除阻塞信号或清空其队列 .

What happens when a thread gets the signal? 如果有信号处理程序,则内核会使线程调用处理程序 . 大多数处理程序在线程堆栈上运行 . 如果进程使用sigaltstack(2)提供堆栈,则处理程序可以在备用堆栈上运行,而使用SA_ONSTACK sigaction(2)来设置处理程序 . 内核将一些东西推到所选的堆栈上,并设置一些线程的寄存器 .

要运行处理程序,该线程必须在用户空间中运行 . 如果线程在内核中运行(可能是系统调用或页面错误),那么在它进入用户空间之前它不会运行处理程序 . 内核可以中断一些系统调用,因此线程现在运行处理程序,而不等待系统调用完成 .

信号处理程序是一个C函数,因此内核遵循体系结构调用C函数的约定 . 每个架构,如arm,i386,powerpc或sparc,都有自己的约定 . 对于powerpc,要调用handler(signum),内核将寄存器r3设置为signum . 内核还将处理程序的返回地址设置为信号trampoline . 返回地址按照惯例进入堆栈或寄存器 .

内核在每个进程中放置一个信号trampoline . 这个trampoline调用sigreturn(2)来恢复线程 . 在内核中,sigreturn(2)从堆栈中读取一些信息(如保存的寄存器) . 在调用处理程序之前,内核已将此信息推送到堆栈上 . 如果系统调用中断,内核可能会重新启动调用(仅当处理程序使用SA_RESTART时),或者使用EINTR失败,或者返回短读或写 .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值