[BACK]Return to kern_proc.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_proc.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: kern_proc.c,v 1.34 2007/08/04 02:43:54 ckuethe Exp $  */
                      2: /*     $NetBSD: kern_proc.c,v 1.14 1996/02/09 18:59:41 christos Exp $  */
                      3:
                      4: /*
                      5:  * Copyright (c) 1982, 1986, 1989, 1991, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the University nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  *
                     32:  *     @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
                     33:  */
                     34:
                     35: #include <sys/param.h>
                     36: #include <sys/systm.h>
                     37: #include <sys/kernel.h>
                     38: #include <sys/proc.h>
                     39: #include <sys/buf.h>
                     40: #include <sys/acct.h>
                     41: #include <sys/wait.h>
                     42: #include <sys/file.h>
                     43: #include <ufs/ufs/quota.h>
                     44: #include <sys/uio.h>
                     45: #include <sys/malloc.h>
                     46: #include <sys/mbuf.h>
                     47: #include <sys/ioctl.h>
                     48: #include <sys/tty.h>
                     49: #include <sys/signalvar.h>
                     50: #include <sys/pool.h>
                     51:
                     52: #define        UIHASH(uid)     (&uihashtbl[(uid) & uihash])
                     53: LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
                     54: u_long uihash;         /* size of hash table - 1 */
                     55:
                     56: /*
                     57:  * Other process lists
                     58:  */
                     59: struct pidhashhead *pidhashtbl;
                     60: u_long pidhash;
                     61: struct pgrphashhead *pgrphashtbl;
                     62: u_long pgrphash;
                     63: struct proclist allproc;
                     64: struct proclist zombproc;
                     65:
                     66: struct pool proc_pool;
                     67: struct pool process_pool;
                     68: struct pool rusage_pool;
                     69: struct pool ucred_pool;
                     70: struct pool pgrp_pool;
                     71: struct pool session_pool;
                     72: struct pool pcred_pool;
                     73:
                     74: static void orphanpg(struct pgrp *);
                     75: #ifdef DEBUG
                     76: void pgrpdump(void);
                     77: #endif
                     78:
                     79: /*
                     80:  * Initialize global process hashing structures.
                     81:  */
                     82: void
                     83: procinit(void)
                     84: {
                     85:        LIST_INIT(&allproc);
                     86:        LIST_INIT(&zombproc);
                     87:
                     88:
                     89:        pidhashtbl = hashinit(maxproc / 4, M_PROC, M_NOWAIT, &pidhash);
                     90:        pgrphashtbl = hashinit(maxproc / 4, M_PROC, M_NOWAIT, &pgrphash);
                     91:        uihashtbl = hashinit(maxproc / 16, M_PROC, M_NOWAIT, &uihash);
                     92:        if (!pidhashtbl || !pgrphashtbl || !uihashtbl)
                     93:                panic("procinit: malloc");
                     94:
                     95:        pool_init(&proc_pool, sizeof(struct proc), 0, 0, 0, "procpl",
                     96:            &pool_allocator_nointr);
                     97:        pool_init(&process_pool, sizeof(struct process), 0, 0, 0, "processpl",
                     98:            &pool_allocator_nointr);
                     99:        pool_init(&rusage_pool, sizeof(struct rusage), 0, 0, 0, "zombiepl",
                    100:            &pool_allocator_nointr);
                    101:        pool_init(&ucred_pool, sizeof(struct ucred), 0, 0, 0, "ucredpl",
                    102:            &pool_allocator_nointr);
                    103:        pool_init(&pgrp_pool, sizeof(struct pgrp), 0, 0, 0, "pgrppl",
                    104:            &pool_allocator_nointr);
                    105:        pool_init(&session_pool, sizeof(struct session), 0, 0, 0, "sessionpl",
                    106:            &pool_allocator_nointr);
                    107:        pool_init(&pcred_pool, sizeof(struct pcred), 0, 0, 0, "pcredpl",
                    108:            &pool_allocator_nointr);
                    109: }
                    110:
                    111: /*
                    112:  * Change the count associated with number of processes
                    113:  * a given user is using.
                    114:  */
                    115: struct uidinfo *
                    116: uid_find(uid_t uid)
                    117: {
                    118:        struct uidinfo *uip, *nuip;
                    119:        struct uihashhead *uipp;
                    120:
                    121:        uipp = UIHASH(uid);
                    122:        LIST_FOREACH(uip, uipp, ui_hash)
                    123:                if (uip->ui_uid == uid)
                    124:                        break;
                    125:        if (uip)
                    126:                return (uip);
                    127:        MALLOC(nuip, struct uidinfo *, sizeof(*nuip), M_PROC, M_WAITOK);
                    128:        /* may have slept, have to check again */
                    129:        LIST_FOREACH(uip, uipp, ui_hash)
                    130:                if (uip->ui_uid == uid)
                    131:                        break;
                    132:        if (uip) {
                    133:                free(nuip, M_PROC);
                    134:                return (uip);
                    135:        }
                    136:        bzero(nuip, sizeof(*nuip));
                    137:        nuip->ui_uid = uid;
                    138:        LIST_INSERT_HEAD(uipp, nuip, ui_hash);
                    139:
                    140:        return (nuip);
                    141: }
                    142:
                    143: int
                    144: chgproccnt(uid_t uid, int diff)
                    145: {
                    146:        struct uidinfo *uip;
                    147:
                    148:        uip = uid_find(uid);
                    149:        uip->ui_proccnt += diff;
                    150:        if (uip->ui_proccnt < 0)
                    151:                panic("chgproccnt: procs < 0");
                    152:        return (uip->ui_proccnt);
                    153: }
                    154:
                    155: /*
                    156:  * Is p an inferior of the current process?
                    157:  */
                    158: int
                    159: inferior(struct proc *p)
                    160: {
                    161:
                    162:        for (; p != curproc; p = p->p_pptr)
                    163:                if (p->p_pid == 0)
                    164:                        return (0);
                    165:        return (1);
                    166: }
                    167:
                    168: /*
                    169:  * Locate a process by number
                    170:  */
                    171: struct proc *
                    172: pfind(pid_t pid)
                    173: {
                    174:        struct proc *p;
                    175:
                    176:        LIST_FOREACH(p, PIDHASH(pid), p_hash)
                    177:                if (p->p_pid == pid)
                    178:                        return (p);
                    179:        return (NULL);
                    180: }
                    181:
                    182: /*
                    183:  * Locate a process group by number
                    184:  */
                    185: struct pgrp *
                    186: pgfind(pid_t pgid)
                    187: {
                    188:        struct pgrp *pgrp;
                    189:
                    190:        LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash)
                    191:                if (pgrp->pg_id == pgid)
                    192:                        return (pgrp);
                    193:        return (NULL);
                    194: }
                    195:
                    196: /*
                    197:  * Move p to a new or existing process group (and session)
                    198:  */
                    199: int
                    200: enterpgrp(struct proc *p, pid_t pgid, int mksess)
                    201: {
                    202:        struct pgrp *pgrp = pgfind(pgid);
                    203:
                    204: #ifdef DIAGNOSTIC
                    205:        if (pgrp != NULL && mksess)     /* firewalls */
                    206:                panic("enterpgrp: setsid into non-empty pgrp");
                    207:        if (SESS_LEADER(p))
                    208:                panic("enterpgrp: session leader attempted setpgrp");
                    209: #endif
                    210:        if (pgrp == NULL) {
                    211:                pid_t savepid = p->p_pid;
                    212:                struct proc *np;
                    213:                /*
                    214:                 * new process group
                    215:                 */
                    216: #ifdef DIAGNOSTIC
                    217:                if (p->p_pid != pgid)
                    218:                        panic("enterpgrp: new pgrp and pid != pgid");
                    219: #endif
                    220:                if ((np = pfind(savepid)) == NULL || np != p)
                    221:                        return (ESRCH);
                    222:                pgrp = pool_get(&pgrp_pool, PR_WAITOK);
                    223:                if (mksess) {
                    224:                        struct session *sess;
                    225:
                    226:                        /*
                    227:                         * new session
                    228:                         */
                    229:                        sess = pool_get(&session_pool, PR_WAITOK);
                    230:                        sess->s_leader = p;
                    231:                        sess->s_count = 1;
                    232:                        sess->s_ttyvp = NULL;
                    233:                        sess->s_ttyp = NULL;
                    234:                        bcopy(p->p_session->s_login, sess->s_login,
                    235:                            sizeof(sess->s_login));
                    236:                        atomic_clearbits_int(&p->p_flag, P_CONTROLT);
                    237:                        pgrp->pg_session = sess;
                    238: #ifdef DIAGNOSTIC
                    239:                        if (p != curproc)
                    240:                                panic("enterpgrp: mksession and p != curproc");
                    241: #endif
                    242:                } else {
                    243:                        pgrp->pg_session = p->p_session;
                    244:                        pgrp->pg_session->s_count++;
                    245:                }
                    246:                pgrp->pg_id = pgid;
                    247:                LIST_INIT(&pgrp->pg_members);
                    248:                LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
                    249:                pgrp->pg_jobc = 0;
                    250:        } else if (pgrp == p->p_pgrp)
                    251:                return (0);
                    252:
                    253:        /*
                    254:         * Adjust eligibility of affected pgrps to participate in job control.
                    255:         * Increment eligibility counts before decrementing, otherwise we
                    256:         * could reach 0 spuriously during the first call.
                    257:         */
                    258:        fixjobc(p, pgrp, 1);
                    259:        fixjobc(p, p->p_pgrp, 0);
                    260:
                    261:        LIST_REMOVE(p, p_pglist);
                    262:        if (LIST_EMPTY(&p->p_pgrp->pg_members))
                    263:                pgdelete(p->p_pgrp);
                    264:        p->p_pgrp = pgrp;
                    265:        LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
                    266:        return (0);
                    267: }
                    268:
                    269: /*
                    270:  * remove process from process group
                    271:  */
                    272: int
                    273: leavepgrp(struct proc *p)
                    274: {
                    275:
                    276:        LIST_REMOVE(p, p_pglist);
                    277:        if (LIST_EMPTY(&p->p_pgrp->pg_members))
                    278:                pgdelete(p->p_pgrp);
                    279:        p->p_pgrp = 0;
                    280:        return (0);
                    281: }
                    282:
                    283: /*
                    284:  * delete a process group
                    285:  */
                    286: void
                    287: pgdelete(struct pgrp *pgrp)
                    288: {
                    289:
                    290:        if (pgrp->pg_session->s_ttyp != NULL &&
                    291:            pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
                    292:                pgrp->pg_session->s_ttyp->t_pgrp = NULL;
                    293:        LIST_REMOVE(pgrp, pg_hash);
                    294:        SESSRELE(pgrp->pg_session);
                    295:        pool_put(&pgrp_pool, pgrp);
                    296: }
                    297:
                    298: /*
                    299:  * Adjust pgrp jobc counters when specified process changes process group.
                    300:  * We count the number of processes in each process group that "qualify"
                    301:  * the group for terminal job control (those with a parent in a different
                    302:  * process group of the same session).  If that count reaches zero, the
                    303:  * process group becomes orphaned.  Check both the specified process'
                    304:  * process group and that of its children.
                    305:  * entering == 0 => p is leaving specified group.
                    306:  * entering == 1 => p is entering specified group.
                    307:  */
                    308: void
                    309: fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
                    310: {
                    311:        struct pgrp *hispgrp;
                    312:        struct session *mysession = pgrp->pg_session;
                    313:
                    314:        /*
                    315:         * Check p's parent to see whether p qualifies its own process
                    316:         * group; if so, adjust count for p's process group.
                    317:         */
                    318:        if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
                    319:            hispgrp->pg_session == mysession) {
                    320:                if (entering)
                    321:                        pgrp->pg_jobc++;
                    322:                else if (--pgrp->pg_jobc == 0)
                    323:                        orphanpg(pgrp);
                    324:        }
                    325:
                    326:        /*
                    327:         * Check this process' children to see whether they qualify
                    328:         * their process groups; if so, adjust counts for children's
                    329:         * process groups.
                    330:         */
                    331:        LIST_FOREACH(p, &p->p_children, p_sibling)
                    332:                if ((hispgrp = p->p_pgrp) != pgrp &&
                    333:                    hispgrp->pg_session == mysession &&
                    334:                    P_ZOMBIE(p) == 0) {
                    335:                        if (entering)
                    336:                                hispgrp->pg_jobc++;
                    337:                        else if (--hispgrp->pg_jobc == 0)
                    338:                                orphanpg(hispgrp);
                    339:                }
                    340: }
                    341:
                    342: /*
                    343:  * A process group has become orphaned;
                    344:  * if there are any stopped processes in the group,
                    345:  * hang-up all process in that group.
                    346:  */
                    347: static void
                    348: orphanpg(struct pgrp *pg)
                    349: {
                    350:        struct proc *p;
                    351:
                    352:        LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                    353:                if (p->p_stat == SSTOP) {
                    354:                        LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                    355:                                psignal(p, SIGHUP);
                    356:                                psignal(p, SIGCONT);
                    357:                        }
                    358:                        return;
                    359:                }
                    360:        }
                    361: }
                    362:
                    363: #ifdef DDB
                    364: void
                    365: proc_printit(struct proc *p, const char *modif, int (*pr)(const char *, ...))
                    366: {
                    367:        static const char *const pstat[] = {
                    368:                "idle", "run", "sleep", "stop", "zombie", "dead", "onproc"
                    369:        };
                    370:        char pstbuf[5];
                    371:        const char *pst = pstbuf;
                    372:
                    373:        if (p->p_stat < 1 || p->p_stat > sizeof(pstat) / sizeof(pstat[0]))
                    374:                snprintf(pstbuf, sizeof(pstbuf), "%d", p->p_stat);
                    375:        else
                    376:                pst = pstat[(int)p->p_stat - 1];
                    377:
                    378:        (*pr)("PROC (%s) pid=%d stat=%s flags=%b\n",
                    379:            p->p_comm, p->p_pid, pst, p->p_flag, P_BITS);
                    380:        (*pr)("    pri=%u, usrpri=%u, nice=%d\n",
                    381:            p->p_priority, p->p_usrpri, p->p_nice);
                    382:        (*pr)("    forw=%p, back=%p, list=%p,%p\n",
                    383:            p->p_forw, p->p_back, p->p_list.le_next, p->p_list.le_prev);
                    384:        (*pr)("    user=%p, vmspace=%p\n",
                    385:            p->p_addr, p->p_vmspace);
                    386:        (*pr)("    estcpu=%u, cpticks=%d, pctcpu=%u.%u%, swtime=%u\n",
                    387:            p->p_estcpu, p->p_cpticks, p->p_pctcpu / 100, p->p_pctcpu % 100,
                    388:            p->p_swtime);
                    389:        (*pr)("    user=%llu, sys=%llu, intr=%llu\n",
                    390:            p->p_uticks, p->p_sticks, p->p_iticks);
                    391: }
                    392: #include <machine/db_machdep.h>
                    393:
                    394: #include <ddb/db_interface.h>
                    395: #include <ddb/db_output.h>
                    396:
                    397: void
                    398: db_show_all_procs(db_expr_t addr, int haddr, db_expr_t count, char *modif)
                    399: {
                    400:        char *mode;
                    401:        int doingzomb = 0;
                    402:        struct proc *p, *pp;
                    403:
                    404:        if (modif[0] == 0)
                    405:                modif[0] = 'n';                 /* default == normal mode */
                    406:
                    407:        mode = "mawn";
                    408:        while (*mode && *mode != modif[0])
                    409:                mode++;
                    410:        if (*mode == 0 || *mode == 'm') {
                    411:                db_printf("usage: show all procs [/a] [/n] [/w]\n");
                    412:                db_printf("\t/a == show process address info\n");
                    413:                db_printf("\t/n == show normal process info [default]\n");
                    414:                db_printf("\t/w == show process wait/emul info\n");
                    415:                return;
                    416:        }
                    417:
                    418:        p = LIST_FIRST(&allproc);
                    419:
                    420:        switch (*mode) {
                    421:
                    422:        case 'a':
                    423:                db_printf("   PID  %-10s  %18s  %18s  %18s\n",
                    424:                    "COMMAND", "STRUCT PROC *", "UAREA *", "VMSPACE/VM_MAP");
                    425:                break;
                    426:        case 'n':
                    427:                db_printf("   PID  %5s  %5s  %5s  S  %10s  %-12s  %-16s\n",
                    428:                    "PPID", "PGRP", "UID", "FLAGS", "WAIT", "COMMAND");
                    429:                break;
                    430:        case 'w':
                    431:                db_printf("   PID  %-16s  %-8s  %18s  %s\n",
                    432:                    "COMMAND", "EMUL", "WAIT-CHANNEL", "WAIT-MSG");
                    433:                break;
                    434:        }
                    435:
                    436:        while (p != 0) {
                    437:                pp = p->p_pptr;
                    438:                if (p->p_stat) {
                    439:
                    440:                        db_printf("%c%5d  ", p == curproc ? '*' : ' ',
                    441:                                p->p_pid);
                    442:
                    443:                        switch (*mode) {
                    444:
                    445:                        case 'a':
                    446:                                db_printf("%-10.10s  %18p  %18p  %18p\n",
                    447:                                    p->p_comm, p, p->p_addr, p->p_vmspace);
                    448:                                break;
                    449:
                    450:                        case 'n':
                    451:                                db_printf("%5d  %5d  %5d  %d  %#10x  "
                    452:                                    "%-12.12s  %-16s\n",
                    453:                                    pp ? pp->p_pid : -1, p->p_pgrp->pg_id,
                    454:                                    p->p_cred->p_ruid, p->p_stat, p->p_flag,
                    455:                                    (p->p_wchan && p->p_wmesg) ?
                    456:                                        p->p_wmesg : "", p->p_comm);
                    457:                                break;
                    458:
                    459:                        case 'w':
                    460:                                db_printf("%-16s  %-8s  %18p  %s\n", p->p_comm,
                    461:                                    p->p_emul->e_name, p->p_wchan,
                    462:                                    (p->p_wchan && p->p_wmesg) ?
                    463:                                        p->p_wmesg : "");
                    464:                                break;
                    465:
                    466:                        }
                    467:                }
                    468:                p = LIST_NEXT(p, p_list);
                    469:                if (p == 0 && doingzomb == 0) {
                    470:                        doingzomb = 1;
                    471:                        p = LIST_FIRST(&zombproc);
                    472:                }
                    473:        }
                    474: }
                    475: #endif
                    476:
                    477: #ifdef DEBUG
                    478: void
                    479: pgrpdump(void)
                    480: {
                    481:        struct pgrp *pgrp;
                    482:        struct proc *p;
                    483:        int i;
                    484:
                    485:        for (i = 0; i <= pgrphash; i++) {
                    486:                if (!LIST_EMPTY(&pgrphashtbl[i])) {
                    487:                        printf("\tindx %d\n", i);
                    488:                        LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) {
                    489:                                printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n",
                    490:                                    pgrp, pgrp->pg_id, pgrp->pg_session,
                    491:                                    pgrp->pg_session->s_count,
                    492:                                    LIST_FIRST(&pgrp->pg_members));
                    493:                                LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
                    494:                                        printf("\t\tpid %d addr %p pgrp %p\n",
                    495:                                            p->p_pid, p, p->p_pgrp);
                    496:                                }
                    497:                        }
                    498:                }
                    499:        }
                    500: }
                    501: #endif /* DEBUG */

CVSweb