函数原型:
#include <signal.h> int sigsuspend(const sigset_t *mask);作用:
用于在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止。 也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接收到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。 sigsuspend返回后将恢复调用之前的的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR. Since sigsuspend() suspends process execution indefinitely, there is no successful completion return value. If a return occurs, -1 is returned and errno is set to indicate the error. The sigsuspend() function will fail if: [EINTR] A signal is caught by the calling process and control is returned from the signal-catching function.
也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接受到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。
结果:
如果按照sig_handler先返回,那么SIGINT是不该被打印出来的,因为那时屏蔽字还没有恢复,所有信号都是不阻塞的。那么是Stevens说错了么?当然没有,只是Stevens没有说请在sigsuspend的原子操作中到底做了什么?
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
Stevens在《Unix环境高级编程》一书中是如是回答的“If a signal is caught and if the signal handler returns, then sigsuspend returns and the signal mask of the process is set to its value before the call to sigsuspend.”,由于sigsuspend是原子操作,所以这句给人的感觉就是先调用signal handler先返回,然后sigsuspend再返回。
- 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 which 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;
- }
- $a.out
- in critical region: SIGINT
- ^C
- in sig_int: SIGINT
- after return from sigsuspend: SIGINT
如果按照sig_handler先返回,那么SIGINT是不该被打印出来的,因为那时屏蔽字还没有恢复,所有信号都是不阻塞的。那么是Stevens说错了么?当然没有,只是Stevens没有说请在sigsuspend的原子操作中到底做了什么?
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
- #include <stdio.h>
- #include <signal.h>
- void checkset();
- void func();
- void main()
- {
- sigset_tblockset,oldblockset,zeroset,pendmask;
- printf("pid:%ld\n",(long)getpid());
- signal(SIGINT,func);
- sigemptyset(&blockset);
- sigemptyset(&zeroset);
- sigaddset(&blockset,SIGINT);
- sigprocmask(SIG_SETMASK,&blockset,&oldblockset);
- checkset();
- sigpending(&pendmask);
- if(sigismember(&pendmask,SIGINT))
- printf("SIGINTpending\n");
- if(sigsuspend(&zeroset)!= -1)
- {
- printf("sigsuspenderror\n");
- exit(0);
- }
- printf("afterreturn\n");
- sigprocmask(SIG_SETMASK,&oldblockset,NULL);
- printf("SIGINTunblocked\n");
- }
- void checkset()
- { sigset_tset;
- printf("checksetstart:\n");
- if(sigprocmask(0,NULL,&set)<0)
- {
- printf("checksetsigprocmask error!!\n");
- exit(0);
- }
- if(sigismember(&set,SIGINT))
- printf("sigint\n");
- if(sigismember(&set,SIGTSTP))
- printf("sigtstp\n");
- if(sigismember(&set,SIGTERM))
- printf("sigterm\n");
- printf("checksetend\n");
- }
- void func()
- {
- printf("hellofunc\n");
- }
父子进程同步到方法如下:
- <span style="font-size:18px;"><strong>#include "apue.h"
- static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */
- static sigset_t newmask, oldmask, zeromask;
- static void
- sig_usr(int signo) /* one signal handler for SIGUSR1 and SIGUSR2 */
- {
- sigflag = 1;
- }
- void
- TELL_WAIT(void)
- {
- if (signal(SIGUSR1, sig_usr) == SIG_ERR)
- err_sys("signal(SIGUSR1) error");
- if (signal(SIGUSR2, sig_usr) == SIG_ERR)
- err_sys("signal(SIGUSR2) error");
- sigemptyset(&zeromask);
- sigemptyset(&newmask);
- sigaddset(&newmask, SIGUSR1);
- sigaddset(&newmask, SIGUSR2);
- /*
- * Block SIGUSR1 and SIGUSR2, and save current signal mask.
- */
- if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
- err_sys("SIG_BLOCK error");
- }
- void
- TELL_PARENT(pid_t pid)
- {
- kill(pid, SIGUSR2); /* tell parent we're done */
- }
- void
- WAIT_PARENT(void)
- {
- while (sigflag == 0)
- sigsuspend(&zeromask); /* and wait for parent */
- sigflag = 0;
- /*
- * Reset signal mask to original value.
- */
- if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
- err_sys("SIG_SETMASK error");
- }
- void
- TELL_CHILD(pid_t pid)
- {
- kill(pid, SIGUSR1); /* tell child we're done */
- }
- void
- WAIT_CHILD(void)
- {
- while (sigflag == 0)
- sigsuspend(&zeromask); /* and wait for child */
- sigflag = 0;
- /*
- * Reset signal mask to original value.
- */
- if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
- err_sys("SIG_SETMASK error");
- }
- </strong></span>