Linux下C編程:sigsuspend執行過程分析

來源:互聯網
上載者:User

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

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;     }

查看全套文章:http://www.bianceng.cn/Programming/C/201212/34807.htm

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。