=============================================================================== 产生被进程阻塞的信号时, 如果信号的动作是默认动作和捕获信号, 则下列情形发生 之前, 信号保持挂起: * 进程解开信号的阻塞 * 改变动作为忽略 ===============================================================================
=============================================================================== #include <signal.h> int sigemptyset (sigset_t *set); int sigfillset (sigset_t *set); int sigaddset (sigset_t *set, int signum); int sigdelset (sigset_t *set, int signum); int sigismember (const sigset_t *set, int signum); ------------------------------------------------------------------------------- 上述函数的一种实现: #define sigemptyset (ptr) ( *(ptr) = 0 ) #define sigfillset (ptr) ( *(ptr) = ~(sigset_t)0, 0 ) /* C 语言的逗号运算符: 返回右边的值作为表达式的返回值 */ #include <signal.h> #include <errno.h> #define SIGBAD (signo) ((signo) <=0 || (signo) >= NSIG) int sigaddset (sigset_t *set, int signo) { if (SIGBAD (signo)) {errno = EINVAL; return -1;} *set != 1 << (signo -1); return 0; } int sigdelset (sigset_t *set, int signo) { if (SIGBAD (signo)) {errno = EINVAL; return -1;} *set &= ~(1 << (signo -1)); return 0; } int sigismember (sigset_t *set, int signo) { if (SIGBAD (signo)) {errno = EINVAL; return -1;} return ((*set & (1<< (signo - 1))) != 0); } ===============================================================================
=============================================================================== #include <signal.h> int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact); int sigprocmask (int how, const sigset_t *set, sigset_t *oldset); int sigpending (sigset_t *set); int sigsuspend (const sigset_t *mask); ------------------------------------------------------------------------------- struct sigaction { void (*sa_handler) (int); void (*sa_sigaction) (int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); // 废弃的元素, 不应使用 } ------------------------------------------------------------------------------- sigaction: * sigaction 用于改变进程在接收到信号时的动作. * sigaction 可指定除 SIGKILL 和 SIGSTOP 之外的信号的动作 (act->sa_handler), 可取 SIG_DFL, SIG_IGN 和用户定义函数. * sigaction 可指定在处理 signum 信号时, 应该阻塞的信号集 (act->sa_mask). * sigaction 可指定信号处理过程中的行为 (act->sa_flags), 下述标志 "或" 的结果: o SA_NOCLDSTOP: 子进程停止时不接收 SIGCHLD. o SA_ONESHOT 或 SA_RESETHAND: 重置信号动作为默认值. o SA_RESTART: 如果该信号中断慢系统调用, 则重新启动系统调用. o SA_NOMASK 或 SA_NODEFER: 不要避免在信号处理函数中接收同一信号. o SA_SIGINFO: 信号处理函数接受三个参数. 这时, 必须设置 act->sa_sigaction 元素, 其中 siginfo_t 是内核传递到信号处理函数中的发生信号时进程的状态 信息. 详细信息, 可参阅 sigaction(2) 手册页. * oldact 非空时, 可返回先前的设置. * 利用 SA_SIGINFO 和 siginfo_t 实现有效的存储管理. ------------------------------------------------------------------------------- sigprocmask: * sigprocmask 用于改变进程的当前阻塞信号集. * how 可取 SIG_BLOCK, SIG_UNBLOCK 和 SIG_MASKSET. 前两个动作分别在当前阻塞 信号集中添加或删除由 set 指定的信号集, SIG_MASK 用于完全设置阻塞信号集. * oldset 非空时, 可返回先前的设置. ------------------------------------------------------------------------------- sigpending: * sigpending 用于检验挂起的信号. ------------------------------------------------------------------------------- sigsuspend: * sigsuspend 用于在接收到某个信号之前, 临时用 mask 替换进程的信号掩码, 并 暂停进程执行. * sigsuspend 返回后将恢复调用之前的信号掩码. * 该系统调用始终返回 -1, 并将 errno 设置为 EINTR. * 该系统调用实际是阻塞并暂停两个动作的原子操作. ===============================================================================
=============================================================================== #include <signal.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <signal.h> #include <unistd.h> static void sig_int (int); void err_sys (const char* info) { perror (info); exit (1); } void pr_mask (const char* str) { sigset_t sigset; int errno_save; errno_save = errno; /* this function may be called by signal handler */ if (sigprocmask (0, NULL, &sigset) < 0) err_sys ("sigprocmask error"); printf ("%s", str); if (sigismember (&sigset, SIGINT)) printf ("SIGINT "); if (sigismember (&sigset, SIGQUIT)) printf ("SIGQUIT "); if (sigismember (&sigset, SIGUSR1)) printf ("SIGUSR1 "); if (sigismember (&sigset, SIGALRM)) printf ("SIGALRM "); printf ("\n"); errno = errno_save; } int main (void) { sigset_t newmask, oldmask, zeromask; if (signal (SIGINT, sig_int) == SIG_ERR) err_sys ("signal (SIGINT) error"); sigemptyset (&zeromask); sigemptyset (&newmask); sigaddset (&newmask, SIGINT); /* block SIGINT and save current signal mask */ if (sigprocmask (SIG_BLOCK, &newmask, &oldmask) < 0) err_sys ("SIG_BLOCK error"); /* critical region of code */ pr_mask ("in critical region: "); /* allow all signals and pause */ if (sigsuspend (&zeromask) != -1) err_sys ("sigsuspend error"); pr_mask ("after return from sigsuspend: "); /* reset signal mask whick unblocks SIGINT */ if (sigprocmask (SIG_SETMASK, &oldmask, NULL) < 0) err_sys ("SIG_SETMASK error"); /* and continue processing ... */ exit (0); } static void sig_int (int signo) { pr_mask ("\nin sig_int: "); return; } ------------------------------------------------------------------------------- * 在 Linux 下, 必须包含头文件: #include <bsd/signal.h> 以便使用可靠的 signal 函数. 或者使用 sigaction 函数. ===============================================================================
=============================================================================== #include <setjmp.h> int sigsetjmp (sigjmp_buf env, int savesigs); void siglongjmp (sigjmp_buf env, int val); ------------------------------------------------------------------------------- * 如果 savesigs 非零, 则 siglongjmp 在添转之后将恢复保存的信号掩码. ===============================================================================