linux-exit.c

/*
*  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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值