linux内核-信号

来源:互联网 发布:vb.net 鼠标穿透控件 编辑:程序博客网 时间:2024/04/28 06:17

信号是很短的消息,可以被发送到一个进程或一组进程组。发送给进程的唯一信息通常是一个数,一次来标识信号。使用信号的两个主要目的是:

让进程知道已经发生了一个特定的事件;

强迫进程执行他自己代码中的信号处理程序。

信号的一个重要特点是他们可以随时发送给状态经常不可预知的进程。发送给非运行进程的信号必须由内核保存,直到进程恢复执行。阻塞一个信号要求信号的传递拖延,知道随后解除阻塞,这使得信号产生一段时间之后才能对其传递这一问题变得更加严重。

内核区分信号传递的两个不同阶段:

信号产生:内核更新目标进程的数据结构以表示一个新信号被发送。

信号传递:内核强迫目标进程通过以下方式对信号做出反应:或改变目标进程的执行状态,或开始执行一个特定的信号处理函数,或两者都是。

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

已经产生但还没有传出去的信号叫挂起信号,任何时候,一个进程仅仅存在给定类型的一个挂起信号,同一进程同种类型的其他信号不被排队,制备简单的丢弃。但是实时信号不同:同种类型的实时信号可以有好几个。

一般来说,信号可以保留不可预知的挂起时间。必须考虑下列因素:

  • 信号通常只被当前正运行的进程传递;
  • 给定类型的信号可以有进程选择性的阻塞。这种情况下,在取消阻塞前,进程将不接受信号
  • 当进程执行一个信号处理函数时,通常屏蔽相应的信号,直到信号处理函数结束,所以信号处理函数不必是可重入的。

尽管信号的表示比较直观,但内核的实现相当复杂。内核必须:

记住每个进程阻塞哪些信号

  • 当从内核态切换到用户态是,对任何一个进程都要检查是否有一个信号已经到达。这几乎在每个定时中断时都发生
  • 确定是否可以忽略信号
  • 处理这样的信号,即信号可能在进程运行期间的任一时刻请求吧进程切换到一个信号处理函数,并在这个函数返回以后恢复原来的执行的上下文。

传递信号之前所执行的操作:

进程以三种方式对一个信号做出应答:

  • 显示的忽略信号
  • 执行与信号相关的缺省操作
  • 通过调用相应的信号处理函数捕捉信号

信号阻塞和忽略的差别:只要信号被阻塞,他就不能传递;只有在信号阻塞解除后才能传递。忽略指传递,但没有进一步的操作。

与信号相关的数据结构:对系统中的每个进程来说,内核必须跟踪什么信号当前正在挂起或屏蔽,以及每个线程组是如何处理所有信号。为了完成这些操作,内核使用从几个处理器描述符课存取的数据结构。

sigaction数据结构:一些体系结构把特性赋给内核可见的信号。新词信号的特性存放在k_sigaction结构中,k_sigaction结构既包含对用户态进程所隐藏的特性,也包含大家熟悉的sigaction结构,该结构保存了用户态进程能看见的所有特性,该结构包含以下字段:

sa_handler:这个字段指定要执行操作的类型。它的值可以是指向信号处理程序的一个指针。

sa_flags:这是一个标志集,指定必须怎样处理信号

sa_mask:这是类型为sigset_t的变量,指定运行信号处理函数时屏蔽的信号。

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

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

私有挂起队列:他位于进程描述符的棚顶字段,存放特点进程的挂起信号。

传递信号:假定内核已经注意到一个信号的到来,并调用前面所介绍的函数为接收此信号的进程准备描述符。但万一这个进程在那一刻并不在cpu上运行,内核就延迟传递信号。内核在允许进程恢复用户态的执行之前,检查进程TIF_SIGPENDING标志的值。每当内核处理完一个中断或异常时,就检查是否存在挂起的信号。

捕获信号:如果信号有一个专门的处理程序,do_signal()就函数必须强迫该处理程序执行。这个通过调用handle_signal()进行的。如果所接收的信号SA_ONESHOT标志被置位,就必须重新设置它的缺省操作,以便同一个信号再次出现时不会触发信号处理程序的执行。

信号处理程序是用户态进程所定义的函数,并包含在用户态的代码中。handle_signal()函数运行在内核态,二信号处理程序运行在用户态,这就意味着在当前进程恢复“正常”前,他必须首先执行用户态的信号处理程序。此为当内核打算恢复进程的正常执行时,内核态堆栈不再包含中断程序的硬件上下文,因为每当从内核态向用户态转换时,内核态堆栈都被清空。

而另外一个复杂性是因为信号处理程序可以进行系统调用,在这种情况下,执行了系统调用的服务例程以后,控制权必须返回到信号处理程序而不是被中断程序的正常代码流。