CSAPP - Explicitly Blocking Signals
Posted on 2007-09-05 12:22 ZelluX 閱讀(364) 評(píng)論(0) 編輯 收藏 所屬分類: System看了半天總算對(duì)這節(jié)有了個(gè)大致的感覺,首先看幾個(gè)和sigprocmask相關(guān)的函數(shù):
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum); // Return: 0 if OK, -1 on error
int sigismember(const sigset_t *set, int signum); // Return: 1 if member, 0 if not, -1 on error
sigprocmask用于改變當(dāng)前blocked signals的集合,how參數(shù)指定了具體的行為:
SIG_BLOCK 把set中的信號(hào)添加到blocked列表(blocked = blocked | set)
SIG_UNBLOCK 把set中的信號(hào)從blocked列表中移出(blocked = blocked & ~set)
SIG_SETMASK blocked = set
另外,如果oldset的值不是NULL的話,之前的blocked列表會(huì)保存在oldset中。
而sigaddset sigdelset sigfillset sigemptyset都是用于操作sigset_t列表的函數(shù)。
sigprocmask適用于在父子進(jìn)程間同步的情況,以一個(gè)典型的UNIX shell程序?yàn)槔高M(jìn)程需要在一個(gè)job list中記錄它所有的子進(jìn)程,當(dāng)父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程時(shí),它把子進(jìn)程加入到j(luò)ob list中;當(dāng)父進(jìn)程reap一個(gè)子進(jìn)程時(shí),就從job list中移出這個(gè)進(jìn)程。
如果不同步父子進(jìn)程,有可能發(fā)生這種情況:
1. 父進(jìn)程執(zhí)行fork函數(shù),內(nèi)核調(diào)度新創(chuàng)建的子進(jìn)程替換父進(jìn)程運(yùn)行
2. 在父進(jìn)程能夠再次運(yùn)行前,子進(jìn)程終止,成為一個(gè)zombie,內(nèi)核發(fā)送SIGCHLD信號(hào)給父進(jìn)程
3. 父進(jìn)程可以運(yùn)行前,內(nèi)核發(fā)現(xiàn)了未處理的(pending)SIGCHLD信號(hào),讓它由父進(jìn)程的handler處理
4. handler reap了終止的進(jìn)程,調(diào)用deletejob函數(shù),實(shí)際上沒有任何作用,因?yàn)楦高M(jìn)程還沒有把該子進(jìn)程加入列表
5. handler完成后,內(nèi)核繼續(xù)運(yùn)行父進(jìn)程,后者調(diào)用fork完成后繼續(xù),錯(cuò)誤地把不存在的子進(jìn)程加入了job list
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum); // Return: 0 if OK, -1 on error
int sigismember(const sigset_t *set, int signum); // Return: 1 if member, 0 if not, -1 on error
sigprocmask用于改變當(dāng)前blocked signals的集合,how參數(shù)指定了具體的行為:
SIG_BLOCK 把set中的信號(hào)添加到blocked列表(blocked = blocked | set)
SIG_UNBLOCK 把set中的信號(hào)從blocked列表中移出(blocked = blocked & ~set)
SIG_SETMASK blocked = set
另外,如果oldset的值不是NULL的話,之前的blocked列表會(huì)保存在oldset中。
而sigaddset sigdelset sigfillset sigemptyset都是用于操作sigset_t列表的函數(shù)。
sigprocmask適用于在父子進(jìn)程間同步的情況,以一個(gè)典型的UNIX shell程序?yàn)槔高M(jìn)程需要在一個(gè)job list中記錄它所有的子進(jìn)程,當(dāng)父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程時(shí),它把子進(jìn)程加入到j(luò)ob list中;當(dāng)父進(jìn)程reap一個(gè)子進(jìn)程時(shí),就從job list中移出這個(gè)進(jìn)程。
如果不同步父子進(jìn)程,有可能發(fā)生這種情況:
1. 父進(jìn)程執(zhí)行fork函數(shù),內(nèi)核調(diào)度新創(chuàng)建的子進(jìn)程替換父進(jìn)程運(yùn)行
2. 在父進(jìn)程能夠再次運(yùn)行前,子進(jìn)程終止,成為一個(gè)zombie,內(nèi)核發(fā)送SIGCHLD信號(hào)給父進(jìn)程
3. 父進(jìn)程可以運(yùn)行前,內(nèi)核發(fā)現(xiàn)了未處理的(pending)SIGCHLD信號(hào),讓它由父進(jìn)程的handler處理
4. handler reap了終止的進(jìn)程,調(diào)用deletejob函數(shù),實(shí)際上沒有任何作用,因?yàn)楦高M(jìn)程還沒有把該子進(jìn)程加入列表
5. handler完成后,內(nèi)核繼續(xù)運(yùn)行父進(jìn)程,后者調(diào)用fork完成后繼續(xù),錯(cuò)誤地把不存在的子進(jìn)程加入了job list