APUE学习:信号

信号机制是一个经典的进程异步机制。
Linux信号机制的基本流程:

  1. 用户程序为一个信号注册一个信号处理函数,例如SIGQUIT注册了一个sig_hander函数
  2. 因为某些原因,进程从用户态切换到内核态
  3. 从内核态要返回到用户态时,内核会去检测有没有给该进程传递一个SIGQUIT信号,如果有会在用户态下面去执行对应的信号处理函数sig_hander
  4. sig_hander执行完毕之后会自动执行特殊的系统调用sigreturn再次进入内核态。
  5. 如果没有新的信号传递过来,这次在返回用户态就恢复到上次中断的地方之后继续执行。

signal函数

#include <signal.h>
void (*signal(int signo, void(*func)(int)))(int);

为信号signo注册一个信号处理函数func,返回值是signo信号的上一个信号处理函数。

中断的系统调用

即系统调用是可以中断的,比如慢速系统调用。在中断之后,系统调用一般会返回一个错误。
对于被中断的系统调用,一般有3中处理方式:

  • 人为重启被中断的系统调用
  • 安装信号时设置SA_RESTART属性
  • 忽略信号
    信号中断与慢系统调用

可靠信号术语与语义

未决信号:在信号产生和递送之间的时间间隔内,称信号是未决的。
信号屏蔽字:每个进程都有一个信号屏蔽字,它规定了当前要阻塞递送到该进程的信号集。
信号集:可以表示多个信号。sigset_t

#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set,
                sigset_t *restrict oset);

how:

  • SIG_BLOCK:表示新的信号屏蔽字是当前信号屏蔽字与set的并集
  • SIG_UNBLOCK:表示新的信号屏蔽字是当前信号屏蔽字和set所指向信号集补集的交集。set包含了我们希望解除阻塞的信号
  • SIG_SETMASK:将该进程的信号屏蔽字用set替代
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int segdelset(sigset_t *set, int signo);

int sigismember(const sigset_t *set, int signo);

sigpending函数

#include <signal.h>
int sigpending(sigset_t *set); //成功返回0,否则返回-1

sigpending 返回信号集,其中各个信号对于调用进程来说是阻塞的而不能传递的,因此也是未决的。
理解阻塞的含义是在进程的未决信号集中,等到解除对该信号的屏蔽。

sigaction

ing sigaction(int signo, const struct sigaction *restrict act,
              struct sigaction *restrict oact);

struct sigaction
{
    union
    {
        void (*sa_handler)(int);
        void (*sa_sigaction)(int, siginfo_t *, void *);
    }
    sigset_t sa_mask;
    int sa_flags;
};

sigsetjmp和siglongjmp函数

longjmp的问题:当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被自动地加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断该信号处理程序。如果此时用longjmp跳出信号处理程序后,该信号仍然在进程的信号屏蔽字中。
为了解决这个问题用到siglongjmp与sigsetjum函数

ing sigsetjmp(sigjmp_buf env, int savemask);

void siglongjmp(sigjmp_buf env, int val);

sigsuspend函数

#include <signal.h>
int sigsuspend(const sigset_t *sigmask); //返回-1,并将errno设置为EINTR

sigsuspend将进程的屏蔽字设置为有sigmask指向的信号集。在捕捉到一个信号或者发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。

你可能感兴趣的:(linux)