Annotation of linux/kernel/exit.c, revision 1.1.1.4

1.1.1.2   root        1: /*
                      2:  *  linux/kernel/exit.c
                      3:  *
                      4:  *  (C) 1991  Linus Torvalds
                      5:  */
                      6: 
1.1.1.4 ! root        7: #define DEBUG_PROC_TREE
        !             8: 
1.1       root        9: #include <errno.h>
                     10: #include <signal.h>
                     11: #include <sys/wait.h>
                     12: 
                     13: #include <linux/sched.h>
                     14: #include <linux/kernel.h>
                     15: #include <linux/tty.h>
                     16: #include <asm/segment.h>
                     17: 
                     18: int sys_pause(void);
                     19: int sys_close(int fd);
                     20: 
                     21: void release(struct task_struct * p)
                     22: {
                     23:        int i;
                     24: 
                     25:        if (!p)
                     26:                return;
1.1.1.4 ! root       27:        if (p == current) {
        !            28:                printk("task releasing itself\n\r");
        !            29:                return;
        !            30:        }
1.1       root       31:        for (i=1 ; i<NR_TASKS ; i++)
                     32:                if (task[i]==p) {
                     33:                        task[i]=NULL;
1.1.1.4 ! root       34:                        /* Update links */
        !            35:                        if (p->p_osptr)
        !            36:                                p->p_osptr->p_ysptr = p->p_ysptr;
        !            37:                        if (p->p_ysptr)
        !            38:                                p->p_ysptr->p_osptr = p->p_osptr;
        !            39:                        else
        !            40:                                p->p_pptr->p_cptr = p->p_osptr;
1.1       root       41:                        free_page((long)p);
                     42:                        schedule();
                     43:                        return;
                     44:                }
                     45:        panic("trying to release non-existent task");
                     46: }
                     47: 
1.1.1.4 ! root       48: #ifdef DEBUG_PROC_TREE
        !            49: /*
        !            50:  * Check to see if a task_struct pointer is present in the task[] array
        !            51:  * Return 0 if found, and 1 if not found.
        !            52:  */
        !            53: int bad_task_ptr(struct task_struct *p)
        !            54: {
        !            55:        int     i;
        !            56: 
        !            57:        if (!p)
        !            58:                return 0;
        !            59:        for (i=0 ; i<NR_TASKS ; i++)
        !            60:                if (task[i] == p)
        !            61:                        return 0;
        !            62:        return 1;
        !            63: }
        !            64:        
        !            65: /*
        !            66:  * This routine scans the pid tree and make sure the rep invarient still
        !            67:  * holds.  Used for debugging only, since it's very slow....
        !            68:  *
        !            69:  * It looks a lot scarier than it really is.... we're doing ænothing more
        !            70:  * than verifying the doubly-linked list foundæin p_ysptr and p_osptr, 
        !            71:  * and checking it corresponds with the process tree defined by p_cptr and 
        !            72:  * p_pptr;
        !            73:  */
        !            74: void audit_ptree()
        !            75: {
        !            76:        int     i;
        !            77: 
        !            78:        for (i=1 ; i<NR_TASKS ; i++) {
        !            79:                if (!task[i])
        !            80:                        continue;
        !            81:                if (bad_task_ptr(task[i]->p_pptr))
        !            82:                        printk("Warning, pid %d's parent link is bad\n",
        !            83:                                task[i]->pid);
        !            84:                if (bad_task_ptr(task[i]->p_cptr))
        !            85:                        printk("Warning, pid %d's child link is bad\n",
        !            86:                                task[i]->pid);
        !            87:                if (bad_task_ptr(task[i]->p_ysptr))
        !            88:                        printk("Warning, pid %d's ys link is bad\n",
        !            89:                                task[i]->pid);
        !            90:                if (bad_task_ptr(task[i]->p_osptr))
        !            91:                        printk("Warning, pid %d's os link is bad\n",
        !            92:                                task[i]->pid);
        !            93:                if (task[i]->p_pptr == task[i])
        !            94:                        printk("Warning, pid %d parent link points to self\n");
        !            95:                if (task[i]->p_cptr == task[i])
        !            96:                        printk("Warning, pid %d child link points to self\n");
        !            97:                if (task[i]->p_ysptr == task[i])
        !            98:                        printk("Warning, pid %d ys link points to self\n");
        !            99:                if (task[i]->p_osptr == task[i])
        !           100:                        printk("Warning, pid %d os link points to self\n");
        !           101:                if (task[i]->p_osptr) {
        !           102:                        if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
        !           103:                                printk(
        !           104:                        "Warning, pid %d older sibling %d parent is %d\n",
        !           105:                                task[i]->pid, task[i]->p_osptr->pid,
        !           106:                                task[i]->p_osptr->p_pptr->pid);
        !           107:                        if (task[i]->p_osptr->p_ysptr != task[i])
        !           108:                                printk(
        !           109:                "Warning, pid %d older sibling %d has mismatched ys link\n",
        !           110:                                task[i]->pid, task[i]->p_osptr->pid);
        !           111:                }
        !           112:                if (task[i]->p_ysptr) {
        !           113:                        if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
        !           114:                                printk(
        !           115:                        "Warning, pid %d younger sibling %d parent is %d\n",
        !           116:                                task[i]->pid, task[i]->p_osptr->pid,
        !           117:                                task[i]->p_osptr->p_pptr->pid);
        !           118:                        if (task[i]->p_ysptr->p_osptr != task[i])
        !           119:                                printk(
        !           120:                "Warning, pid %d younger sibling %d has mismatched os link\n",
        !           121:                                task[i]->pid, task[i]->p_ysptr->pid);
        !           122:                }
        !           123:                if (task[i]->p_cptr) {
        !           124:                        if (task[i]->p_cptr->p_pptr != task[i])
        !           125:                                printk(
        !           126:                        "Warning, pid %d youngest child %d has mismatched parent link\n",
        !           127:                                task[i]->pid, task[i]->p_cptr->pid);
        !           128:                        if (task[i]->p_cptr->p_ysptr)
        !           129:                                printk(
        !           130:                        "Warning, pid %d youngest child %d has non-NULL ys link\n",
        !           131:                                task[i]->pid, task[i]->p_cptr->pid);
        !           132:                }
        !           133:        }
        !           134: }
        !           135: #endif /* DEBUG_PROC_TREE */
        !           136: 
1.1.1.2   root      137: static inline int send_sig(long sig,struct task_struct * p,int priv)
1.1       root      138: {
1.1.1.4 ! root      139:        if (!p)
1.1.1.2   root      140:                return -EINVAL;
1.1.1.4 ! root      141:        if (!priv && (current->euid!=p->euid) && !suser())
1.1.1.2   root      142:                return -EPERM;
1.1.1.4 ! root      143:        if ((sig == SIGKILL) || (sig == SIGCONT)) {
        !           144:                if (p->state == TASK_STOPPED)
        !           145:                        p->state = TASK_RUNNING;
        !           146:                p->exit_code = 0;
        !           147:                p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
        !           148:                                (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
        !           149:        } 
        !           150:        /* If the signal will be ignored, don't even post it */
        !           151:        if ((int) p->sigaction[sig-1].sa_handler == 1)
        !           152:                return 0;
        !           153:        /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */
        !           154:        if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) 
        !           155:                p->signal &= ~(1<<(SIGCONT-1));
        !           156:        /* Actually deliver the signal */
        !           157:        p->signal |= (1<<(sig-1));
1.1.1.2   root      158:        return 0;
1.1       root      159: }
                    160: 
1.1.1.4 ! root      161: int session_of_pgrp(int pgrp)
1.1.1.2   root      162: {
1.1.1.4 ! root      163:        struct task_struct **p;
        !           164: 
        !           165:        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
        !           166:                if ((*p)->pgrp == pgrp)
        !           167:                        return((*p)->session);
        !           168:        return -1;
        !           169: }
        !           170: 
        !           171: int kill_pg(int pgrp, int sig, int priv)
        !           172: {
        !           173:        struct task_struct **p;
        !           174:        int err,retval = -ESRCH;
        !           175:        int found = 0;
        !           176: 
        !           177:        if (sig<1 || sig>32 || pgrp<=0)
        !           178:                return -EINVAL;
        !           179:        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
        !           180:                if ((*p)->pgrp == pgrp) {
        !           181:                        if (sig && (err = send_sig(sig,*p,priv)))
        !           182:                                retval = err;
        !           183:                        else
        !           184:                                found++;
        !           185:                }
        !           186:        return(found ? 0 : retval);
        !           187: }
        !           188: 
        !           189: int kill_proc(int pid, int sig, int priv)
        !           190: {
        !           191:        struct task_struct **p;
        !           192: 
        !           193:        if (sig<1 || sig>32)
        !           194:                return -EINVAL;
        !           195:        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
        !           196:                if ((*p)->pid == pid)
        !           197:                        return(sig ? send_sig(sig,*p,priv) : 0);
        !           198:        return(-ESRCH);
1.1.1.2   root      199: }
                    200: 
                    201: /*
1.1.1.4 ! root      202:  * POSIX specifies that kill(-1,sig) is unspecified, but what we have
        !           203:  * is probably wrong.  Should make it like BSD or SYSV.
1.1.1.2   root      204:  */
                    205: int sys_kill(int pid,int sig)
1.1       root      206: {
                    207:        struct task_struct **p = NR_TASKS + task;
1.1.1.2   root      208:        int err, retval = 0;
1.1       root      209: 
1.1.1.4 ! root      210:        if (!pid)
        !           211:                return(kill_pg(current->pid,sig,0));
        !           212:        if (pid == -1) {
        !           213:                while (--p > &FIRST_TASK)
1.1.1.2   root      214:                        if (err = send_sig(sig,*p,0))
                    215:                                retval = err;
1.1.1.4 ! root      216:                return(retval);
        !           217:        }
        !           218:        if (pid < 0) 
        !           219:                return(kill_pg(-pid,sig,0));
        !           220:        /* Normal kill */
        !           221:        return(kill_proc(pid,sig,0));
1.1       root      222: }
                    223: 
1.1.1.4 ! root      224: /*
        !           225:  * Determine if a process group is "orphaned", according to the POSIX
        !           226:  * definition in 2.2.2.52.  Orphaned process groups are not to be affected
        !           227:  * by terminal-generated stop signals.  Newly orphaned process groups are 
        !           228:  * to receive a SIGHUP and a SIGCONT.
        !           229:  * 
        !           230:  * "I ask you, have you ever known what it is to be an orphan?"
        !           231:  */
        !           232: int is_orphaned_pgrp(int pgrp)
1.1       root      233: {
1.1.1.4 ! root      234:        struct task_struct **p;
1.1.1.2   root      235: 
1.1.1.4 ! root      236:        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
        !           237:                if (!(*p) ||
        !           238:                    ((*p)->pgrp != pgrp) || 
        !           239:                    ((*p)->state == TASK_ZOMBIE) ||
        !           240:                    ((*p)->p_pptr->pid == 1))
        !           241:                        continue;
        !           242:                if (((*p)->p_pptr->pgrp != pgrp) &&
        !           243:                    ((*p)->p_pptr->session == (*p)->session))
        !           244:                        return 0;
        !           245:        }
        !           246:        return(1);      /* (sighing) "Often!" */
1.1       root      247: }
                    248: 
1.1.1.4 ! root      249: static int has_stopped_jobs(int pgrp)
1.1       root      250: {
1.1.1.4 ! root      251:        struct task_struct ** p;
        !           252: 
        !           253:        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
        !           254:                if ((*p)->pgrp != pgrp)
        !           255:                        continue;
        !           256:                if ((*p)->state == TASK_STOPPED)
        !           257:                        return(1);
        !           258:        }
        !           259:        return(0);
        !           260: }
        !           261: 
        !           262: volatile void do_exit(long code)
        !           263: {
        !           264:        struct task_struct *p;
1.1       root      265:        int i;
                    266: 
                    267:        free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
                    268:        free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
                    269:        for (i=0 ; i<NR_OPEN ; i++)
                    270:                if (current->filp[i])
                    271:                        sys_close(i);
                    272:        iput(current->pwd);
1.1.1.4 ! root      273:        current->pwd = NULL;
1.1       root      274:        iput(current->root);
1.1.1.4 ! root      275:        current->root = NULL;
1.1.1.3   root      276:        iput(current->executable);
1.1.1.4 ! root      277:        current->executable = NULL;
        !           278:        iput(current->library);
        !           279:        current->library = NULL;
1.1.1.2   root      280:        current->state = TASK_ZOMBIE;
                    281:        current->exit_code = code;
1.1.1.4 ! root      282:        /* 
        !           283:         * Check to see if any process groups have become orphaned
        !           284:         * as a result of our exiting, and if they have any stopped
        !           285:         * jobs, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
        !           286:         *
        !           287:         * Case i: Our father is in a different pgrp than we are
        !           288:         * and we were the only connection outside, so our pgrp
        !           289:         * is about to become orphaned.
        !           290:         */
        !           291:        if ((current->p_pptr->pgrp != current->pgrp) &&
        !           292:            (current->p_pptr->session == current->session) &&
        !           293:            is_orphaned_pgrp(current->pgrp) &&
        !           294:            has_stopped_jobs(current->pgrp)) {
        !           295:                kill_pg(current->pgrp,SIGHUP,1);
        !           296:                kill_pg(current->pgrp,SIGCONT,1);
        !           297:        }
        !           298:        /* Let father know we died */
        !           299:        current->p_pptr->signal |= (1<<(SIGCHLD-1));
        !           300:        
        !           301:        /*
        !           302:         * This loop does two things:
        !           303:         * 
        !           304:         * A.  Make init inherit all the child processes
        !           305:         * B.  Check to see if any process groups have become orphaned
        !           306:         *      as a result of our exiting, and if they have any stopped
        !           307:         *      jons, send them a SIGUP and then a SIGCONT.  (POSIX 3.2.2.2)
        !           308:         */
        !           309:        if (p = current->p_cptr) {
        !           310:                while (1) {
        !           311:                        p->p_pptr = task[1];
        !           312:                        if (p->state == TASK_ZOMBIE)
        !           313:                                task[1]->signal |= (1<<(SIGCHLD-1));
        !           314:                        /*
        !           315:                         * process group orphan check
        !           316:                         * Case ii: Our child is in a different pgrp 
        !           317:                         * than we are, and it was the only connection
        !           318:                         * outside, so the child pgrp is now orphaned.
        !           319:                         */
        !           320:                        if ((p->pgrp != current->pgrp) &&
        !           321:                            (p->session == current->session) &&
        !           322:                            is_orphaned_pgrp(p->pgrp) &&
        !           323:                            has_stopped_jobs(p->pgrp)) {
        !           324:                                kill_pg(p->pgrp,SIGHUP,1);
        !           325:                                kill_pg(p->pgrp,SIGCONT,1);
        !           326:                        }
        !           327:                        if (p->p_osptr) {
        !           328:                                p = p->p_osptr;
        !           329:                                continue;
        !           330:                        }
        !           331:                        /*
        !           332:                         * This is it; link everything into init's children 
        !           333:                         * and leave 
        !           334:                         */
        !           335:                        p->p_osptr = task[1]->p_cptr;
        !           336:                        task[1]->p_cptr->p_ysptr = p;
        !           337:                        task[1]->p_cptr = current->p_cptr;
        !           338:                        current->p_cptr = 0;
        !           339:                        break;
        !           340:                }
        !           341:        }
        !           342:        if (current->leader) {
        !           343:                struct task_struct **p;
        !           344:                struct tty_struct *tty;
        !           345: 
        !           346:                if (current->tty >= 0) {
        !           347:                        tty = TTY_TABLE(current->tty);
        !           348:                        if (tty->pgrp>0)
        !           349:                                kill_pg(tty->pgrp, SIGHUP, 1);
        !           350:                        tty->pgrp = 0;
        !           351:                        tty->session = 0;
        !           352:                }
        !           353:                for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
        !           354:                        if ((*p)->session == current->session)
        !           355:                                (*p)->tty = -1;
        !           356:        }
        !           357:        if (last_task_used_math == current)
        !           358:                last_task_used_math = NULL;
        !           359: #ifdef DEBUG_PROC_TREE
        !           360:        audit_ptree();
        !           361: #endif
1.1       root      362:        schedule();
                    363: }
                    364: 
                    365: int sys_exit(int error_code)
                    366: {
1.1.1.4 ! root      367:        do_exit((error_code&0xff)<<8);
1.1       root      368: }
                    369: 
1.1.1.2   root      370: int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
1.1       root      371: {
1.1.1.4 ! root      372:        int flag;
        !           373:        struct task_struct *p;
        !           374:        unsigned long oldblocked;
1.1       root      375: 
                    376:        verify_area(stat_addr,4);
                    377: repeat:
1.1.1.2   root      378:        flag=0;
1.1.1.4 ! root      379:        for (p = current->p_cptr ; p ; p = p->p_osptr) {
1.1.1.2   root      380:                if (pid>0) {
1.1.1.4 ! root      381:                        if (p->pid != pid)
1.1.1.2   root      382:                                continue;
                    383:                } else if (!pid) {
1.1.1.4 ! root      384:                        if (p->pgrp != current->pgrp)
1.1.1.2   root      385:                                continue;
                    386:                } else if (pid != -1) {
1.1.1.4 ! root      387:                        if (p->pgrp != -pid)
1.1.1.2   root      388:                                continue;
                    389:                }
1.1.1.4 ! root      390:                switch (p->state) {
1.1.1.2   root      391:                        case TASK_STOPPED:
1.1.1.4 ! root      392:                                if (!(options & WUNTRACED) || 
        !           393:                                    !p->exit_code)
1.1.1.2   root      394:                                        continue;
1.1.1.4 ! root      395:                                put_fs_long((p->exit_code << 8) | 0x7f,
        !           396:                                        stat_addr);
        !           397:                                p->exit_code = 0;
        !           398:                                return p->pid;
1.1.1.2   root      399:                        case TASK_ZOMBIE:
1.1.1.4 ! root      400:                                current->cutime += p->utime;
        !           401:                                current->cstime += p->stime;
        !           402:                                flag = p->pid;
        !           403:                                put_fs_long(p->exit_code, stat_addr);
        !           404:                                release(p);
        !           405: #ifdef DEBUG_PROC_TREE
        !           406:                                audit_ptree();
        !           407: #endif
1.1.1.2   root      408:                                return flag;
                    409:                        default:
1.1       root      410:                                flag=1;
1.1.1.2   root      411:                                continue;
                    412:                }
                    413:        }
1.1       root      414:        if (flag) {
                    415:                if (options & WNOHANG)
                    416:                        return 0;
1.1.1.2   root      417:                current->state=TASK_INTERRUPTIBLE;
1.1.1.4 ! root      418:                oldblocked = current->blocked;
        !           419:                current->blocked &= ~(1<<(SIGCHLD-1));
1.1.1.2   root      420:                schedule();
1.1.1.4 ! root      421:                current->blocked = oldblocked;
        !           422:                if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
        !           423:                        return -ERESTARTSYS;
1.1       root      424:                else
1.1.1.4 ! root      425:                        goto repeat;
1.1       root      426:        }
                    427:        return -ECHILD;
                    428: }
                    429: 
                    430: 

unix.superglobalmegacorp.com