程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> linux c之sigsuspend 進程阻塞

linux c之sigsuspend 進程阻塞

編輯:關於C語言

函數原型:

#include <signal.h>

int sigsuspend(const sigset_t *mask);

作用:

用於在接收到某個信號之前,臨時用mask替換進程的信號掩碼,並暫停進程執行,直到收到信號為止。

The sigsuspend() function replaces the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspends the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. This will not cause any other signals that may have been pending on the process to become pending on the thread.

If the action is to terminate the process then sigsuspend() will never return. If the action is to execute a signal-catching function, thensigsuspend() will return after the signal- catching function returns, with the signal mask restored to the set that existed prior to thesigsuspend() call.

It is not possible to block signals that cannot be ignored. This is enforced by the system without causing an error to be indicated.

也就是說,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後,進程就掛在那裡,等待著開放的信號的喚醒。 系統在接受到信號後,馬上就把現在的信號集還原為原來的,然後調用處理函數。

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返回。

大致就是上面這個過程,噢,原來 signal handler是原子操作的一部分,而且是在恢復屏蔽字後執行的,所以上面的例子是沒有問題的, 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;  
}

int sigsuspend(const sigset_t *sigmask);

此函數用於進程的掛起,sigmask指向一個信 號集。當此函數被調用時,sigmask所指向的信號集中的信號將賦值給信號掩碼。之後進程掛起。直到進程捕 捉到信號,並調用處理函數返回時,函數sigsuspend返回。信號掩碼恢復為信號調用前的值,同時將errno設 為EINTR。進程結束信號可將其立即停止。

01.#include <stdio.h>
02.#include <signal.h>
03.
04.void checkset();
05.void func();
06.void main()
07.{
08. sigset_tblockset,oldblockset,zeroset,pendmask;
09. printf("pid:%ld\n",(long)getpid());
10. signal(SIGINT,func);
11.
12. sigemptyset(&blockset);
13. sigemptyset(&zeroset);
14. sigaddset(&blockset,SIGINT);
15.
16. sigprocmask(SIG_SETMASK,&blockset,&oldblockset);
17. checkset();
18. sigpending(&pendmask);
19.
20. if(sigismember(&pendmask,SIGINT))
21. printf("SIGINTpending\n");
22.
23. if(sigsuspend(&zeroset)!= -1)
24. {
25. printf("sigsuspenderror\n");
26. exit(0);
27. }
28.
29. printf("afterreturn\n");
30. sigprocmask(SIG_SETMASK,&oldblockset,NULL);
31.
32. printf("SIGINTunblocked\n");
33.}
34.
35.void checkset()
36.{ sigset_tset;
37. printf("checksetstart:\n");
38. if(sigprocmask(0,NULL,&set)<0)
39. {
40. printf("checksetsigprocmask error!!\n");
41. exit(0);
42. }
43.
44. if(sigismember(&set,SIGINT))
45. printf("sigint\n");
46.
47. if(sigismember(&set,SIGTSTP))
48. printf("sigtstp\n");
49.
50. if(sigismember(&set,SIGTERM))
51. printf("sigterm\n");
52. printf("checksetend\n");
53.}
54.
55.void func()
56.{
57. printf("hellofunc\n");
58.}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved