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

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

unix.superglobalmegacorp.com