📄 exit.c
字号:
/* * linux/kernel/exit.c * * (C) 1991 Linus Torvalds */#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)/*释放指定进程在TASK[]中的项,并释放其PCB所占的内存页面,由父进程调用来释放子进程*/{ int i; if (!p) return; for (i=1 ; i<NR_TASKS ; i++) if (task[i]==p) { task[i]=NULL; free_page((long)p); schedule(); return; } panic("trying to release non-existent task");}static inline int send_sig(long sig,struct task_struct * p,int priv)/*向指定任务p发送信号sig,强制发送标志priv*/{ if (!p || sig<1 || sig>32) return -EINVAL; if (priv || (current->euid==p->euid) || suser())/*有强制发送标志,或当前进程的euid即为指定进程的euid,或当前进程是超级用户*/ p->signal |= (1<<(sig-1)); else return -EPERM; return 0;}static void kill_session(void)/*关闭会话*/{ struct task_struct **p = NR_TASKS + task;/*指向TASK数组的末端*/ while (--p > &FIRST_TASK) {/*若进程的会话号session等于当前进程的会话号,则向其发送挂断信号(sighup)*/ if (*p && (*p)->session == current->session) (*p)->signal |= 1<<(SIGHUP-1); }}/* * XXX need to check permissions needed to send signals to process * groups, etc. etc. kill() permissions semantics are tricky! */int sys_kill(int pid,int sig)/*向任何进程发任何信号(p215)*/{ struct task_struct **p = NR_TASKS + task; int err, retval = 0; if (!pid) while (--p > &FIRST_TASK) { if (*p && (*p)->pgrp == current->pid) if (err=send_sig(sig,*p,1)) retval = err; } else if (pid>0) while (--p > &FIRST_TASK) { if (*p && (*p)->pid == pid) if (err=send_sig(sig,*p,0)) retval = err; } else if (pid == -1) while (--p > &FIRST_TASK) if (err = send_sig(sig,*p,0)) retval = err; else while (--p > &FIRST_TASK) if (*p && (*p)->pgrp == -pid) if (err = send_sig(sig,*p,0)) retval = err; return retval;}static void tell_father(int pid)/*通知父进程(向pid发SIGCHLD信号:默认情况下子进程将停止(此时子进程尚未完全释放),若没有找到父进程,则释放自己)*/{ int i; if (pid) for (i=0;i<NR_TASKS;i++) { if (!task[i]) continue; if (task[i]->pid != pid) continue; task[i]->signal |= (1<<(SIGCHLD-1));/*向该进程的父进程发送信号(SIGCHLD),通知其某个子进程已经中止*/ return; }/* if we don't find any fathers, we just release ourselves *//* This is not really OK. Must change it to make father 1 */ printk("BAD BAD - no father found\n\r"); release(current);/*进程释放自己*/}int do_exit(long code)/*关闭进程(将当前进程设置为TASK_ZOMBIE状态,并调度schedule,且不再返回)*/{ 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_TASKS ; i++) if (task[i] && task[i]->father == current->pid) {/*将该进程的所有子进程的父进程设为进程1*/ task[i]->father = 1; if (task[i]->state == TASK_ZOMBIE)/*若某一子进程为TASK_ZOMBIE状态则向进程1发子进程中止信号SIGCHLD*/ /* assumption task[1] is always init */ (void) send_sig(SIGCHLD, task[1], 1); } 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; if (current->leader && current->tty >= 0)/*如果该进程是一个会话头且有控制终端,则释放终端*/ tty_table[current->tty].pgrp = 0; if (last_task_used_math == current)/*若当前进程上次使用过协处理器,则置空*/ last_task_used_math = NULL; if (current->leader)/*关闭会话(若当前进程是leader则中止所有相关进程)*/ kill_session(); current->state = TASK_ZOMBIE;/*设为僵死(内核态进程不接受时钟中断引起的进程调度)*/ current->exit_code = code;/*设退出码*/ tell_father(current->father); schedule();/*进程调度*/ return (-1); /* just to suppress warnings *//*这条语句不会执行*/}int sys_exit(int error_code)/*中止进程*/{ return do_exit((error_code&0xff)<<8);}int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)/*挂起当前进程,直到pid指定的进程退出或收到要求中止该进程,或是需要调用一个信号句柄*/{ int flag, code; struct task_struct ** p; verify_area(stat_addr,4);repeat: flag=0; for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {/*跳过不合条件的*/ if (!*p || *p == current) continue; if ((*p)->father != current->pid) continue; 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:/*若子进程的状态为TASK_STOPPED:若WUNTRACED标志没有置位时则继续扫描其它进程;否则把状态信息0x7f放入*stat_addr中*/ if (!(options & WUNTRACED)) continue; put_fs_long(0x7f,stat_addr); return (*p)->pid; case TASK_ZOMBIE:/*若子进程为僵死状态,则首先将它在用户态和内核态运行的时间分别累计到当前进程(父)中,然后释放该子进程*/ current->cutime += (*p)->utime; current->cstime += (*p)->stime; flag = (*p)->pid; code = (*p)->exit_code; release(*p); put_fs_long(code,stat_addr); return flag; default:/*flag置位,表示找到了符合要求的子进程,但它的状态非TASK_STOPPED或TASK_ZOMBIE*/ flag=1; continue; } } if (flag) { if (options & WNOHANG)/*WNOHANG表示没有子进程处于退出或中止态就立刻返回*/ return 0; current->state=TASK_INTERRUPTIBLE;/*等待的子进程仍在运行中,所以挂起当前进程,继续等待*/ schedule(); if (!(current->signal &= ~(1<<(SIGCHLD-1)))) goto repeat; else return -EINTR; } return -ECHILD;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -