- 论坛徽章:
- 4
|
在忽略情况下,一旦一个进程收到一个SIG_CHLD,这个进程就会干掉:
current进程所在的thread_group中, 所有进程的所有子进程里的,exit_signal == SIG_CHLD,并且处于僵尸状态的那部分子进程
以下摘自2.4.32
int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
{
siginfo_t info;
struct k_sigaction *ka;
if ((regs->xcs & 3) != 3)
return 1;
if (!oldset)
oldset = ¤t->blocked;
for (; {
unsigned long signr;
spin_lock_irq(¤t->sigmask_lock);
signr = dequeue_signal(¤t->blocked, &info);
spin_unlock_irq(¤t->sigmask_lock);
if (!signr)
break;
if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
//进程被跟踪,在这里处理,不考虑
}
ka = ¤t->sig->action[signr-1];
/*SIG_IGN 时的处理, 这里是关键*/
if (ka->sa.sa_handler == SIG_IGN) {
/*SIGCHLD以外的信号忽略,但是SIGCHLD不忽略,执行这里*/
if (signr != SIGCHLD)
continue;
while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
;
continue;
}
/*默认的信号处理函数*/
if (ka->sa.sa_handler == SIG_DFL) {
int exit_code = signr;
if (current->pid == 1)
continue;
/* 这里执行默认的信号处理函数*/
}
__asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7]));
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs);
return 1;
}
/* Did we come from a system call? */
if (regs->orig_eax >= 0) {
/* Restart the system call - no handlers present */
if (regs->eax == -ERESTARTNOHAND ||
regs->eax == -ERESTARTSYS ||
regs->eax == -ERESTARTNOINTR) {
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
}
return 0;
}
这个就是对SIGCHLD的处理
while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
;
反复执行sys_wait4(-1, NULL, WNOHANG, NULL) ,直到返回<=0
asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
{
int flag, retval;
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
add_wait_queue(¤t->wait_chldexit,&wait);
/* 以上语句都不用考虑*/
repeat:
flag = 0;
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
tsk = current;
do {
struct task_struct *p;
for (p = tsk->p_cptr ; p ; p = p->p_osptr) {
/* 这里省略了一部分指令,以参数pid = -1, option = WNOHANG
* 来执行这里的语句时,效果就是
*
* 过滤掉所有exit_signal != SIG_CHLD的,进程task的子进程
*
* 进程task的所有exit_signal == SIG_CHLD的子进程进入下边的
* flag = 1;
* switch (p->state) {
*
*/
flag = 1;
switch (p->state) {
case TASK_STOPPED:
/* 对被跟踪进程的处理,我们不考虑*/
goto end_wait4;
case TASK_ZOMBIE:
read_unlock(&tasklist_lock);
retval = p->pid;
/* 对exit_signal == SIG_CHLD的子进程的处理*/
if (p->p_opptr != p->p_pptr) {
/*进程task的继子进程归还给继子进程的原始父进程,
*并向原始父进程发送SIG_CHLD*/
} else
release_task(p);
/*回收僵尸进程的task_struct*/
goto end_wait4;
default:
continue;
}
}
/* 以下3句指令
*
* 因为参数中没有设置__WNOTHREAD,所以会循环扫描整个thread_group中的
* 所有进程的所有子进程,当然,子进程必须exit_signal == SIG_CHLD
*/
if (options & __WNOTHREAD)
break;
tsk = next_thread(tsk);
} while (tsk != current);
read_unlock(&tasklist_lock);
/* 一旦执行这个if语句,证明当前进程所在的thread_group中,所有进程的所有子进程
*(子进程还要满足 exit_signal == SIG_CHLD)只有就绪,可中断,不可中断三种状态
*
* 而没有僵尸,或者被跟踪而停止的子进程
*
* 这样会返回0
*/
if (flag) {
retval = 0;
if (options & WNOHANG)
goto end_wait4;
/*以下省略一些指令,因为根本不会执行,参数中option == WNOHANG*/
}
/* thread_group中,所有进程都没有exit_signal == SIG_CHLD的子进程,才会执行
* retval = -ECHILD,返回负值
*/
retval = -ECHILD;
/* 三种情况会到达这里
*
* 1) 处理了一个僵尸进程,retval = 僵尸进程的pid
*
* 2) thread_group组中所有进程的子进程们,虽然有的exit_signal == SIG_CHLD,
* 但是没有僵尸进程,retval = 0
*
* 3) thread_group组中进程的子进程们,没有任何一个exit_signal == SIG_CHLD,
* 这时retval = -ECHILD,负值
*/end_wait4:
current->state = TASK_RUNNING;
remove_wait_queue(¤t->wait_chldexit,&wait);
return retval;
}
[ 本帖最后由 塑料袋 于 2006-9-19 23:27 编辑 ] |
|