zoukankan      html  css  js  c++  java
  • 信号

    Linux中有两种类型信号

    常规信号(regular signal):编码范围为1~31。同种类型的常规信号假设被发送多次,那么,仅仅有当中的一个发送到接收进城

    实时信号(real-time signal):编码范围32~64。它与常规信号不通。由于他们必须排队以便发送的多个信号能被接收到。虽然linux内核不使用实时信号。它还是通过几个特定的系统调用全然实现了POSIX标准。

    与信号相关的最重要的系统调用

    kill()         向线程组发送一个信号

    tkill()        向进程发送一个信号

    tgkill()       向一个特定线程组中的进程发送信号

    sigaction()    改变与信号相关的操作

    signal()       类似于sigaction()

    sigpending()   检查是否有挂起信号

    sigprocmask()  改动堵塞信号的集合

    sigsuspend()   等待一个信号

    信号的一个重要特点是它们能够随时随地发送给状态常常不可预知的进程。发送给非执行进程的信号必须由内核保存。直到进程恢复执行。

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

    信号产生

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

    信号传递

    内核强迫目标进程通过下面方式对信号做出反应:或改变目标进程的运行状态,或開始运行一个特定的信号处理程序,或者两者都是。

    已经产生但还没有传递的信号称为挂起信号(pending signal)。不论什么时候,一个进程仅存在给定类型的一个挂起信号。同一进程同种类型的其它信号不被排队,仅仅被简单的丢弃。可是,实时信号时不同的:同种类型的挂起信号能够多个。

    虽然信号表项比較直观,但内核实现相当复杂:

    1、记住每一个进程堵塞哪些信号

    2、当从内核态切换到用户态时,对不论什么一个进程都要检查是否有一个信号到达。这差点儿在每一个定时器中断都发送

    3、确定能否够忽略信号。这发生在下列全部条件都满足时:

       a、目标进程没有被还有一个进程跟踪

       b、信号没有被目标进程堵塞

       c、信号被目标进程屏蔽

    4、处理这种信号,即信号可能在进程执行期间的任一时刻请求把进程切换到一个信号处理函数。并在这个函数返回后恢复原来执行的上下文。

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

    1、显示地忽略信号

    2、运行与信号相关的缺省操作

    3、通过调用对应的信号处理函数捕获信号

    注意。对一个信号的堵塞和忽略是不同的:仅仅要信号被堵塞,它就不被传递;仅仅有信号解除堵塞后才传递它。而一个被忽略的信号总是被传递,仅仅是没有进一步的操作。

    SIGKILL和SIGSTOP信号不能够被显式地忽略、捕获或堵塞,因此。通常必须运行它们的缺省操作。

    POSIX标准对多线程应用的信号处理有一些严格的要求:

    1、信号处理程序必须在多线程应用的全部线程之间共享。只是,每一个线程必须有自己的挂起信号掩码和堵塞信号掩码

    2、每一个发送给多线程应用的信号仅传送给一个线程,这个线程是由内核在从不堵塞该信号的线程中任意选择出来的

    3、假设向多线程应用发送了一个致命的信号,那么内核将杀死该应用的全部线程,而不不过杀死接收信号的那个线程。

    task_struct线程描写叙述符中与信号相关的字段

    struct signal_struct *signal;
    struct sighand_struct *sighand;
    struct sigpending pending;


    产生信号

    非常多内核函数都会产生信号:它们完毕信号处理第一步的工作。即依据须要更新一个或多个进程的描写叙述符。

    它们不直接运行第二步的信号传递操作。而是可能可能依据信号的类型和目标进程的状态唤醒一下进程。并促使这些进程接收信号。

    当发送给进程一个信号时,这个信号可能来自内核,也可能来自还有一个进程

    传递信号

    假定内核已经注意到一个信号的到来,并调用前面介绍的函数为接收此信号的进程准备描写叙述符。但万一这个进程在那一刻并不在CPU执行,内核就延迟传递函数的任务。那么怎样确保进程的挂起信号得到处理呢?

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

    捕获信号


    上图说明了有关捕获一个信号的函数的运行流。

    一个非堵塞的信号发送给一个进程。其中断或异常发生时,进程切换到内核态。正要返回到用户态前,内核运行do_signal()函数。这个函数又依次处理信号和建立用户态堆栈。

    当进程又切换到用户态时由于信号处理程序的起始地址被强制放进程序计数器中。因此開始运行信号处理程序。当处理程序终止时,setup_frame()函数放在用户态堆栈中的返回代码被运行。这个代码调用sigreturn()系统调用,对应的服务例程把正常程序的用户态堆栈硬件上下文复制到内核态堆栈。并把用户态堆栈恢复到原来的状态。当这个系统调用结束时,普通进程就因此能恢复自己的运行。



  • 相关阅读:
    Arduino 各种模块篇 DHT11 温度湿度 数字模块 单总线
    Arduino 各种模块篇 火焰传感器
    exception
    google c++ code style
    昙花一现
    晏才宏
    win 2003 玩3D游戏设置
    生成多文件的Assembly 的两种方法
    怎样使自己写的程序集出现在Visual Studio Add Reference 的 .NET Tab页中
    安装将仅在管理模式下运行,安装终止
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7371723.html
Copyright © 2011-2022 走看看