NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; if (in_interrupt()) panic("Aiee, killing interrupt handler!"); if (!tsk->pid) panic("Attempted to kill the idle task!"); if (tsk->pid == 1) panic("Attempted to kill init!"); tsk->flags |= PF_EXITING; del_timer_sync(&tsk->real_timer); fake_volatile: #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif if (current->tux_info) { #ifdef CONFIG_TUX_DEBUG printk("Possibly unexpected TUX-thread exit(%ld) at %p?\n", code, __builtin_return_address(0)); #endif current->tux_exit(); } __exit_mm(tsk); lock_kernel(); sem_exit(); __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); exit_sighand(tsk); exit_thread(); if (current->leader) disassociate_ctty(1); put_exec_domain(tsk->exec_domain); if (tsk->binfmt && tsk->binfmt->module) __MOD_DEC_USE_COUNT(tsk->binfmt->module); tsk->exit_code = code; exit_notify(); schedule(); BUG(); /* * In order to get rid of the "volatile function does return" message * I did this little loop that confuses gcc to think do_exit really * is volatile. In fact it's schedule() that is volatile in some * circumstances: when current->state = ZOMBIE, schedule() never * returns. * * In fact the natural way to do all this is to have the label and the * goto right after each other, but I put the fake_volatile label at * the start of the function just in case something /really/ bad * happens, and the schedule returns. This way we can try again. I'm * not paranoid: it's just that everybody is out to get me. */ goto fake_volatile; }
NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; if (in_interrupt()) printk("Aiee, killing interrupt handler\n"); if (!tsk->pid) panic("Attempted to kill the idle task!"); tsk->flags |= PF_EXITING; start_bh_atomic(); del_timer(&tsk->real_timer); end_bh_atomic(); lock_kernel(); fake_volatile: #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif sem_exit(); __exit_mm(tsk); #if CONFIG_AP1000 exit_msc(tsk); #endif __exit_files(tsk); __exit_fs(tsk); __exit_sighand(tsk); exit_thread(); tsk->state = TASK_ZOMBIE; tsk->exit_code = code; exit_notify(); #ifdef DEBUG_PROC_TREE audit_ptree(); #endif if (tsk->exec_domain && tsk->exec_domain->module) __MOD_DEC_USE_COUNT(tsk->exec_domain->module); if (tsk->binfmt && tsk->binfmt->module) __MOD_DEC_USE_COUNT(tsk->binfmt->module); schedule(); /* * In order to get rid of the "volatile function does return" message * I did this little loop that confuses gcc to think do_exit really * is volatile. In fact it's schedule() that is volatile in some * circumstances: when current->state = ZOMBIE, schedule() never * returns. * * In fact the natural way to do all this is to have the label and the * goto right after each other, but I put the fake_volatile label at * the start of the function just in case something /really/ bad * happens, and the schedule returns. This way we can try again. I'm * not paranoid: it's just that everybody is out to get me. */ goto fake_volatile; }
NORET_TYPE void do_exit(long code) { if (intr_count) { printk("Aiee, killing interrupt handler\n"); intr_count = 0; } fake_volatile: acct_process(code); current->flags |= PF_EXITING; del_timer(¤t->real_timer); sem_exit(); kerneld_exit(); __exit_mm(current); __exit_files(current); __exit_fs(current); __exit_sighand(current); exit_thread(); current->state = TASK_ZOMBIE; current->exit_code = code; exit_notify(); #ifdef DEBUG_PROC_TREE audit_ptree(); #endif if (current->exec_domain && current->exec_domain->use_count) (*current->exec_domain->use_count)--; if (current->binfmt && current->binfmt->use_count) (*current->binfmt->use_count)--; schedule(); /* * In order to get rid of the "volatile function does return" message * I did this little loop that confuses gcc to think do_exit really * is volatile. In fact it's schedule() that is volatile in some * circumstances: when current->state = ZOMBIE, schedule() never * returns. * * In fact the natural way to do all this is to have the label and the * goto right after each other, but I put the fake_volatile label at * the start of the function just in case something /really/ bad * happens, and the schedule returns. This way we can try again. I'm * not paranoid: it's just that everybody is out to get me. */ goto fake_volatile; }
NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; if (in_interrupt()) panic("Aiee, killing interrupt handler!"); if (!tsk->pid) panic("Attempted to kill the idle task!"); if (tsk->pid == 1) panic("Attempted to kill init!"); /* * If do_exit is called because this processes oopsed, it's possible * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before * continuing. Amongst other possible reasons, this is to prevent * mm_release()->clear_child_tid() from writing to a user-controlled * kernel address. */ set_fs(USER_DS); tsk->flags |= PF_EXITING; del_timer_sync(&tsk->real_timer); fake_volatile: #ifdef CONFIG_BSD_PROCESS_ACCT acct_process(code); #endif __exit_mm(tsk); lock_kernel(); sem_exit(); __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); exit_sighand(tsk); exit_thread(); if (current->leader) disassociate_ctty(1); put_exec_domain(tsk->exec_domain); if (tsk->binfmt && tsk->binfmt->module) __MOD_DEC_USE_COUNT(tsk->binfmt->module); tsk->exit_code = code; exit_notify(); schedule(); BUG(); /* * In order to get rid of the "volatile function does return" message * I did this little loop that confuses gcc to think do_exit really * is volatile. In fact it's schedule() that is volatile in some * circumstances: when current->state = ZOMBIE, schedule() never * returns. * * In fact the natural way to do all this is to have the label and the * goto right after each other, but I put the fake_volatile label at * the start of the function just in case something /really/ bad * happens, and the schedule returns. This way we can try again. I'm * not paranoid: it's just that everybody is out to get me. */ goto fake_volatile; }
NORET_TYPE void do_exit(long code) { struct task_struct *p; int i; fake_volatile: if (current->semun) sem_exit(); if (current->shm) shm_exit(); free_page_tables(current); for (i=0 ; i<NR_OPEN ; i++) if (current->filp[i]) sys_close(i); forget_original_parent(current); iput(current->pwd); current->pwd = NULL; iput(current->root); current->root = NULL; iput(current->executable); current->executable = NULL; /* Release all of the old mmap stuff. */ { struct vm_area_struct * mpnt, *mpnt1; mpnt = current->mmap; current->mmap = NULL; while (mpnt) { mpnt1 = mpnt->vm_next; if (mpnt->vm_ops && mpnt->vm_ops->close) mpnt->vm_ops->close(mpnt); kfree(mpnt); mpnt = mpnt1; } } if (current->ldt) { vfree(current->ldt); current->ldt = NULL; for (i=1 ; i<NR_TASKS ; i++) { if (task[i] == current) { set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, &default_ldt, 1); load_ldt(i); } } } current->state = TASK_ZOMBIE; current->exit_code = code; current->rss = 0; /* * Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) * * Case i: Our father is in a different pgrp than we are * and we were the only connection outside, so our pgrp * is about to become orphaned. */ if ((current->p_pptr->pgrp != current->pgrp) && (current->p_pptr->session == current->session) && is_orphaned_pgrp(current->pgrp) && has_stopped_jobs(current->pgrp)) { kill_pg(current->pgrp,SIGHUP,1); kill_pg(current->pgrp,SIGCONT,1); } /* Let father know we died */ /* 通知父进程 */ notify_parent(current); /* * This loop does two things: * * A. Make init inherit all the child processes * B. Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) */ while ((p = current->p_cptr) != NULL) { current->p_cptr = p->p_osptr; p->p_ysptr = NULL; p->flags &= ~(PF_PTRACED|PF_TRACESYS); if (task[1] && task[1] != current) p->p_pptr = task[1]; else p->p_pptr = task[0]; p->p_osptr = p->p_pptr->p_cptr; p->p_osptr->p_ysptr = p; p->p_pptr->p_cptr = p; if (p->state == TASK_ZOMBIE) notify_parent(p); /* * process group orphan check * Case ii: Our child is in a different pgrp * than we are, and it was the only connection * outside, so the child pgrp is now orphaned. */ if ((p->pgrp != current->pgrp) && (p->session == current->session) && is_orphaned_pgrp(p->pgrp) && has_stopped_jobs(p->pgrp)) { kill_pg(p->pgrp,SIGHUP,1); kill_pg(p->pgrp,SIGCONT,1); } } if (current->leader) disassociate_ctty(1); if (last_task_used_math == current) last_task_used_math = NULL; #ifdef DEBUG_PROC_TREE audit_ptree(); #endif schedule(); /* * In order to get rid of the "volatile function does return" message * I did this little loop that confuses gcc to think do_exit really * is volatile. In fact it's schedule() that is volatile in some * circumstances: when current->state = ZOMBIE, schedule() never * returns. * * In fact the natural way to do all this is to have the label and the * goto right after each other, but I put the fake_volatile label at * the start of the function just in case something /really/ bad * happens, and the schedule returns. This way we can try again. I'm * not paranoid: it's just that everybody is out to get me. */ goto fake_volatile; }