/* * linux/kernel/exit.c * //--任務終止和退出的有關處理事宜,包括釋放,會話,終止和程式退出處理函數以及殺死進程 * (C) 1991 Linus Torvalds */#define DEBUG_PROC_TREE#include <errno.h>#include <signal.h>#include <sys/wait.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/tty.h>#include <asm/segment.h>int sys_pause(void);int sys_close(int fd);void release(struct task_struct * p) //--根據進程的任務資料結構指標,{ //--在任務數組中刪除指定的進程指標,釋放相關記憶體頁 int i; //--並立刻讓核心重新調度任務的運行。 if (!p) return; if (p == current) { printk("task releasing itself/n/r"); return; } for (i=1 ; i<NR_TASKS ; i++) if (task[i]==p) { task[i]=NULL; /* Update links */ if (p->p_osptr) p->p_osptr->p_ysptr = p->p_ysptr; if (p->p_ysptr) p->p_ysptr->p_osptr = p->p_osptr; else p->p_pptr->p_cptr = p->p_osptr; free_page((long)p); //--釋放記憶體頁 schedule(); //--重新調度任務 return; } panic("trying to release non-existent task");}#ifdef DEBUG_PROC_TREE/* * Check to see if a task_struct pointer is present in the task[] array * Return 0 if found, and 1 if not found. */int bad_task_ptr(struct task_struct *p) //--檢查任務結構指標p{ int i; if (!p) return 0; for (i=0 ; i<NR_TASKS ; i++) if (task[i] == p) return 0; return 1;} /* * This routine scans the pid tree and make sure the rep invarient still * holds. Used for debugging only, since it's very slow.... * * It looks a lot scarier than it really is.... we're doing **nothing more * than verifying the doubly-linked list found**in p_ysptr and p_osptr, * and checking it corresponds with the process tree defined by p_cptr and * p_pptr; */void audit_ptree() //--檢查進程樹,僅用於調試{ int i; for (i=1 ; i<NR_TASKS ; i++) { if (!task[i]) continue; if (bad_task_ptr(task[i]->p_pptr)) printk("Warning, pid %d's parent link is bad/n", task[i]->pid); if (bad_task_ptr(task[i]->p_cptr)) printk("Warning, pid %d's child link is bad/n", task[i]->pid); if (bad_task_ptr(task[i]->p_ysptr)) printk("Warning, pid %d's ys link is bad/n", task[i]->pid); if (bad_task_ptr(task[i]->p_osptr)) printk("Warning, pid %d's os link is bad/n", task[i]->pid); if (task[i]->p_pptr == task[i]) printk("Warning, pid %d parent link points to self/n"); if (task[i]->p_cptr == task[i]) printk("Warning, pid %d child link points to self/n"); if (task[i]->p_ysptr == task[i]) printk("Warning, pid %d ys link points to self/n"); if (task[i]->p_osptr == task[i]) printk("Warning, pid %d os link points to self/n"); if (task[i]->p_osptr) { if (task[i]->p_pptr != task[i]->p_osptr->p_pptr) printk( "Warning, pid %d older sibling %d parent is %d/n", task[i]->pid, task[i]->p_osptr->pid, task[i]->p_osptr->p_pptr->pid); if (task[i]->p_osptr->p_ysptr != task[i]) printk( "Warning, pid %d older sibling %d has mismatched ys link/n", task[i]->pid, task[i]->p_osptr->pid); } if (task[i]->p_ysptr) { if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr) printk( "Warning, pid %d younger sibling %d parent is %d/n", task[i]->pid, task[i]->p_osptr->pid, task[i]->p_osptr->p_pptr->pid); if (task[i]->p_ysptr->p_osptr != task[i]) printk( "Warning, pid %d younger sibling %d has mismatched os link/n", task[i]->pid, task[i]->p_ysptr->pid); } if (task[i]->p_cptr) { if (task[i]->p_cptr->p_pptr != task[i]) printk( "Warning, pid %d youngest child %d has mismatched parent link/n", task[i]->pid, task[i]->p_cptr->pid); if (task[i]->p_cptr->p_ysptr) printk( "Warning, pid %d youngest child %d has non-NULL ys link/n", task[i]->pid, task[i]->p_cptr->pid); } }}#endif /* DEBUG_PROC_TREE */static inline int send_sig(long sig,struct task_struct * p,int priv){ //--向指定任務發送訊號sig,許可權為priv if (!p) return -EINVAL; if (!priv && (current->euid!=p->euid) && !suser()) //--檢查許可權,是否是目前使用者,是否是超級使用者 return -EPERM; if ((sig == SIGKILL) || (sig == SIGCONT)) { //--如果是sigkill和sigcout訊號,則... if (p->state == TASK_STOPPED) p->state = TASK_RUNNING; p->exit_code = 0; p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); //--去掉可能會導致進程停止的訊號 } /* If the signal will be ignored, don't even post it */ if ((int) p->sigaction[sig-1].sa_handler == 1) //--如果訊號將被進程p忽略,則不用發送。 return 0; /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */ if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) p->signal &= ~(1<<(SIGCONT-1)); /* Actually deliver the signal */ p->signal |= (1<<(sig-1)); //--向p發送訊號 return 0;}int session_of_pgrp(int pgrp) //--根據進程組號pgrp取得進程組所屬的會話號{ struct task_struct **p; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) if ((*p)->pgrp == pgrp) return((*p)->session); return -1;}int kill_pg(int pgrp, int sig, int priv) //--向進程組發送訊號{ struct task_struct **p; int err,retval = -ESRCH; int found = 0; if (sig<1 || sig>32 || pgrp<=0) return -EINVAL; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) if ((*p)->pgrp == pgrp) { if (sig && (err = send_sig(sig,*p,priv))) retval = err; else found++; } return(found ? 0 : retval);}int kill_proc(int pid, int sig, int priv) //--向進程發送訊號{ struct task_struct **p; if (sig<1 || sig>32) return -EINVAL; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) if ((*p)->pid == pid) return(sig ? send_sig(sig,*p,priv) : 0); return(-ESRCH);}/* * POSIX specifies that kill(-1,sig) is unspecified, but what we have * is probably wrong. Should make it like BSD or SYSV. */int sys_kill(int pid,int sig) //--用於向任何進程或進程組發送任何訊號{ struct task_struct **p = NR_TASKS + task; int err, retval = 0; if (!pid) //--訊號發送給當前進程的進程組中所有的進程 return(kill_pg(current->pid,sig,0)); if (pid == -1) { //--訊號發送給除初始進程外的所有進程 while (--p > &FIRST_TASK) if (err = send_sig(sig,*p,0)) retval = err; return(retval); } if (pid < 0) //--訊號發送給進程組-pid的所有進程 return(kill_pg(-pid,sig,0)); /* Normal kill */ return(kill_proc(pid,sig,0)); //--訊號發送給指定進程}/* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected * by terminal-generated stop signals. Newly orphaned process groups are * to receive a SIGHUP and a SIGCONT. * * "I ask you, have you ever known what it is to be an orphan?" */int is_orphaned_pgrp(int pgrp) //--判斷一個進程是否是孤兒進程{ //--如果...如果...否則...我也看不懂什麼是孤兒進程了 struct task_struct **p; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if (!(*p) || ((*p)->pgrp != pgrp) || ((*p)->state == TASK_ZOMBIE) || ((*p)->p_pptr->pid == 1)) continue; if (((*p)->p_pptr->pgrp != pgrp) && ((*p)->p_pptr->session == (*p)->session)) return 0; } return(1); /* (sighing) "Often!" */ //--為孤兒進程...}static int has_stopped_jobs(int pgrp) //--判斷進程組中是否有處於停止狀態的作業{ struct task_struct ** p; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if ((*p)->pgrp != pgrp) continue; if ((*p)->state == TASK_STOPPED) return(1); } return(0);}volatile void do_exit(long code) //--程式退出處理函數{ struct task_struct *p; int i; //--首先釋放當前進程程式碼片段和資料區段所佔的記憶體 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); for (i=0 ; i<NR_OPEN ; i++) //--關閉當前進程開啟著的所有檔案 if (current->filp[i]) sys_close(i); iput(current->pwd); //--目前的目錄 current->pwd = NULL; iput(current->root); //--根目錄 current->root = NULL; iput(current->executable); //--執行檔案 current->executable = NULL; iput(current->library); //--庫檔案 current->library = NULL; current->state = TASK_ZOMBIE; //--僵死狀態 current->exit_code = code; /* * 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 */ current->p_pptr->signal |= (1<<(SIGCHLD-1)); //--發送訊號通知父進程當前進程將終止 /* * 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 * jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) */ if (p = current->p_cptr) { //--讓init進程成為其所有子進程的父進程 while (1) { p->p_pptr = task[1]; if (p->state == TASK_ZOMBIE) //--若為僵死狀態,則向init發送進程已終止訊號 task[1]->signal |= (1<<(SIGCHLD-1)); /* * 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 (p->p_osptr) { p = p->p_osptr; continue; } /* * This is it; link everything into init's children * and leave */ p->p_osptr = task[1]->p_cptr; //--最老與最新子進程的處理 task[1]->p_cptr->p_ysptr = p; task[1]->p_cptr = current->p_cptr; current->p_cptr = 0; break; } } if (current->leader) { //--如果當前進程為會話頭領進程 struct task_struct **p; struct tty_struct *tty; if (current->tty >= 0) { tty = TTY_TABLE(current->tty); if (tty->pgrp>0) kill_pg(tty->pgrp, SIGHUP, 1); tty->pgrp = 0; tty->session = 0; } for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) if ((*p)->session == current->session) (*p)->tty = -1; } if (last_task_used_math == current) //--如果當前進程上次使用國副處理器,則... last_task_used_math = NULL;#ifdef DEBUG_PROC_TREE audit_ptree(); //--調用進程樹檢測顯示函數#endif schedule(); //--重新調度}int sys_exit(int error_code) //--終止進程{ do_exit((error_code&0xff)<<8);}int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options){ //--系統調用,掛起當前進程,直到pid指定的子進程退出 int flag; struct task_struct *p; unsigned long oldblocked; verify_area(stat_addr,4); //--檢測記憶體空間是否足夠repeat: flag=0; //--從當前進程的最年輕子進程開始掃描子進程兄弟鏈表 for (p = current->p_cptr ; p ; p = p->p_osptr) { if (pid>0) { if (p->pid != pid) continue; } else if (!pid) { if (p->pgrp != current->pgrp) continue; } else if (pid != -1) { if (p->pgrp != -pid) continue; } switch (p->state) { //--如果...如果...處理... case TASK_STOPPED: if (!(options & WUNTRACED) || !p->exit_code) continue; put_fs_long((p->exit_code << 8) | 0x7f, stat_addr); p->exit_code = 0; return p->pid; case TASK_ZOMBIE: current->cutime += p->utime; current->cstime += p->stime; flag = p->pid; put_fs_long(p->exit_code, stat_addr); release(p);#ifdef DEBUG_PROC_TREE audit_ptree();#endif return flag; default: flag=1; continue; } } if (flag) { if (options & WNOHANG) return 0; current->state=TASK_INTERRUPTIBLE; oldblocked = current->blocked; current->blocked &= ~(1<<(SIGCHLD-1)); schedule(); current->blocked = oldblocked; if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1)))) return -ERESTARTSYS; else goto repeat; } return -ECHILD;}|xGv00|fcc8d4de8197f69fde70263fb4d52380