Linux操作系统下信号处理函数

您所在的位置:网站首页 linux信号处理的三种方式包括哪些 Linux操作系统下信号处理函数

Linux操作系统下信号处理函数

2024-07-15 22:34| 来源: 网络整理| 查看: 265

Linux系统下的信号

一、信号概念

1. 什么是信号 信号是软件中断,信号提供了一种异步处理事件的方法,它允许进程和内核中断其他进程。一个信号就是一条消息,它通知进程系统发生了一个某种类型的事件,在Linux系统中支持31中不同类型的信号 在我这篇文章中给大家列出了Linux系统支持的31个信号(https://blog.csdn.net/qq_34934140/article/details/116550027)。

每种信号都对应不同的系统类型,底层硬件异常是由内核异常处理程序处理的,正常情况下对用户是不可见的,信号提供了一种机制,通知用户进程发生了这些异常。每个信号都有自己的名字,他们都是以SIG开头,这些信号都包含在中。

产生信号的事件相对于进程来说是不可预见的,所以进程不可以测试一个变量来判断信号的产生,而必须告诉内核当信号发生时进程该如何处理。在信号出现时有以下三种处理方式 1)忽略信号,大多数信号采用这种处理方式,但是有两种信号不可用忽略,SIGKILL 和 SIGSTOP,因为他们向内核和超级用户提供了可靠的进程终止或停止的方法。 2)捕捉信号,通知内核在信号发生时调用一个用户函数,在用户函数中执行用户希望对该事件的处理方式。同样SIGKILL 和 SIGSTOP不可以被捕捉。 3)执行默认动作,系统会给所有信号一个默认动作,在(https://blog.csdn.net/qq_34934140/article/details/116550027)里面我已经详细列出。

2.信号术语 1)发送信号 内核通过更新目的进程上下文中的某个状态,发送一个信号给目的进程。发送信号的原因 a. 内核检测都一个系统事件,如硬件异常或子程序终止 b. 一个进程调用kill函数,显示地要求内核发送一个进程给目的进程,或者进程自己给自己发送信号。 2)接收信号 当目的进程被内核强迫以某种方式对信号的发送做出反应时,它就接收了信号。进程可以忽略这个信号也可以捕捉它做一个信号处理函数。 3)待处理信号 一个发出而没有被接收的信号,任一时刻,一种类型最多只会有一个待处理信号,如果一个进程此时有一个类型为k的处理信号,那么接下来发送到此进程的所有k类型信号都不会排队等待 ,他们都会被丢弃,进程可以选择阻塞接收某种信号,当一个信号被阻塞时,它仍然可以被发送,但是不会被接收,所有产生了待处理信号,直到进程取消对该进程的阻塞。一个待处理信号最多被 接收一次,在内核中有一个pending位向量维护着待处理信号集合,在blocked位向量中维护着被阻塞的信号集合,只要传送一个k类型信号,内核就会设置pending的第k位,接收一个k信号就会清楚 pending的k位。 4)阻塞信号 Linux提供阻塞信号的隐式和显式机制 隐式阻塞机制:内核默认阻塞任何当前处理程序正在处理信号类型的待处理信号 显式阻塞机制:应用程序可以使用sigprocmask函数和它的辅助函数,明确地阻塞和解除阻塞选定的信号 5)不可靠的信号 不可靠指的是信号可能会丢失,一个信号发生了,但你是进程却不知道。 6)可靠信号术语和语义 未决:信号产生和递送之间的时间间隔内,称信号是未决的,调用sigpending函数可以查看哪些信号被设置为阻塞并且是未决的。 信号屏蔽字:每个信号都有,它规定了当前阻塞递送到该进程的信号集,每种信号对应屏蔽字中的一位,使用sigprocmask函数来查看、设置、修改。 7)作业控制信号 SIGCHLD 子进程已停止或终止 SIGCONT 如果进程停止则继续运行 SIGSTOP 停止信号 SIGTSTP 交互式停止信号 SIGTTIN 后台进程组成员读控制终端 SIGTTOU 后台进程组成员写控制终端 除了SIGCHLD之外,大多数应用程序不处理这些信号,交互式shell通常会处理这些信号。 8)信号集 一个可以表示多个信号的数据类型

3.编写信号处理函数基本规则 处理程序和主程序并发执行,他们共享全局变量,因此可能与主程序和其他处理程序相互干扰,所以需要编写安全、正确、可移植的信号处理程序。 1)安全的信号处理 a.处理程序尽可能简单, b.在处理程序中只调用异步信号安全的函数 c.保存和恢复,在处理程序时把errno保存在一个局部变量中,返回时恢复。 d.阻塞所有信号,保护对共享全局数据结构的访问。 e.用volatile声明全局变量, f.用sig_atomic_t声明标志,保证读写不可中断

二、信号调用函数 1. signal函数 #include typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); 功能:设置某一信号对应动作 参数:signum:信号名 handler:信号处理函数,当信号发生时调用此函数。 返回值:成功返回处理函数的指针,失败返回SIG_ERR。 2. 发送信号函数(kill函数和raise函数) #include #include 2.1 int kill(pid_t pid, int sig); 功能:将信号发送给进程或者进程组 参数:pid > 0:发送给进程的进程ID pid = 0: 将信号发送给发送进程所属进程组的所有进程 pid < 0: 发送给pid绝对值的进程 pid = -1:发送给可发送的所有进程 sig:信号名 返回值:成功 0, 失败 -1. 2.2 int raise(int sig); 功能:允许进程 向自己发送信号 参数:sig:信号名 返回值:成功 0, 失败 -1. 3. 定时函数(alarm函数和pause函数) #include 3.1 unsigned int alarm(unsigned int seconds); 功能:设置一个定时器,当超时之后产生SIGALRM信号,如果忽略此信号,默认动作是终止此进程 参数:seconds:时间,单位 秒 返回值:0或者一起设置闹钟时间剩余的秒数 注释:每个进程只能设置一个闹钟,如果调用alarm函数时,进程已经调用过了此函数则返回剩余时间数,时间被新值替换。 3.2 int pause(void); 功能:进程挂起直到捕捉到一个信号 参数:无 返回值:-1, errno 设置为 EINTR. 4. 信号集函数 #include 4.1 int sigemptyset(sigset_t *set); 功能:初始化set指向的信号集,清除其中所有信号。所有应用程序在使用信号集前必须调用sigfillset或者sigemptyset 参数:set;信号集 返回值:成功 0, 失败 -1. 4.2 int sigfillset(sigset_t *set); 功能:初始化set指向的信号集,使其包括所有信号。所有应用程序在使用信号集前必须调用sigfillset或者sigemptyset 参数:set;信号集 返回值:成功 0, 失败 -1. 4.3 int sigaddset(sigset_t *set, int signum); 功能:添加一个信号 参数:set;信号集 signum:信号 返回值:成功 0, 失败 -1. 4.4 int sigdelset(sigset_t *set, int signum); 功能:删除一个信号 参数:set;信号集 signum:信号 返回值:成功 0, 失败 -1. 4.5 int sigismember(const sigset_t *set, int signum); 功能:测试一个指定位,因为信号没有编号为0,所有从信号编号中减去1得到要处理的位编号。 参数:set;信号集 signum:信号 返回值:成功 0, 失败 -1. 5.检测和修改信号屏蔽字 #include int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 功能:可以检测和修改进程的信号屏蔽字 参数:how: SIG_BLOCK:该进程新的信号屏蔽字是set指向的信号集和当前信号屏蔽字的并集,阻塞信号 SIG_UNBLOCK:该进程新的信号屏蔽字是set指向的信号集和当前信号屏蔽字的补集的交集,解除阻塞 SIG_SETMASK:该进程新的信号屏蔽字是set指向的值 set:非空指针,则how修改当前信号屏蔽字 空指针:则how无意义 6.返回信号集函数:sigpending #include int sigpending(sigset_t *set); 功能:返回一信号集 参数:set:信号集 返回值:成功 0,失败 -1. 7.检测或修改以及指定信号相关联的处理动作 #include int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 功能:检测或修改以及指定信号相关联的处理动作 参数:signum:要修改或检测的信号 act:非空指针:则要修改动作 为空: 则由oldact指针返回信号上一个动作。 oldact:指针 返回值:成功 0,失败 -1. struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }; 当更改信号动作时,sa_handler是信号处理函数,sa_sigaction是替代的信号处理程序,sa_mask是一个信号集,调用信号处理函数之前新将信号集加入到信号屏蔽字中, 这样当正在处理信号时候,再来这种信号就会被阻塞,sa_flags指对信号进程处理的各个选项,有以下选项。 SA_NOCLDSTOP:若signo是SIGCHLD,当子进程终止产生此信号。 SA_NOCLDWAIT:若signo是SIGCHLD,当子进程终止不创建僵尸进程,若调用wait则阻塞到所有子进程都终止 SA_NODEFER:当捕捉到信号时,在执行其信号处理函数时,系统不自动阻塞此信号 SA_ONSTACK:此信号递送给替换栈上的进程。 SA_RESETHAND:此信号捕捉函数入口处,将此信号处理方式重置为SIG_DFL,清除SA_SIGINFO标准 SA_RESTART:此信号中断的系统调用自动重启 SA_SIGINFO:提供了一个指向siginfo结构的指针和指向进程上下文的标识符指针。 8.非局部转移函数 sigsetjmp函数 和 siglongjmp函数 同setjmp函数longjmp函数功能一样,在 信号处理程序中调用siglongjmp跳回到主程序。不同之处是多了一个参数,如果savemask非0,则sigsetjmp在env中保存进程的当前信号屏蔽字 。调用siglongjmp时,如果带非0 savemask的sigsetjmp调用已经保存env,则siglongjmp从其中恢复保存的信号屏蔽字。 #include int sigsetjmp(sigjmp_buf env,int savemask); 功能:可以保存当前执行线索状态 参数: env:存放调用siglongjmp时可以恢复栈状态的所有信息,通常为全局变量 savemask:非0:env中保存当前进程信号屏蔽字 返回值:直接调用返回 0,若从siglongjmp调用返回0. int siglongjmp(sigjmp_buf env, int val); 功能:跳转函数 参数:env:sigsetjmp调用的env val:非0值 9.恢复信号屏蔽字的值 #include int sigsuspend(const sigset_t *mask); 功能:如果捕捉到一个信号而且信号处理函数返回,则sigsuspend返回,并且该信号屏蔽字设置为调用sigsuspend之前的值 参数:由sigmask指向的值 返回值:此函数没有成功返回值,如果返回到调用者则总是-1. 10.程序异常终止函数 #include void abort(void); 功能:此函数将SIGABRT信号发送给调用进程 11.信号名和信号编号 #include 11. void psignal(int sig, const char *s); void psiginfo(const siginfo_t *pinfo, const char *s); 功能:打印与信号编号对应的字符串 参数:sig:信号名 s: 对应字符串 11.2 #include char *strsignal(int sig); 功能:给定信号编号,返回信号字符串


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3