信号

Linux系统,信号提供了一种处理异步事件的方法。很多重要的程序都需要处理信号。本文略作梳理,更详细的知识可以参考APUE。

一、基本概念

  • 信号是软件中断,信号相对于进程控制流程来说是异步的
  • kill -l命令可以查看系统定义的信号列表,每一个信号都有一个编号(不为0)和名称
  • 信号在用户程序不注册处理函数时,有默认的处理动作,比如:终止进程、coredump

二、产生信号

  • 用户终端按键触发信号发送到前台进程,比如: Ctrl-C产生SIGINT中断信号,Ctrl-\产生SIGQUIT信号
  • 硬件异常产生信号,如:除0产生SIGFPE信号,非法内存访问产生SIGSEGV信号
  • 发送kill命令
  • 另一个进程调用kill函数发送信号
  • 内核检测到某种软件条件发生,比如:timer超时产生SIGALRM信号,向已关闭的管道写数据产生SIGPIPE信号

三、阻塞信号

  • 信号在内核中的表示
    1. pending: 信号是否处于未决状态,信号产生内核处理中断完成后,对应的信号pending被设置为1。如果block标记为0,则可以递送,否则需等待解除阻塞后递送
    2. block: 是(1)/否(0) 阻塞产生的信号递送。阻塞时,信号多次产生的话,常规信号仅计一次(标记pending为1),实时信号排队处理
  • 信号集操作函数
    1. sigemptyset、sigfillset:初始化信号集 (前者将信号集中的所有bit位置0,后者则置1)
    2. sigaddset, sigdelset: 操作信号集添加或删除某信号 (对应的信号bit位置1或0)
    3. sigismember: 检查信号是否在信号集是否有效
    4. sigprocmask: 操作信号屏蔽字(即设置信号的block标记,如果为1则阻塞递送)
    5. sigpending: 获取进程的未决信号集(信号的pending为1)
    6. sigsuspend: 挂起当前进程,直到捕捉到一个信号

四、信号捕捉

  • 捕捉后处理
    1. 忽略SIG_IGN
    2. 不忽略
      1. 执行系统默认SIG_DFL
      2. 用户程序注册handler处理
  • 注册信号处理函数的方式
    • signal: 使用sigaction函数替代
    • sigaction
      • 信号处理函数指针有两种,只能二选一 (sa_flags是否被标记SA_SIGINFO区分)
  • 如果用户程序注册信号处理函数,则信号递送后,表示捕捉信号成功,过程举例
    1. 用户程序注册了SIGINT信号的处理函数sighandler
    2. 程序执行时任意时刻,收到SIGINT信号发生中断切换到内核态
    3. 中断处理完毕,内核在返回用户态之前,发现SIGINT信号处于未决状态且未被阻塞递送,则返回用户态后执行信号处理函数sighandler
    4. 信号处理函数sighandler执行完毕后,自动执行特殊的系统调用sigreturn再次进入内核态
    5. 内核态检查没有新的信号可以递送,则返回用户态执行正常的业务流程