sigsuspend 函数
更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞,使用这种技术可以保护不希望由信号中断的代码临界区。如果希望对一个信号解除阻塞,然后pause 等待以前被阻塞的信号发生,就是把“解除信号屏蔽”和“挂起等待信号”这两步能合并成一个原子操作。sigsuspend 函数能够实现该功能,即包含了pause的挂起等待功能,同时临时解除对某个信号的屏蔽。以下是该函数的原型:
- #include <signal.h>
- int sigsuspend(const sigset_t *sigmask);//返回值:-1,并将errno设置为EINTR;
跟 pause 一样, sigsuspend 没有成功返回值,只有执行了一个信号处理函数之后 sigsuspend 才返回,返回值为-1,并将 errno 设置为 EINTR 。调用 sigsuspend 时,进程的信号屏蔽字由 sigmask 参数指定,可以通过指定 sigmask 来临时解除对某个信号的屏蔽,然后挂起等待,当 sigsuspend 返回时,进程的信号屏蔽字恢复为原来的值。
测试程序:
- #include <signal.h>
- /*
- int sigsuspend(const sigset_t *sigmask);//返回值:-1,并将errno设置为EINTR;
- */
- #include "apue.h"
- #include "pr_mask.h"
- static void sig_func(int signo);
- int main(void)
- {
- sigset_t newmask, oldmask, waitmask;
- pr_mask("Program start: ");
- if(signal(SIGINT,sig_func) == SIG_ERR)
- err_sys("signal error");
- sigemptyset(&newmask);//初始化信号集
- sigaddset(&newmask,SIGINT);//添加SIGINT信号
- sigemptyset(&waitmask);
- sigaddset(&waitmask,SIGUSR1);
- //屏蔽信号
- /*
- * Block SIGINT and save current signal mask
- */
- if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)
- err_sys("SIG_BLOCK error");
- pr_mask("in critical region: ");
- //临时修改进程信号屏蔽字,在捕捉信号之前,将进程挂起等待
- /*
- * pause, allowing all of signals except SIGUSR1
- */
- if(sigsuspend(&waitmask) != -1)
- err_sys("sigsuspend error");
- pr_mask("after return from sigsuspend: ");
- /*
- * reset signal mask which unblocks SIGINT
- */
- if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)
- err_sys("SIG_SETMASK error");
- pr_mask("program exit: ");
- exit(0);
- }
- static void sig_func(int signo)
- {
- pr_mask("\nin sig_func: ");
- }
- $ ./sigsuspend
- Program start:
- in critical region: SIGINT
- ^C
- in sig_func: SIGINT SIGUSR1
- after return from sigsuspend: SIGINT
- program exit:
- 首先设置信号 SIGINT为信号屏蔽字进行阻塞;
- 当程序执行了 sigsuspend 后,临时使 SIGUSR1 成为信号屏蔽字进行阻塞,对 SIGINT 解除阻塞,并且挂起进程,等待信号输入;
- 我们在终端中输入ctrl-C ,即输入一个中断信号,进程捕捉到中断信号,调用捕捉函数sig_func 进行处理,处理完中断信号后sigsuspend 函数返回-1。此时,进程的信号屏蔽字恢复为原来的值SIGINT;