linux下信号

信号是很短的信息,可以被发送到一个进程或一组进程。发送给进程的唯一信息通常是一个数,依次来标识信号。

POSIX标准引入了一类新的信号叫做实时信号,在linux中他们的编码范围是32-64.他们与常规信号有很大的不同,因为他们必须排队以便发送的多个信号能被接收到。

如果一个常规信号被连续发送多次,那么,只有其中的一个发送到接收进程。

发送给非运行进程的信号必须由内核保存,知道进程恢复执行。

每个所产生的信号至多被传递一次。信号是可消费资源,一旦他们被传递出去,进程描述符有关这个信号的所有信息被取消。

已经产生但没有传递的信号成为挂起信号。任何时候,一个进程仅存在给定类型的一个挂起信号,同一进程同种类型的其他信号不被排队,只被简单地丢弃。

信号通常只被当前正在运行的进程传递。

当进程执行一个信号处理程序的函数时,通常屏蔽相应的信号,即自动阻塞这个信号知道处理程序结束。信号处理函数是不可重入的。

由内核预定义的缺省操作取决于信号的类型,可以是下列类型之一:1 terminate 进程被杀死 2 进程被杀死,并且如果可能,创建包含进程执行上下文的核心转储文件,这个文件可以用于调试 3 ignore信号被忽略 4 stop进程被停止,即把进程设置为TASK_STOPPED状态 5 如果进程被停止,就把它设置为TASK_RUNNING状态。

SIGKILL和SIGSTOP信号不可以被显示的忽略,捕获或阻塞,通常必须执行它的显示操作。

信号处理程序必须在多线程的所有线程之间共享,不过每个线程必须有自己的挂起信号掩码和阻塞信号掩码。

每个发送给多线程应用的信号仅传送给一个线程,这个线程是由内核在从不会阻塞该信号的线程中随意挑选出来的。

如果向多线程应用发送了一个致命信号,那么内核将杀死该应用的所有线程,而不仅仅是杀死接收信号的那个线程。

不可能给进程0发送信号,而发送给进程1的信号在捕获到他们之前总被丢弃,所以进程0永不死亡,而进程1只有当init程序终止时才死亡。

对属于同一线程组的每个进程而言,信号描述符的字段必须都是相同的。

在一个POSIX的多线程应用中,线程组的所有轻量级进程都引用相同的信号描述符和信号处理程序描述符。

k_sigaction结构既包含对用户态进程所隐藏的特性,也包含大家熟悉的sigaction结构,该结构保存了用户态进程能看见的所有特性。

为了跟踪当前的挂起信号是什么,内核把两个挂起信号队列与每个进程相关联:

共享挂起信号队列,它位于信号描述符的shared_pending字段,存放整个线程的挂起信号

私有挂起信号队列,它位于进程描述符的pending字段,存放特定进程的挂起信号。

specific_send_sig_info()函数向指定进程发送信号。它作用于三个参数:sig (信号编号),info(或者是siginfo表的地址,或者是三个特殊值中的一个,0意味着信号是由用户态进程发的1意味着由内核发送的2由内核发送的SIGSTOP或SIGKILL信号),t 指向目标进程描述符的指针。

内核在允许进程恢复用户态下的执行之前,检查进程TIF_SIGPENDING标志的值,每当内核处理完一个中断或异常时,就检查是否存在挂起信号。

为了处理非阻塞的挂起信号,内核调用do_signal()函数,通常只是在CPU返回到用户态才调用do_signal()函数。

do_signal()函数的核心是由重复调用dequeue_signal()函数的循环组成,直到在私有挂起信号队列和共享挂起队列中都没有非阻塞的挂起信号时,循环才结束。?????

SIGSTOP总是停止线程组,而其他信号只停止不在孤儿进程组中的线程组。

POSIX标 准规定,只要进程组有一个进程有父进程,尽管父进程处于不同的进程组中但在同一个会话中,那么这个进程组就不是孤儿进程。因此,如果父进程死亡,但启动该进程的用户仍然在登录在线,那么该进程就不是一个孤儿。

do_signal_stop()函数检查current是否是在线程组中第一个被停止的进程,如果是,它激活”组停止“,本质上,该函数把一个正数值赋给信号描述符中的group_stop_count字段,并唤醒线程组中的所有进程。

缺省操作为Dump的信号可以在进程的工作目录中创建一个”转储“文件,这个文件列出进程地址空间和CPU寄存器的全部内容。

如果信号有一个专门的处理程序,do_signal()就函数必须强迫该处理程序执行,这是通过调用handle_signal()进行的。

信号处理函数是用户态所定义的函数,并包含在用户态代码段中,handle_signal函数运行在内核态,而信号处理程序运行在用户态,这就意味着在当前进程恢复”正常“执行之前,它必须首先执行用户态的信号处理程序。

当内核打算恢复进程的正常执行时,内核堆栈不再包含被中断程序的硬件上下文,因为每当从内核态 向用户态转换时,内核态堆栈都被清空。

当信号处理程序终止时,自动调用sigreturn系统调用把硬件上下文拷贝回到内核态堆栈中,并恢复用户态堆栈中原来的内容。

为了适当建立进程的用户态堆栈,handle_signal()函数或者调用setup_frame()或者调用setup_rt_frame()。

setup_signal()函数把一个叫做sigframe的数据结构推进用户态堆栈中,这个帧含有处理信号所需要的信息,并确保正确返回到handle_signal()函数。

linux允许进程通过signalstack()系统调用来为他们的信号处理程序指定一个预备的栈。

setup_frame()函数把保存在内核态堆栈的段寄存器内容重新设置成他们的缺省值以后才结束,这时,信号处理程序所需的信息就在用户态堆栈的顶部。

do_signal()返回时,当前进程恢复它在用户态的执行。

当信号处理程序结束时,返回栈顶地址。

sys_sigreturn()函数必须把来自帧的sc字段的进程硬件上下文拷贝到内核态堆栈中,并从用户态堆栈中删除帧,这两个任务是从restore_sigcontext()函数完成的。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值