信号之函数sigqueue、作业控制信号以及信号名和编号

本文来自个人博客:https://dunkwan.cn

文章目录

    • 函数`sigqueue`
    • 作业控制信号
    • 信号名和编号

函数sigqueue

大部分UNIX系统不对信号排队,在POSIX.1的实时扩展中,有些系统开始增加对信号排队的支持。

使用排队信号必须做以下几个操作。

  1. 使用sigaction函数安装信号处理程序时指定SA_SIGINFO标志。如果没有给出这个标志,信号会延迟,但信号是否进入队列要取决于具体实现。
  2. sigaction结构的sa_sigaction成员中(而不是通常的sa_handler字段)提供信号处理程序。实现可能允许用户使用sa_handler字段,但不能获取sigqueue函数发送出来的额外信息。
  3. 使用sigqueue函数发送信号。
#include 
int sigqueue(pid_t pid, int signo, const union sigval value);
返回值:若成功,返回0;若出错,返回-1

sigqueue函数只能把信号发送给单个进程,可以使用value参数向信号处理程序传递整数和指针值,除此之外,sigqueue函数和kill函数类似。

信号不能无限排队,到达相应的限制以后,sigqueue就会失败,将errno设为EAGAIN

随着实时信号的增强,引入用于应用程序的独立信号集。这些信号的编号在SIGRTMIN~SIGRTMAX之间,包括这两个限制值。注意,这些信号的默认行为是终止进程。

下图是排队信号在不同实现上行为的差异。
信号之函数sigqueue、作业控制信号以及信号名和编号_第1张图片

作业控制信号

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);
}

结果如下:
信号之函数sigqueue、作业控制信号以及信号名和编号_第2张图片

信号名和编号

如何在信号名和编号之间进行映射。某些系统提供如下数组

extern char *sys_siglist[];

数组下标是信号编号,数组中的元素是指向信号名符串的指针。

FreeBSD 8.0、Linux 3.2.0和 Mac OS X 10.6.8 都提供这种信号名数组。Solaris 10也提供信号名数组,但该数组名是_sys_siglist

psignal函数可移植地打印与信号编号对应的字符串。

#include 
void psignal(int signo, const char *msg);

字符串msg输出到标准错误文件,后面跟随一个冒号和一个空格,再后面对该信号的说明,最后是一个换行符。如果msgNULL,只有信号说明部分输出到标准错误文件,类似于perror函数。

psiginfo函数用于打印信号信息。

#include 
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 
char *strsignal(int signo);
返回值:指向描述该信号的字符串的指针。

测试示例:

#include 
#include 
#include 
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;
}

结果如下:

你可能感兴趣的:(Unix/Linux,C/C++)