本文来自个人博客:https://dunkwan.cn
函数sigqueue
大部分UNIX系统不对信号排队,在POSIX.1的实时扩展中,有些系统开始增加对信号排队的支持。
使用排队信号必须做以下几个操作。
- 使用
sigaction
函数安装信号处理程序时指定SA_SIGINFO
标志。如果没有给出这个标志,信号会延迟,但信号是否进入队列要取决于具体实现。 - 在
sigaction
结构的sa_sigaction
成员中(而不是通常的sa_handler
字段)提供信号处理程序。实现可能允许用户使用sa_handler
字段,但不能获取sigqueue
函数发送出来的额外信息。 - 使用
sigqueue
函数发送信号。
#include <signal.h>
int sigqueue(pid_t pid, int signo, const union sigval value);
返回值:若成功,返回0;若出错,返回-1。
sigqueue
函数只能把信号发送给单个进程,可以使用value
参数向信号处理程序传递整数和指针值,除此之外,sigqueue
函数和kill
函数类似。信号不能无限排队,到达相应的限制以后,
sigqueue
就会失败,将errno
设为EAGAIN
。随着实时信号的增强,引入用于应用程序的独立信号集。这些信号的编号在
SIGRTMIN
~SIGRTMAX
之间,包括这两个限制值。注意,这些信号的默认行为是终止进程。
下图是排队信号在不同实现上行为的差异。
作业控制信号
POSIX.1 认为与作业控制相关的6个信号如下:
SIGCHLD
子进程已停止或终止
SIGCONT
如果进程已停止,则使其继续运行
SIGSTOP
停止信号
SIGTSTP
交互式停止信号
SIGTTIN
后台进程组成员读控制终端
SIGTTOUT
后台进程组成员写控制终端。
测试示例:
该程序是将其标准输入复制至标准输出。
#include "apue.h"
#define BUFFSIZE 1024
static void
sig_tstp(int signo) /* signal handler for SIGTSTP */
{
sigset_t mask;
/* ... move cursor to lower left corner, reset tty mode ... */
/*
* Unblock SIGTSTP, since it's blocked while we're handling it.
*/
sigemptyset(&mask);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
signal(SIGTSTP, SIG_DFL); /* reset disposition to default */
kill(getpid(), SIGTSTP); /* and send the signal to ourself */
/* we won't return from the kill until we're continued */
signal(SIGTSTP, sig_tstp); /* reestablish signal handler */
/* ... reset tty mode, redraw screen ... */
}
int
main(void)
{
int n;
char buf[BUFFSIZE];
/*
* Only catch SIGTSTP if we're running with a job-control shell.
*/
if (signal(SIGTSTP, SIG_IGN) == SIG_DFL)
signal(SIGTSTP, sig_tstp);
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
exit(0);
}
结果如下:
信号名和编号
如何在信号名和编号之间进行映射。某些系统提供如下数组
extern char *sys_siglist[];
数组下标是信号编号,数组中的元素是指向信号名符串的指针。
FreeBSD 8.0、Linux 3.2.0和 Mac OS X 10.6.8 都提供这种信号名数组。Solaris 10也提供信号名数组,但该数组名是
_sys_siglist
。
psignal
函数可移植地打印与信号编号对应的字符串。
#include <signal.h>
void psignal(int signo, const char *msg);
字符串
msg
输出到标准错误文件,后面跟随一个冒号和一个空格,再后面对该信号的说明,最后是一个换行符。如果msg
为NULL
,只有信号说明部分输出到标准错误文件,类似于perror
函数。
psiginfo
函数用于打印信号信息。
#include <signal.h>
void psignal(const siginfo_t *info, const char *msg);
siginfo_t
结构体如下:
siginfo_t { /* implementation on Linux system*/
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count;
POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
void *si_lower; /* Lower bound when address violation
occurred (since Linux 3.19) */
void *si_upper; /* Upper bound when address violation
occurred (since Linux 3.19) */
int si_pkey; /* Protection key on PTE that caused
fault (since Linux 4.6) */
void *si_call_addr; /* Address of system call instruction
(since Linux 3.5) */
int si_syscall; /* Number of attempted system call
(since Linux 3.5) */
unsigned int si_arch; /* Architecture of attempted system call
(since Linux 3.5) */
};
strsignal
函数用于打印信号的字符描述部分,类似于strerror
函数。
#include <string.h>
char *strsignal(int signo);
返回值:指向描述该信号的字符串的指针。
测试示例:
#include <stdio.h>
#include <signal.h>
#include <string.h>
void test_psignal()
{
psignal(SIGINT, "SIGINT error");
}
void test_strsignal()
{
char *buf = strsignal(SIGALRM);
printf("buf = %s\n", buf);
}
void test_psiginfo()
{
}
int main()
{
test_psignal();
test_strsignal();
return 0;
}
结果如下: