歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Unix知識 >> BSD >> FreeBSD內核讀書筆記-4.7-2

FreeBSD內核讀書筆記-4.7-2

日期:2017/2/28 11:23:06   编辑:BSD


【The work of psignal() is a patchwork of special cases required by the process-debugging and job-control facilities and by intrinsic properties associated with signals. The steps involved in posting a signal are as follows:】

【1、Determine the action that the receiving process will take when the signal is delivered. This information is kept in the p_sigignore and p_sigcatch fields of the process's process structure. If a process is not ignoring or catching a signal, the default action is presumed to apply. If a process is being traced by its parent—that is, by a debugger—the parent process is always permitted to intercede before the signal is delivered. If the process is ignoring the signal, psignal()'s work is done and the routine can return.】

在FreeBSD6.1中,上述處理的代碼在do_tdsignal()函數中。

---------------------------------------------------------------------FreeBSD6.1
1704 /*
1705 * If the signal is being ignored,
1706 * then we forget about it immediately.
1707 * (Note: we don't set SIGCONT in ps_sigignore,
1708 * and if it is set to SIG_IGN,
1709 * action will be SIG_DFL here.)
1710 */
1711 mtx_lock(&ps->ps_mtx);
1712 if (SIGISMEMBER(ps->ps_sigignore, sig) ||
1713 (p->p_flag & P_WEXIT)) {
1714 mtx_unlock(&ps->ps_mtx);
1715 return;
1716 }
1717 if (SIGISMEMBER(td->td_sigmask, sig))
1718 action = SIG_HOLD;
1719 else if (SIGISMEMBER(ps->ps_sigcatch, sig))
1720 action = SIG_CATCH;
1721 else
1722 action = SIG_DFL;
1723 if (SIGISMEMBER(ps->ps_sigintr, sig))
1724 intrval = EINTR;
1725 else
1726 intrval = ERESTART;
1727 mtx_unlock(&ps->ps_mtx);
-----------------------------------------------------------/sys/kern/kern_sig.c

首先來看SIGISMEMBER宏,其定義如下:
---------------------------------------------------------------------FreeBSD6.1
130 #define SIGISMEMBER(set, signo) \
131 ((set).__bits[_SIG_WORD(signo)] & _SIG_BIT(signo))
-----------------------------------------------------------/sys/sys/signalvar.h

其中,_SIG_WORD()和_SIG_BIT()宏以及__sigset類型的定義為:
---------------------------------------------------------------------FreeBSD6.1
44 #define _SIG_WORDS 4
......
46 #define _SIG_IDX(sig) ((sig) - 1)
47 #define _SIG_WORD(sig) (_SIG_IDX(sig) >> 5)
48 #define _SIG_BIT(sig) (1 << (_SIG_IDX(sig) & 31))
......
51 typedef struct __sigset {
52 __uint32_t __bits[_SIG_WORDS];
53 } __sigset_t;
-------------------------------------------------------------/sys/sys/_sigset.h

__sigset是一個由4個__uint32_t組成的數組。_SIG_WORD()宏根據信號值計算出該信號在數組內的下標。_SIG_BIT()宏則計算出該信號在__uint32_t內的位偏移。於是,SIGISMEMBER()宏的作用就是測試信號signo在信號集set中的對應位是否為1。
前引書雲,“Determine the action that the receiving process will take”所需的信息是存放在進程結構體的p_sigignore和p_sigcatch中的。這裡說的其實是4.4BSD的情況,代碼如下:
-------------------------------------------------------------------4.4BSD-Lite2
81 struct proc {
......
151 sigset_t p_sigmask; /* Current signal mask. */
152 sigset_t p_sigignore; /* Signals being ignored. */
153 sigset_t p_sigcatch; /* Signals being caught by user. */
----------------------------------------------------------------/sys/sys/proc.h

相應的處理代碼則是:
-------------------------------------------------------------------4.4BSD-Lite2
689 /*
690 * If the signal is being ignored,
691 * then we forget about it immediately.
692 * (Note: we don't set SIGCONT in p_sigignore,
693 * and if it is set to SIG_IGN,
694 * action will be SIG_DFL here.)
695 */
696 if (p->p_sigignore & mask)
697 return;
698 if (p->p_sigmask & mask)
699 action = SIG_HOLD;
700 else if (p->p_sigcatch & mask)
701 action = SIG_CATCH;
702 else
703 action = SIG_DFL;
-------------------------------------------------------/sys/sys/kern/kern_sig.c

而在FreeBSD中,對這些字段進行了封裝,放到了struct sigacts裡面:
---------------------------------------------------------------------FreeBSD6.1
46 /*
47 * Logical process signal actions and state, needed only within the process
48 * The mapping between sigacts and proc structures is 1:1 except for rfork()
49 * processes masquerading as threads which use one structure for the whole
50 * group. All members are locked by the included mutex. The reference count
51 * and mutex must be last for the bcopy in sigacts_copy() to work.
52 */
53 struct sigacts {
54 sig_t ps_sigact[_SIG_MAXSIG]; /* Disposition of signals. */
55 sigset_t ps_catchmask[_SIG_MAXSIG]; /* Signals to be blocked. */
56 sigset_t ps_sigonstack; /* Signals to take on sigstack. */
57 sigset_t ps_sigintr; /* Signals that interrupt syscalls. */
58 sigset_t ps_sigreset; /* Signals that reset when caught. */
59 sigset_t ps_signodefer; /* Signals not masked while handled. */
60 sigset_t ps_siginfo; /* Signals that want SA_SIGINFO args. */
61 sigset_t ps_sigignore; /* Signals being ignored. */
62 sigset_t ps_sigcatch; /* Signals being caught by user. */
63 sigset_t ps_freebsd4; /* signals using freebsd4 ucontext. */
64 sigset_t ps_osigset; /* Signals using <= 3.x osigset_t. */
65 sigset_t ps_usertramp; /* SunOS compat; libc sigtramp. XXX */
66 int ps_flag;
67 int ps_refcnt;
68 struct mtx ps_mtx;
69 };
-----------------------------------------------------------/sys/sys/signalvar.h

現在,出現在proc結構體定義代碼中的就是sigacts結構體了:
---------------------------------------------------------------------FreeBSD6.1
514 struct proc {
......
525 struct sigacts *p_sigacts; /* (x) Signal actions, state (CPU). */
----------------------------------------------------------------/sys/sys/proc.h

回到前述do_tdsignal()函數的代碼。1712行判斷入參信號sig是否已在proc.sigacts.ps_sigignore中被設置為忽略了。若是,則函數返回,不做任何處理。另外,如果當前進程正處於退出過程中,亦照此辦理。1717行判斷入參信號sig是否已在在thread.td_sigmask中被設置為屏蔽了。若是,則對應操作為SIG_HOLD,暫緩對此信號的處理,直至其解除屏蔽。注意,在4.4BSD中,信號掩碼字段的名稱是p_sigmask,它是放在進程結構體中的,而在FreeBSD中,這個字段的名稱已經變成了td_sigmask,被放到線程結構體中了。由此可見,FreeBSD對信號的屏蔽設置是以線程為單位的,而對信號的忽略和捕獲設置則仍然以進程為單位。1719行判斷入參信號sig是否已在proc.sigacts.ps_sigcatch中被設置為捕獲了。若是,則對應操作為SIG_CATCH。如果上述情況都不滿足,則在1722行將對應操作設置為SIG_DFL。
Copyright © Linux教程網 All Rights Reserved