• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

linux c sigsuspend 执行过程分析

docker 水墨上仙 2859次浏览

用于在接受到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止。
出处:” target=”_blank”>http://blog.csdn.net/muge0913/article/details/7334840

/*The&nbspsigsuspend()&nbspfunction&nbspreplaces&nbspthe&nbspcurrent&nbspsignal&nbspmask&nbspof&nbspthe&nbspcalling&nbspthread&nbspwith&nbspthe&nbspset&nbspof&nbspsignals&nbsppointed&nbsp&nbsp
&nbsp&nbsp&nbspto&nbspby&nbspsigmask&nbspand&nbspthen&nbspsuspends&nbspthe&nbspthread&nbspuntil&nbspdelivery&nbspof&nbspa&nbspsignal&nbspwhose&nbspaction&nbspis&nbspeither&nbspto&nbspexecute&nbspa&nbspsignal-catching&nbsp&nbsp
&nbsp&nbspfunction&nbspor&nbspto&nbspterminate&nbspthe&nbspprocess.&nbspThis&nbspwill&nbspnot&nbspcause&nbspany&nbspother&nbspsignals&nbspthat&nbspmay&nbsphave&nbspbeen&nbsppending&nbspon&nbspthe&nbspprocess&nbspto&nbsp&nbsp
&nbsp&nbspbecome&nbsppending&nbspon&nbspthe&nbspthread.&nbsp
If&nbspthe&nbspaction&nbspis&nbspto&nbspterminate&nbspthe&nbspprocess&nbspthen&nbspsigsuspend()&nbspwill&nbspnever&nbspreturn.&nbspIf&nbspthe&nbspaction&nbspis&nbspto&nbspexecute&nbspa&nbspsignal-catching&nbsp&nbsp
&nbsp&nbspfunction,&nbspthensigsuspend()&nbspwill&nbspreturn&nbspafter&nbspthe&nbspsignal-catching&nbspfunction&nbspreturns,&nbspwith&nbspthe&nbspsignal&nbspmask&nbsprestored&nbspto&nbspthe&nbspset&nbsp&nbsp
&nbsp&nbspthat&nbspexisted&nbspprior&nbspto&nbspthesigsuspend()&nbspcall.&nbsp
It&nbspis&nbspnot&nbsppossible&nbspto&nbspblock&nbspsignals&nbspthat&nbspcannot&nbspbe&nbspignored.&nbspThis&nbspis&nbspenforced&nbspby&nbspthe&nbspsystem&nbspwithout&nbspcausing&nbspan&nbsperror&nbspto&nbspbe&nbspindicated.*/&nbsp&nbsp

  也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接受到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。

Stevens在《Unix环境高级编程》一书中是如是回答的“If&nbspa&nbspsignal&nbspis&nbspcaught&nbspand&nbspif&nbspthe&nbspsignal&nbsphandler&nbspreturns,&nbspthen&nbspsigsuspend&nbspreturns&nbspand&nbspthe&nbspsignal&nbspmask&nbspof&nbspthe&nbspprocess&nbspis&nbspset&nbspto&nbspits&nbspvalue&nbspbefore&nbspthe&nbspcall&nbspto&nbspsigsuspend.”,由于sigsuspend是原子操作,所以这句给人的感觉就是先调用signal&nbsphandler先返回,然后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;  
}  
 

结果:
[cpp]&nbspview&nbspplaincopyprint?
$a.out&nbsp&nbsp
in&nbspcritical&nbspregion:&nbspSIGINT&nbsp&nbsp
^C&nbsp&nbsp
in&nbspsig_int:&nbspSIGINT&nbsp&nbsp
after&nbspreturn&nbspfrom&nbspsigsuspend:&nbspSIGINT&nbsp&nbsp

如果按照sig_handler先返回,那么SIGINT是不该被打印出来的,因为那时屏蔽字还没有恢复,所有信号都是不阻塞的。那么是Stevens说错了么?当然没有,只是Stevens没有说请在sigsuspend的原子操作中到底做了什么?
sigsuspend的整个原子操作过程为:
(1)&nbsp设置新的mask阻塞当前进程;
(2)&nbsp收到信号,恢复原先mask;
(3)&nbsp调用该进程设置的信号处理函数;
(4)&nbsp待信号处理函数返回后,sigsuspend返回。
大致就是上面这个过程,噢,原来signal&nbsphandler是原子操作的一部分,而且是在恢复屏蔽字后执行的,所以上面的例子是没有问题的,Stevens说的也没错。由于Linux和Unix的千丝万缕的联系,所以在两个平台上绝大部分的系统调用的语义是一致的。上面的sigsuspend的原子操作也是从《深入理解Linux内核》一书中揣度出来的。书中的描述如下:

/*The sigsuspend( ) system call puts the process in the TASK_INTERRUPTIBLE state, after having blocked the standard signals specified 
 by a bit mask array to which the mask parameter points. The process will wake up only when a nonignored, nonblocked signal is sent  
 to it. The corresponding sys_sigsuspend( ) service routine executes these statements: 
*/  
  
mask &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));  
spin_lock_irq(¤t->sigmask_lock);  
saveset = current->blocked;  
siginitset(¤t->blocked, mask);  
recalc_sigpending(current);  
spin_unlock_irq(¤t->sigmask_lock);  
regs->eax = -EINTR;  
while (1) {  
    current->state = TASK_INTERRUPTIBLE;  
    schedule(  );  
    if (do_signal(regs, &saveset))  
        return -EINTR;  
}   


喜欢 (0)
加载中……