国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 操作系統(tǒng) > 正文

信號(hào)量機(jī)制

2024-06-28 13:24:37
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
信號(hào)量機(jī)制

信號(hào)量機(jī)制

11.1 2 個(gè)程序的例子

先看 2 個(gè)程序;

#include<unistd.h> int main(void)

{

allarm(10); for(;;;);

}

這段程序的含義比較明顯:這個(gè)程序在一個(gè)無(wú)限循環(huán)中,直到過(guò)了 10 秒,之后

程序被終止。

在來(lái)看另外一個(gè)程序:

Static void setvalue(void)

{

Flag=1;

}

int main(void) {

int sum=0; int flag=0;

struct sigaction act; act.sa_handler=setvalue,act. sa_sa_flags=0;

sigempteyset(&act,sa_mask);

sigaction(SIGINT,&act,NULL); while(flag==0)

{

sum+=1;

}

PRintf(“ the sum is %d”,&sum);

}

分析這個(gè)程序:這個(gè)程序就是注冊(cè)一個(gè)捕獲信號(hào)量 SIGINT(在兼容 POSIX 內(nèi)會(huì)

169

默認(rèn)是 Ctrl+C),捕獲到這個(gè)信號(hào)量之后執(zhí)行 setvalue 函數(shù),就停止加,最后將結(jié) 果打印出來(lái)之后程序(進(jìn)程)結(jié)束。

舉這 2 個(gè)程序的目的是:用戶(hù)程序編寫(xiě)者需要異步執(zhí)行,需要異步觸發(fā)時(shí)間,操 作系統(tǒng)必須提供這樣的功能---異步執(zhí)行。在 MINX3 中,用信號(hào)量來(lái)實(shí)現(xiàn)這種異 步功能。

11.2 MINIX 信號(hào)量機(jī)制概述

MINIX3 采用微內(nèi)核結(jié)構(gòu),PM(進(jìn)程管理器)是放到內(nèi)核外執(zhí)行,但是你或許 已經(jīng)感受到,信號(hào)量的機(jī)制實(shí)現(xiàn)一定要靠?jī)?nèi)核的幫助來(lái)完成。所以信號(hào)量的實(shí)現(xiàn) 還是比較復(fù)雜。

首先我們想象一個(gè)事情:一個(gè)進(jìn)程怎么能夠讓 PM 和內(nèi)核知道它設(shè)定了一個(gè)信號(hào) 量呢?事實(shí)上內(nèi)核部分是不知道的,內(nèi)核的功能就是接受消息之后將它發(fā)送出 去。事實(shí)上,真正實(shí)現(xiàn)信號(hào)量的主體部分是 PM 部分,這點(diǎn)到后會(huì)非常的清楚。 先默認(rèn)是 PM 來(lái)控制信號(hào)量主體實(shí)現(xiàn),我們來(lái)看看 PM:

在 PM 中,我們同樣定義了一個(gè)進(jìn)程表數(shù)組,為每一個(gè)進(jìn)程設(shè)定一個(gè)數(shù)據(jù)結(jié)構(gòu), 這個(gè)結(jié)構(gòu)是

EXTERN struct mproc {

……….

/* Signal handling information. */

sigset_t mp_ignore;

sigset_t mp_catch; sigset_t mp_sig2mess; sigset_t mp_sigmask; sigset_t mp_sigmask2;

/* 1 means ignore the signal, 0 means don't */

/* 1 means catch the signal, 0 means don't */ /* 1 means transform into notify message */ /* signals to be blocked */

/* saved copy of mp_sigmask */

sigset_t mp_sigpending; /* pending signals to be handled */

struct sigaction mp_sigact[_NSIG + 1]; /* as in sigaction(2) */

vir_bytes mp_sigreturn; /* address of C library __sigreturn function */

struct timer mp_timer; /* watchdog timer for alarm(2) */ …………

}mproc[NR_PROCS];

可以看到這里定義了一個(gè)靜態(tài)變量數(shù)組。上面暫且展現(xiàn)了與信號(hào)量有關(guān)的域

先看下 strcut sigaction mp_sigact[NSIG+1];這個(gè)是一個(gè)結(jié)構(gòu)體數(shù)組,里面每一項(xiàng) 都是 sigaction。這里每一個(gè)項(xiàng)就是存儲(chǔ)一個(gè)信號(hào)量信息。如果進(jìn)程有需要標(biāo)記信

號(hào)量,則就是在這個(gè)結(jié)構(gòu)體數(shù)組標(biāo)志,這里到后面還要詳細(xì)介紹。sigset_t *

都是一些位圖,用于標(biāo)志一些 flag.之后 vir_bytes mp_sigreturn,這是 C 語(yǔ)言庫(kù)里面 _sigreturn 函數(shù)的地址,我們可以設(shè)想下,當(dāng)捕獲函數(shù)完成后,我們應(yīng)該怎么辦, 必須要讓用戶(hù)進(jìn)程毫無(wú)察覺(jué)到的放回,所以必須有一個(gè)函數(shù)來(lái)完成這個(gè)任務(wù),而 且最終是靠?jī)?nèi)核設(shè)置相關(guān)棧來(lái)完成,這個(gè)數(shù)據(jù)項(xiàng)就是這個(gè)函數(shù)地址。最后一個(gè)數(shù) 據(jù)結(jié)構(gòu)就是一個(gè)看門(mén)狗時(shí)鐘,用于處理與時(shí)鐘相關(guān)的例程。這個(gè)在后面會(huì)詳細(xì)的 介紹。

170

wpsB8AE.tmp

11.3 MINIX3 信號(hào)量機(jī)制源碼導(dǎo)讀

函數(shù)主要放在 pm/signal.c 中,我在這里會(huì)把與內(nèi)核相關(guān)的系統(tǒng)調(diào)用函數(shù)也拿出 來(lái),主要是為了講解的方便。首先是看 do_sigaction()函數(shù): 這個(gè)函數(shù)調(diào)用的宏觀(guān)過(guò)程如下圖:

/*=================================================================== ========*

* do_sigaction 執(zhí)行SIGACTION系統(tǒng)調(diào)用,這個(gè)系統(tǒng)調(diào)用沒(méi)

有參數(shù),參數(shù)都是在m_in信息里 這個(gè)函數(shù)主體就是注冊(cè)一個(gè)信號(hào)量 *

*==================================================================== =======*/

PUBLIC int do_sigaction() {

int r;

struct sigaction svec; struct sigaction *svp;

//SIGKILL代表不能捕獲信號(hào)量,就返回

if (m_in.sig_nr == SIGKILL) return(OK); //不在范圍內(nèi),返回錯(cuò)誤信息

if (m_in.sig_nr < 1 || m_in.sig_nr > _NSIG) return (EINVAL);

//svp是指向sigaction的地址,在這里,要理解mp_sigact[]數(shù)組的含義,里面 每一個(gè)元值都表示一個(gè)信號(hào)處理結(jié)構(gòu).用m_in.sig_nr做索引

svp = &mp->mp_sigact[m_in.sig_nr];

//準(zhǔn)備注冊(cè)一個(gè)信號(hào)量 將系統(tǒng)任務(wù)的當(dāng)前屬性全部復(fù)制到m_in.sig_osa所指向 //的變量中

171

if ((struct sigaction *) m_in.sig_osa != (struct sigaction *) NULL) { r = sys_datacopy(PM_PROC_NR,(vir_bytes) svp,

who, (vir_bytes) m_in.sig_osa, (phys_bytes) sizeof(svec)); if (r != OK) return(r);

}

if ((struct sigaction *) m_in.sig_nsa == (struct sigaction *) NULL) return(OK);

/* Read in the sigaction structure. */

r = sys_datacopy(who, (vir_bytes) m_in.sig_nsa,

PM_PROC_NR, (vir_bytes) &svec, (phys_bytes) sizeof(svec)); if (r != OK) return(r);

// SIG_IGN代表忽略這個(gè)信號(hào)量

if (svec.sa_handler == SIG_IGN) {

sigaddset(&mp->mp_ignore, m_in.sig_nr);

sigdelset(&mp->mp_sigpending, m_in.sig_nr); sigdelset(&mp->mp_catch, m_in.sig_nr); sigdelset(&mp->mp_sig2mess, m_in.sig_nr);

//默認(rèn)信號(hào)處理函數(shù)

} else if (svec.sa_handler == SIG_DFL) { sigdelset(&mp->mp_ignore, m_in.sig_nr); sigdelset(&mp->mp_catch, m_in.sig_nr);

sigdelset(&mp->mp_sig2mess, m_in.sig_nr);

//做為一個(gè)信息傳遞到到MINIX中

} else if (svec.sa_handler == SIG_MESS) {

if (! (mp->mp_flags & PRIV_PROC)) return(EPERM); sigdelset(&mp->mp_ignore, m_in.sig_nr); sigaddset(&mp->mp_sig2mess, m_in.sig_nr); sigdelset(&mp->mp_catch, m_in.sig_nr);

//捕獲自己定義的函數(shù)

} else {

sigdelset(&mp->mp_ignore, m_in.sig_nr); sigaddset(&mp->mp_catch, m_in.sig_nr); sigdelset(&mp->mp_sig2mess, m_in.sig_nr); }

//將svec結(jié)構(gòu)體各個(gè)域傳遞給mp結(jié)構(gòu)體,也將其他的一些信息傳遞給 mp->mp_sigaction[],最終確定注冊(cè)成功。

mp->mp_sigact[m_in.sig_nr].sa_handler = svec.sa_handler; sigdelset(&svec.sa_mask, SIGKILL);

mp->mp_sigact[m_in.sig_nr].sa_mask = svec.sa_mask;

mp->mp_sigact[m_in.sig_nr].sa_flags = svec.sa_flags; mp->mp_sigreturn = (vir_bytes) m_in.sig_ret; return(OK);

}

172

/*=================================================================== ========*

* check_sig 這個(gè)函數(shù)就是發(fā)送信號(hào)的一個(gè)接口 *

*====================================================================

=======*/

PUBLIC int check_sig(proc_id, signo)

pid_t proc_id; /* pid of proc to sig, or 0 or -1, or -pgrp */

int signo; /* signal to send to process (0 to _NSIG) */

{

/* Check to see if it is possible to send a signal. The signal may have to be sent to a group of processes. This routine is invoked by the KILL system call, and also when the kernel catches a DEL or other signal.

*/

//檢查看是否需要發(fā)送一個(gè)信號(hào)量,信號(hào)量也許不得不發(fā)送給一組進(jìn)程。

//當(dāng)然當(dāng)內(nèi)核捕獲到一個(gè)DEL或者其他信號(hào)時(shí),這個(gè)例程涉及到KILL系統(tǒng)調(diào)用 register struct mproc *rmp;

int count; /* count # of signals sent */

int error_code;

//檢查要發(fā)送的信號(hào)量是否合法

if (signo < 0 || signo > _NSIG) return(EINVAL);

//如果嘗試給INIT_PID進(jìn)程發(fā)送SIGKILL信號(hào),將會(huì)產(chǎn)生錯(cuò)誤 //這個(gè)在開(kāi)機(jī)時(shí)永遠(yuǎn)不會(huì)被殺死

/* Return EINVAL for attempts to send SIGKILL to INIT alone. */ if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL); //對(duì)進(jìn)程表搜索進(jìn)程信號(hào)量

/* Search the proc table for processes to signal.

* pid magic.)

*/

count = 0;

error_code = ESRCH;

(See forkexit.c about

for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { if (!(rmp->mp_flags & IN_USE)) continue;

if ((rmp->mp_flags & ZOMBIE) && signo != 0) continue;

/* Check for selection. */

if (proc_id > 0 && proc_id != rmp->mp_pid) continue;

if (proc_id == 0 && mp->mp_procgrp != rmp->mp_procgrp) continue; if (proc_id == -1 && rmp->mp_pid <= INIT_PID) continue;

173

if (proc_id < -1 && rmp->mp_procgrp != -proc_id) continue;

/* Check for permission. */

if (mp->mp_effuid != SUPER_USER

&& mp->mp_realuid != rmp->mp_realuid && mp->mp_effuid != rmp->mp_realuid && mp->mp_realuid != rmp->mp_effuid

&& mp->mp_effuid != rmp->mp_effuid) { error_code = EPERM;

continue;

}

count++;

if (signo == 0) continue;

/* 'sig_proc' will handle the disposition of the signal. The * signal may be caught, blocked, ignored, or cause process * termination, possibly with core dump.

*/

//找到滿(mǎn)足條件后,將調(diào)用sig_proc()函數(shù),來(lái)處理這個(gè)信號(hào)量

sig_proc(rmp, signo);

if (proc_id > 0) break; /* only one process being signaled */

}

/* If the calling process has killed itself, don't reply. */

if ((mp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return(SUSPEND); return(count > 0 ? OK : error_code);

}

在往下面分析之前,先看一個(gè)結(jié)構(gòu)體。

/* PM passes the address of a structure of this type to KERNEL when

* sys_sendsig() is invoked as part of the signal catching mechanism. * The structure contain all the information that KERNEL needs to build * the signal stack.當(dāng)使用sys_sendsing()這個(gè)函數(shù)來(lái)進(jìn)行捕獲 PM傳遞將這 個(gè)結(jié)構(gòu)體傳遞給內(nèi)核。這個(gè)結(jié)構(gòu)體包含了所用內(nèi)核想要建造的信號(hào)棧信息

*/

struct sigmsg {

int sm_signo; /* signal number being caught 捕獲信號(hào)量號(hào) */

unsigned long sm_mask; /* mask to restore when handler returns 當(dāng)處

理返回時(shí) 重新標(biāo)記一些標(biāo)記位*/

vir_bytes sm_sighandler; /* address of handler 信號(hào)量處理地址 */

vir_bytes sm_sigreturn; /* address of _sigreturn in C library 事實(shí)

上是一個(gè)信號(hào)量返回地址,在這里就是_sigreturn地址*/

vir_bytes sm_stkptr; /* user stack pointer 用戶(hù)棧的指針 */

174

};

這個(gè)結(jié)構(gòu)體得功能其實(shí)就是PM所處理的一個(gè)專(zhuān)門(mén)為信號(hào)量所設(shè)置的結(jié)構(gòu)體,主要 功能是為內(nèi)核提供所有想要的棧信息。

/*=================================================================== ========*

* sig_proc 這個(gè)函數(shù)是最重要的是處理信號(hào)量的核心函數(shù)

*

*==================================================================== =======*/

PUBLIC void sig_proc(rmp, signo)

register struct mproc *rmp; /* pointer to the process to be signaled */

int signo; /* signal to send to process (1 to _NSIG) */

{

/* Send a signal to a process. Check to see if the signal is to be caught, * ignored, tranformed into a message (for system processes) or blocked. * 給一個(gè)進(jìn)程發(fā)送一個(gè)信號(hào)量。檢查看看這個(gè)信號(hào)是否被捕獲,忽略,轉(zhuǎn)變成 一個(gè)消息或者阻塞

* - If the signal is to be transformed into a message, request the KERNEL to send the target process a system notification with the pending signal as an argument.

如果這個(gè)信號(hào)量被轉(zhuǎn)成一個(gè)消息,請(qǐng)求內(nèi)核發(fā)送一個(gè)系統(tǒng)通知給這個(gè)目標(biāo)進(jìn)程 * - If the signal is to be caught, request the KERNEL to push a sigcontext * structure and a sigframe structure onto the catcher's stack. Also, KERNEL will reset the program counter and stack pointer, so that when the process next runs, it will be executing the signal handler. When the signal handler returns, sigreturn(2) will be called. Then KERNEL will

restore the signal context from the sigcontext structure.

如果這個(gè)信號(hào)量被捕獲,請(qǐng)求內(nèi)核將sigcontext壓入棧中并且將sigframe結(jié)構(gòu) 壓入捕獲者的棧中。當(dāng)然,內(nèi)核將會(huì)重新設(shè)置這個(gè)程序計(jì)數(shù)器和堆棧指針,所以 當(dāng)進(jìn)程在下次來(lái)運(yùn)行時(shí),他將會(huì)執(zhí)行信號(hào)處理函數(shù)。當(dāng)信號(hào)處理函數(shù)返回時(shí), sigreturn(2)例程將會(huì)被調(diào)用。內(nèi)核將會(huì)重新從sigcontext結(jié)構(gòu)重新設(shè)置信號(hào)量 上下文

* If there is insufficient stack space, kill the process. 如果沒(méi)有充足堆棧空間,將會(huì)殺死這個(gè)進(jìn)程

*/

vir_bytes new_sp; int s;

int slot;

int sigflags;

struct sigmsg sm;

slot = (int) (rmp - mproc);

175

//查看進(jìn)程表中目的進(jìn)程的標(biāo)志位,看看其是不是IN_USE,如果該進(jìn)程已經(jīng)結(jié) 束或者僵死

//將不能執(zhí)行這個(gè)操作。

if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) {

printf("PM: signal %d sent to %s process %d/n",

signo, (rmp->mp_flags & ZOMBIE) ? "zombie" : "dead", slot); panic(__FILE__,"", NO_NUM);

}

//查看進(jìn)程的標(biāo)志位,如果該進(jìn)程正在被跟蹤,那么就收到這個(gè)信號(hào)量后,將 停止操作

if ((rmp->mp_flags & TRACED) && signo != SIGKILL) { /* A traced process has special handling. */

unpause(slot);

stop_proc(rmp, signo); /* a signal causes it to stop */

return;

}

//如果信號(hào)量被忽略,則函數(shù)結(jié)束

/* Some signals are ignored by default. */ if (sigismember(&rmp->mp_ignore, signo)) { return;

}

//如果信號(hào)量被阻塞,將mp_sigpending位圖設(shè)置相應(yīng)的位 if (sigismember(&rmp->mp_sigmask, signo)) { /* Signal should be blocked. */

sigaddset(&rmp->mp_sigpending, signo); return;

}

#if ENABLE_SWAP

if (rmp->mp_flags & ONSWAP) {

/* Process is swapped out, leave signal pending. */

sigaddset(&rmp->mp_sigpending, signo);

swap_inqueue(rmp);

return;

}

#endif

//函數(shù)的主體部分,非常重要

sigflags = rmp->mp_sigact[signo].sa_flags;

//首先判斷時(shí)候捕獲這個(gè)信號(hào)量

if (sigismember(&rmp->mp_catch, signo)) { if (rmp->mp_flags & SIGSUSPENDED) sm.sm_mask = rmp->mp_sigmask2;

else

sm.sm_mask = rmp->mp_sigmask;

sm.sm_signo = signo;//被捕獲的信號(hào)量號(hào)

176

//被捕獲信號(hào)量處理函數(shù)的首地址

sm.sm_sighandler = (vir_bytes) rmp->mp_sigact[signo].sa_handler;

//被捕獲的信號(hào)量處理函數(shù)的返回地址,這個(gè)地址是在庫(kù)函數(shù)中

sm.sm_sigreturn = rmp->mp_sigreturn;

//分配新的堆棧主要用于儲(chǔ)存信息

if ((s=get_stack_ptr(slot, &new_sp)) != OK)

panic(__FILE__,"couldn't get new stack pointer",s); //將捕獲的信號(hào)量處理函數(shù)的堆棧地址儲(chǔ)存起來(lái)

sm.sm_stkptr = new_sp;

//給sigcontext和sigframe結(jié)構(gòu)騰出地址來(lái),new_sp的地址也就隨之改變 /* Make room for the sigcontext and sigframe struct. */ new_sp -= sizeof(struct sigcontext)

+ 3 * sizeof(char *) + 2 * sizeof(int);

if (adjust(rmp, rmp->mp_seg[D].mem_len, new_sp) != OK) goto doterminate;

//給進(jìn)程的信號(hào)量進(jìn)行標(biāo)識(shí),也就是設(shè)定標(biāo)識(shí)位

rmp->mp_sigmask |= rmp->mp_sigact[signo].sa_mask; if (sigflags & SA_NODEFER)

sigdelset(&rmp->mp_sigmask, signo);

else

sigaddset(&rmp->mp_sigmask, signo);

if (sigflags & SA_RESETHAND) {

sigdelset(&rmp->mp_catch, signo);

rmp->mp_sigact[signo].sa_handler = SIG_DFL; }

//給內(nèi)核發(fā)送消息,消息存儲(chǔ)在sm內(nèi)。當(dāng)然這不是進(jìn)入內(nèi)核的最終消息格式 //關(guān)于sys_sigsend在下面有詳細(xì)分析

if (OK == (s=sys_sigsend(slot, &sm))) {

sigdelset(&rmp->mp_sigpending, signo);

/* If process is hanging on PAUSE, WAIT, SIGSUSPEND, tty, * pipe, etc., release it.

*/

unpause(slot); return;

}

panic(__FILE__, "warning, sys_sigsend failed", s);

}

//

else if (sigismember(&rmp->mp_sig2mess, signo)) { if (OK != (s=sys_kill(slot,signo)))

panic(__FILE__, "warning, sys_kill failed", s);

177

return;

}

doterminate:

/* Signal should not or cannot be caught. Take default action. */ if (sigismember(&ign_sset, signo)) return;

rmp->mp_sigstatus = (char) signo;

if (sigismember(&core_sset, signo)) { #if ENABLE_SWAP

if (rmp->mp_flags & ONSWAP) {

/* Process is swapped out, leave signal pending. */

sigaddset(&rmp->mp_sigpending, signo);

swap_inqueue(rmp);

return;

}

#endif

/* Switch to the user's FS environment and dump core. */

tell_fs(CHDIR, slot, FALSE, 0);

dump_core(rmp);

}

pm_exit(rmp, 0); /* terminate process */

}

往下講解之前先看下幾個(gè)結(jié)構(gòu)體: struct sigregs {

#if _Word_SIZE == 4 short sr_gs;

short sr_fs;

#endif /* _WORD_SIZE == 4 */ short sr_es;

short sr_ds; int sr_di; int sr_si; int sr_bp;

int sr_st; /* stack top -- used in kernel */

int sr_bx; int sr_dx; int sr_cx;

int sr_retreg;

int sr_retadr; /* return address to caller of save -- used

* in kernel */

int sr_pc;

int sr_cs;

178

int sr_psw; int sr_sp; int sr_ss; };

struct sigframe { /* stack frame created for signalled process */

_PROTOTYPE( void (*sf_retadr), (void) );

int sf_signo;

int sf_code;

struct sigcontext *sf_scp; int sf_fp;

_PROTOTYPE( void (*sf_retadr2), (void) ); struct sigcontext *sf_scpcopy;

};

struct sigcontext {

int sc_flags; /* sigstack state to restore */

long sc_mask; /* signal mask to restore */

struct sigregs sc_regs; /* register set to restore */

};

對(duì)上面的結(jié)構(gòu)體一一做出一個(gè)解釋?zhuān)?

第1:struct sigregs 這個(gè)結(jié)構(gòu)體存儲(chǔ)的是CPU各個(gè)寄存器的值和一些其他的值: 一些通用寄存器的值就不介紹了,現(xiàn)在來(lái)介紹幾個(gè)與寄存器值無(wú)關(guān)的值。

int sr_st; /* stack top -- used in kernel */

這個(gè)值的意思就是棧頂指針,先記住,在后面的分析中會(huì)有介紹

int sr_retadr; 這個(gè)值的意思是調(diào)用者保留的返回地址,在進(jìn)行信號(hào)量的處理 過(guò)程中,會(huì)涉及到處理調(diào)用者的最后用戶(hù)狀態(tài)的下地址,所以這里必須要設(shè)一個(gè) 值進(jìn)行保存

第2:sigframe 這個(gè)結(jié)構(gòu)體主作用的就是3個(gè): struct sigcontext *sf_scopy 和 int sf_signo以及 void(*sf_retadr)(void)

struct sigcontext *sf_scopy 這個(gè)是指向sigcontext結(jié)構(gòu)體,下面會(huì)介紹。 int sf_signo 是被信號(hào)量號(hào)

void (*sf_retadr)(void)是返回函數(shù)的地址。

第3 sigcontext結(jié)構(gòu)體,主要是儲(chǔ)存做上下文切換動(dòng)作一些必需量。 先看下執(zhí)行流程圖(對(duì)于上下函數(shù)的一個(gè)銜接)

179

wpsB8CE.tmp

#include "syslib.h"

/*=================================================================== ========*

* sys_sigsend (本來(lái)本函數(shù)在Lib文件中

但是方便講解,在這里拿出來(lái)) 接著上面的動(dòng)作進(jìn)行分析 *

*====================================================================

=======*/

PUBLIC int sys_sigsend(proc_ep, sig_ctxt)

endpoint_t proc_ep; /* for which process */

struct sigmsg *sig_ctxt; /* POSIX style handling */

{ //這個(gè)函數(shù)主要是構(gòu)造一個(gè)消息,之后發(fā)往內(nèi)核

message m; int result;

m.SIG_ENDPT = proc_ep;

m.SIG_CTXT_PTR = (char *) sig_ctxt;

// SIG_CTXT_PTR代表的就是信號(hào)量上下文地址

result = _kernel_call(SYS_SIGSEND, &m);

//給內(nèi)核發(fā)送一條消息,將執(zhí)行系統(tǒng)調(diào)用

//系統(tǒng)調(diào)用號(hào)時(shí)SYS_SIGSEND,下面也將這個(gè)do_sigsend函數(shù)附上來(lái)

180

wpsB8EE.tmp

return(result);

}

這個(gè)函數(shù)的主體是進(jìn)行一系列復(fù)制動(dòng)作,最關(guān)鍵的信息就是將用戶(hù)棧的

rp_p_regs結(jié)構(gòu)體復(fù)制sigmsg這個(gè)結(jié)構(gòu)。這個(gè)結(jié)構(gòu)體是非常重要的。你想象一下, 如果我現(xiàn)在準(zhǔn)備捕獲一個(gè)信號(hào)量,我們動(dòng)用了這個(gè)信號(hào)量處理函數(shù)之后,棧和各 個(gè)寄存器值都可能發(fā)生變化,所以必須要做出一個(gè)保留工作,這個(gè)函數(shù)主體就是 做這個(gè)工作。之后將各個(gè)結(jié)構(gòu)體的各個(gè)域初始化。

看看這個(gè)函數(shù)主體是做一個(gè)什么工作,先看下這個(gè)函數(shù)執(zhí)行流程圖:

/*=================================================================== ========*

* do_sigsend 這里的m_ptr其實(shí)就是上面的消息m

函數(shù)主要設(shè)置相關(guān)信息到用戶(hù)棧 *

*==================================================================== =======*/

PUBLIC int do_sigsend(m_ptr)

message *m_ptr; /* pointer to request message */

{

/* Handle sys_sigsend, POSIX-style signal handling. */ //處理sys_sigsend 這么做是為了符合POSIX標(biāo)準(zhǔn) struct sigmsg smsg;

register struct proc *rp;

phys_bytes src_phys, dst_phys; struct sigcontext sc, *scp; struct sigframe fr, *frp;

181

if (! isokprocn(m_ptr->SIG_PROC)) return(EINVAL);

if (iskerneln(m_ptr->SIG_PROC)) return(EPERM);

rp = proc_addr(m_ptr->SIG_PROC);//待通知進(jìn)程的地址

//sigmsg結(jié)構(gòu)從用戶(hù)狀態(tài)復(fù)制到內(nèi)核地址空間 下面這調(diào)用這2個(gè)函數(shù)的目的 比較明確,就是把用戶(hù)態(tài)已經(jīng)寫(xiě)好的sigmsg結(jié)構(gòu)體復(fù)制到這里所定義的smsg結(jié)構(gòu) 體中。這個(gè)起始地址是src_phys

/* Get the sigmsg structure into our address space. */

src_phys = umap_local(proc_addr(PM_PROC_NR), D, (vir_bytes) m_ptr->SIG_CTXT_PTR, (vir_bytes) sizeof(struct sigmsg)); if (src_phys == 0) return(EFAULT);

phys_copy(src_phys,vir2phys(&smsg),(phys_bytes) sizeof(struct sigmsg));

/* Compute the user stack pointer where sigcontext will be stored. */ //smsg.sm_stkptr-1是用戶(hù)棧指針?biāo)赶虻牡胤?

scp = (struct sigcontext *) smsg.sm_stkptr - 1;

/* Copy the registers to the sigcontext structure. */ //將CPU中的寄存器都復(fù)制到sigcontext結(jié)構(gòu)

memcpy(&sc.sc_regs, (char *) &rp->p_reg, sizeof(struct sigregs));

/* Finish the sigcontext initialization. */

//將sc其他2個(gè)量進(jìn)行設(shè)置

sc.sc_flags = SC_SIGCONTEXT; sc.sc_mask = smsg.sm_mask;

/* Copy the sigcontext structure to the user's stack. */

//將剛剛設(shè)置好的sigcontext結(jié)構(gòu)體復(fù)制到要發(fā)送信號(hào)量的用戶(hù)棧進(jìn)程中

dst_phys = umap_local(rp, D, (vir_bytes) scp,

(vir_bytes) sizeof(struct sigcontext)); if (dst_phys == 0) return(EFAULT);

phys_copy(vir2phys(&sc), dst_phys, (phys_bytes) sizeof(struct sigcontext));

/* Initialize the sigframe structure. */

//現(xiàn)在做最后一步工作,初始化sigframe結(jié)構(gòu)體工作。這個(gè)結(jié)構(gòu)體對(duì)從信號(hào)量的 //返回有非常中要的作用

frp = (struct sigframe *) scp - 1; fr.sf_scpcopy = scp;

fr.sf_retadr2= (void (*)()) rp->p_reg.pc; fr.sf_fp = rp->p_reg.fp;

rp->p_reg.fp = (reg_t) &frp->sf_fp; fr.sf_scp = scp;

fr.sf_code = 0; /* XXX - should be used for type of FP exception */

182

fr.sf_signo = smsg.sm_signo;

fr.sf_retadr = (void (*)()) smsg.sm_sigreturn;

/* Copy the sigframe structure to the user's stack. */

dst_phys = umap_local(rp, D, (vir_bytes) frp, (vir_bytes) sizeof(struct sigframe)); if (dst_phys == 0) return(EFAULT);

phys_copy(vir2phys(&fr), dst_phys, (phys_bytes) sizeof(struct sigframe));

/* Reset user registers to execute the signal handler. */ //設(shè)置用戶(hù)寄存器來(lái)執(zhí)行信號(hào)處理函數(shù)

rp->p_reg.sp = (reg_t) frp;

rp->p_reg.pc = (reg_t) smsg.sm_sighandler;

return(OK);

}

從時(shí)間上看,執(zhí)行完上一個(gè)函數(shù)之后,還是在內(nèi)核中,內(nèi)核調(diào)度器調(diào)度上面被設(shè) 置信號(hào)量的進(jìn)程之后,進(jìn)程就會(huì)調(diào)用信號(hào)量處理函數(shù),這個(gè)宏觀(guān)上只是一個(gè)順序 執(zhí)行,但是在微觀(guān)上還是做了非常多動(dòng)作。

現(xiàn)在我們分析這個(gè)問(wèn)題,信號(hào)量函數(shù)處理完之后,我們是不是應(yīng)該設(shè)置一個(gè)函數(shù) 來(lái)執(zhí)行信號(hào)量返回調(diào)用的操作?答案是毫無(wú)疑問(wèn)的,因?yàn)檫@個(gè)動(dòng)作能需要重新設(shè) 置相關(guān)的寄存器的量。我們就從這個(gè)動(dòng)作開(kāi)始 也就是 do_sigreturn,這個(gè)函數(shù)是 PM 一個(gè)調(diào)用函數(shù)。我們假設(shè)已經(jīng)進(jìn)入了這個(gè)函數(shù)。我先看下 do_sigreturn 主要 是干了什么工作?

do_sigreturn 函數(shù)主要是調(diào)用這個(gè) sys_sigreturn 函數(shù),這個(gè)函數(shù)是與內(nèi)核函數(shù)的 一個(gè)接口,調(diào)用系統(tǒng)任務(wù)的系統(tǒng)函數(shù)。

/*=================================================================== ========*

* do_sigreturn 注意這個(gè)函數(shù)是PM機(jī)制下的信號(hào)返回函數(shù),下面

那個(gè)函數(shù)是內(nèi)核狀態(tài)下的信號(hào)返回函數(shù) *

*==================================================================== =======*/

PUBLIC int do_sigreturn() {

/* A user signal handler is done. Restore context and check for * pending unblocked signals.

*/

int r;

mp->mp_sigmask = (sigset_t) m_in.sig_set; sigdelset(&mp->mp_sigmask, SIGKILL);

183

r = sys_sigreturn(who, (struct sigmsg *) m_in.sig_context); check_pending(mp);

return(r);

}

/*=================================================================== ========*

* sys_sigreturn 與內(nèi)核的一個(gè)接口函

數(shù),函數(shù)主體構(gòu)造一個(gè)消息,調(diào)用do_sigreturn函數(shù),我們就順著往后面那個(gè)

函數(shù) *

*====================================================================

=======*/

PUBLIC int sys_sigreturn(proc_ep, sig_ctxt)

endpoint_t proc_ep;

struct sigmsg *sig_ctxt; {

message m;

int result;

m.SIG_ENDPT = proc_ep;

/* for which process */ /* POSIX style handling */

m.SIG_CTXT_PTR = (char *) sig_ctxt;

result = _kernel_call(SYS_SIGRETURN, &m); return(result);

}

我們接著上面的那個(gè)函數(shù),現(xiàn)在來(lái)看看這個(gè)函數(shù),這個(gè)函數(shù)的主體就是將之前保 留的p_regs都還原到現(xiàn)在這個(gè)進(jìn)程的p_regs

184

wpsB90F.tmp

/*=================================================================== ========*

* do_sigreturn 內(nèi)核處理信號(hào)返回函數(shù),這個(gè)函數(shù)上面那個(gè)函

數(shù)調(diào)用SYSTEM進(jìn)程,之后SYSTEM進(jìn)程就調(diào)用這個(gè)函數(shù) *

*==================================================================== =======*/

PUBLIC int do_sigreturn(m_ptr)

message *m_ptr; /* pointer to request message */

{

/* POSIX style signals require sys_sigreturn to put things in order before * the signalled process can resume execution

*/

struct sigcontext sc;

register struct proc *rp; phys_bytes src_phys;

if (! isokprocn(m_ptr->SIG_PROC)) return(EINVAL); if (iskerneln(m_ptr->SIG_PROC)) return(EPERM); rp = proc_addr(m_ptr->SIG_PROC);

185

/* Copy in the sigcontext structure. */

//復(fù)制sigcontext結(jié)構(gòu),分析下從哪里復(fù)制到哪里!

//這種復(fù)制就是從外核復(fù)制到內(nèi)核中,將m_ptr結(jié)構(gòu)所指向的sigcontext結(jié)構(gòu)體 復(fù)制到前面所定義的結(jié)構(gòu)體sc中。

//注意這里是返回操作!返回就是將之前所定義好的內(nèi)核寄存器復(fù)原。這點(diǎn)比較 的總要,在后的代碼會(huì)有所涉及!

src_phys = umap_local(rp, D, (vir_bytes) m_ptr->SIG_CTXT_PTR, (vir_bytes) sizeof(struct sigcontext));

if (src_phys == 0) return(EFAULT);

phys_copy(src_phys, vir2phys(&sc), (phys_bytes) sizeof(struct sigcontext));

/* Make sure that this is not just a jump buffer. */

if ((sc.sc_flags & SC_SIGCONTEXT) == 0) return(EINVAL);

/* Fix up only certain key registers if the compiler doesn't use * register variables within functions containing setjmp. */

//將rp.p_reg復(fù)原捕獲信號(hào)量前得各個(gè)值,這點(diǎn)很重要,因?yàn)樵诓东@信號(hào)量時(shí), 指向信號(hào)處理函數(shù),可能各個(gè)寄存器的值都發(fā)生了變化,為了保持他們?cè)瓉?lái)的狀 態(tài),這里必須進(jìn)行在一次的復(fù)制

if (sc.sc_flags & SC_NOREGLOCALS) { rp->p_reg.retreg = sc.sc_retreg; rp->p_reg.fp = sc.sc_fp; rp->p_reg.pc = sc.sc_pc; rp->p_reg.sp = sc.sc_sp; return(OK);

}

sc.sc_psw = rp->p_reg.psw;

#if (CHIP == INTEL)

/* Don't panic kernel if user gave bad selectors. */

//段選擇器的恢復(fù)工作,將rp指向的進(jìn)程各個(gè)段選擇器都復(fù)制到sc結(jié)構(gòu)體相應(yīng)的 域中。為后面的還原過(guò)程做出基礎(chǔ)

sc.sc_cs = rp->p_reg.cs; sc.sc_ds = rp->p_reg.ds; sc.sc_es = rp->p_reg.es; #if _WORD_SIZE == 4 sc.sc_fs = rp->p_reg.fs; sc.sc_gs = rp->p_reg.gs;

#endif

#endif

186

wpsB92F.tmp

/* Restore the registers. */

//這里就是全部重新賦值,sc.sc_regs的各個(gè)值都恢復(fù)到被信號(hào)量的棧值。 memcpy(&rp->p_reg, &sc.sc_regs, sizeof(struct sigregs)); return(OK);

}

從時(shí)間軸上來(lái)看。執(zhí)行完這個(gè)函數(shù),只要調(diào)度器調(diào)度這個(gè)進(jìn)程,這個(gè)進(jìn)程就可以 繼續(xù)被信號(hào)量中斷前得指令繼續(xù)執(zhí)行。從宏觀(guān)上,用戶(hù)只是會(huì)覺(jué)得整個(gè)調(diào)用過(guò)程 就是一個(gè)普通的調(diào)用函數(shù)一樣。!

MINIX3 的信號(hào)量機(jī)制基本上就是這樣,事實(shí)上,讀者可以結(jié)合前面的時(shí)鐘機(jī)制, 繼續(xù)分析一次 alarm 怎么來(lái)實(shí)現(xiàn)這種信號(hào)量機(jī)制!最后用一副圖來(lái)表示我們整個(gè) 執(zhí)行過(guò)程:

至此,信號(hào)量處理機(jī)制基本講解完成,信號(hào)量機(jī)制比較復(fù)雜,需要仔細(xì)的分析。


上一篇:有名管道_2

下一篇:倒騰路由器

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 峨边| 丹东市| 万宁市| 云南省| 敖汉旗| 正镶白旗| 灵丘县| 望奎县| 和顺县| 凤山市| 锦州市| 淮南市| 民勤县| 玉山县| 南澳县| 林甸县| 都兰县| 阿克| 本溪市| 瓦房店市| 泽州县| 类乌齐县| 洞口县| 云林县| 武隆县| 昂仁县| 高台县| 广德县| 宿迁市| 安国市| 保亭| 剑阁县| 平远县| 界首市| 安多县| 东莞市| 平昌县| 万山特区| 伊宁县| 永和县| 拉萨市|