請閱讀下列程式碼片段,並回答五個小題。
(a) (2 pts) 這個process第一次執行時,會在哪一行被suspend? (b) (2 pts) 當process被suspend、且一個SIGUSR2 signal被送給這個process時,process會如何反應?(A) terminated,(B) resume,(C) no action,或(D) Add SIGUSR2 to the signal mask。 (c) (2 pts) 當SIGUSR2被process捕捉到時,此時的signal mask是什麼?(A) SIGUSR1和SIGUSR2,(B) SIGUSR1,(C) SIGINT和SIGUSR2,(D) Empty。 (d) (2 pts) 當SIGINT被送出並被捕捉時,process會從哪一行恢復執行? (e) (2 pts) 若第17、19、21行的sigaction()都換成signal(),那麼在捕捉到SIGINT後恢復執行時的signal mask是什麼?(A) SIGUSR1和SIGUSR2,(B) SIGUSR1,(C) SIGINT和SIGUSR2,(D) Empty。
1 %% include all the head files
2
3 static void sigHandling(int);
4
5 int
6 main(void)
7 {
8 sigset_t newmask, oldmask, waitmask;
9 struct sigaction handling, saveintr;
10
11 pr_mask("program start: ");
12
13 handling.sa_handler = sigHandling;
14 sigemptyset(&handling.sa_mask);
15 handling.sa_flags = 0;
16
17 if (sigaction(SIGUSR1, &handling, &saveintr) < 0)
18 return(-1);
19 if (sigaction(SIGUSR2, &handling, &saveintr) < 0)
20 return(-1);
21 if (sigaction(SIGINT, &handling, &saveintr) < 0)
22 return(-1);
23
24 sigemptyset(&waitmask);
25 sigaddset(&waitmask, SIGUSR1);
26 sigemptyset(&newmask);
27 sigaddset(&newmask, SIGINT);
28
29 /*
30 * Block SIGINT and save current signal mask.
31 */
32 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
33 err_sys("SIG_BLOCK error");
34
35 /*
36 * Critical region of code.
37 */
38 pr_mask("in critical region: ");
39
40 /*
41 * Pause, allowing all signals except SIGUSR1.
42 */
43 if (sigsuspend(&waitmask) != -1)
44 err_sys("sigsuspend error");
45
46 pr_mask("after return from sigsuspend: ");
47
48 /*
49 * Reset signal mask which unblocks SIGINT.
50 */
51 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
52 err_sys("SIG_SETMASK error");
53
54 /*
55 * And continue processing ...
56 */
57 pr_mask("program exit: ");
58
59 exit(0);
60 }
61
62 static void
63 sigHandling(int signo)
64 {
65 pr_mask("\n in sigHandling:");
66 printf("Received signal %d\n", signo);
67 }
參考答案與解析
程式流程:第 17~21 行為 SIGUSR1、SIGUSR2、SIGINT 註冊同一個 handler(sa_mask 為空、sa_flags 為 0);第 32 行用 sigprocmask(SIG_BLOCK) 封鎖 SIGINT,並把原本的遮罩(空集合)存進 oldmask;第 43 行 sigsuspend(&waitmask) 暫時把遮罩換成 waitmask = {SIGUSR1} 並暫停,收到訊號、handler 返回後,sigsuspend 回傳 −1,並把遮罩恢復成呼叫前的 {SIGINT};第 51 行再把遮罩還原成空集合。
(a) 第 43 行,sigsuspend(&waitmask)。
(b) (B) resume。暫停期間的遮罩是 {SIGUSR1},SIGUSR2 沒有被封鎖,會遞送並執行 handler;handler 返回後 sigsuspend 返回,行程繼續執行。
(c) (A) SIGUSR1 和 SIGUSR2。執行 handler 時的遮罩是 sigsuspend 設定的 {SIGUSR1},再加上 sigaction() 預設會自動封鎖正在處理的訊號(sa_flags 沒有 SA_NODEFER),所以是 {SIGUSR1, SIGUSR2}。
(d) 第 46 行。SIGINT 在 sigsuspend 期間沒有被封鎖,handler 返回後 sigsuspend 回傳 −1,第 43 行的條件不成立、不會執行第 44 行,行程從第 46 行 pr_mask("after return from sigsuspend: ") 繼續執行。
(e) (B) SIGUSR1。傳統(System V)語意的 signal() 執行 handler 時不會自動封鎖正在處理的訊號,這是它和 sigaction() 的差別。捕捉到 SIGINT、進入 handler 時,遮罩是 sigsuspend 設定的 {SIGUSR1},不會再加上 SIGINT。
sigsuspend 返回之後,不論用 sigaction() 或 signal(),遮罩都會恢復成呼叫前的 {SIGINT},四個選項都沒有這個值,所以本小題問的是捕捉 SIGINT、進入 handler 時的遮罩。