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

Annotation of sys/kern/kern_fork.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: kern_fork.c,v 1.92 2007/07/25 23:11:52 art Exp $      */
        !             2: /*     $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1982, 1986, 1989, 1991, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  * (c) UNIX System Laboratories, Inc.
        !             8:  * All or some portions of this file are derived from material licensed
        !             9:  * to the University of California by American Telephone and Telegraph
        !            10:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
        !            11:  * the permission of UNIX System Laboratories, Inc.
        !            12:  *
        !            13:  * Redistribution and use in source and binary forms, with or without
        !            14:  * modification, are permitted provided that the following conditions
        !            15:  * are met:
        !            16:  * 1. Redistributions of source code must retain the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer.
        !            18:  * 2. Redistributions in binary form must reproduce the above copyright
        !            19:  *    notice, this list of conditions and the following disclaimer in the
        !            20:  *    documentation and/or other materials provided with the distribution.
        !            21:  * 3. Neither the name of the University nor the names of its contributors
        !            22:  *    may be used to endorse or promote products derived from this software
        !            23:  *    without specific prior written permission.
        !            24:  *
        !            25:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            28:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            29:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            30:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            31:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            33:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            34:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            35:  * SUCH DAMAGE.
        !            36:  *
        !            37:  *     @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
        !            38:  */
        !            39:
        !            40: #include <sys/param.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/filedesc.h>
        !            43: #include <sys/kernel.h>
        !            44: #include <sys/malloc.h>
        !            45: #include <sys/mount.h>
        !            46: #include <sys/proc.h>
        !            47: #include <sys/exec.h>
        !            48: #include <sys/resourcevar.h>
        !            49: #include <sys/signalvar.h>
        !            50: #include <sys/vnode.h>
        !            51: #include <sys/file.h>
        !            52: #include <sys/acct.h>
        !            53: #include <sys/ktrace.h>
        !            54: #include <sys/sched.h>
        !            55: #include <dev/rndvar.h>
        !            56: #include <sys/pool.h>
        !            57: #include <sys/mman.h>
        !            58: #include <sys/ptrace.h>
        !            59:
        !            60: #include <sys/syscallargs.h>
        !            61:
        !            62: #include "systrace.h"
        !            63: #include <dev/systrace.h>
        !            64:
        !            65: #include <uvm/uvm_extern.h>
        !            66: #include <uvm/uvm_map.h>
        !            67:
        !            68: int    nprocs = 1;             /* process 0 */
        !            69: int    randompid;              /* when set to 1, pid's go random */
        !            70: pid_t  lastpid;
        !            71: struct forkstat forkstat;
        !            72:
        !            73: void fork_return(void *);
        !            74: int pidtaken(pid_t);
        !            75:
        !            76: void process_new(struct proc *, struct proc *);
        !            77:
        !            78: void
        !            79: fork_return(void *arg)
        !            80: {
        !            81:        struct proc *p = (struct proc *)arg;
        !            82:
        !            83:        if (p->p_flag & P_TRACED)
        !            84:                psignal(p, SIGTRAP);
        !            85:
        !            86:        child_return(p);
        !            87: }
        !            88:
        !            89: /*ARGSUSED*/
        !            90: int
        !            91: sys_fork(struct proc *p, void *v, register_t *retval)
        !            92: {
        !            93:        int flags;
        !            94:
        !            95:        flags = FORK_FORK;
        !            96:        if (p->p_ptmask & PTRACE_FORK)
        !            97:                flags |= FORK_PTRACE;
        !            98:        return (fork1(p, SIGCHLD, flags, NULL, 0,
        !            99:            fork_return, NULL, retval, NULL));
        !           100: }
        !           101:
        !           102: /*ARGSUSED*/
        !           103: int
        !           104: sys_vfork(struct proc *p, void *v, register_t *retval)
        !           105: {
        !           106:        return (fork1(p, SIGCHLD, FORK_VFORK|FORK_PPWAIT, NULL, 0, NULL,
        !           107:            NULL, retval, NULL));
        !           108: }
        !           109:
        !           110: int
        !           111: sys_rfork(struct proc *p, void *v, register_t *retval)
        !           112: {
        !           113:        struct sys_rfork_args /* {
        !           114:                syscallarg(int) flags;
        !           115:        } */ *uap = v;
        !           116:
        !           117:        int rforkflags;
        !           118:        int flags;
        !           119:
        !           120:        flags = FORK_RFORK;
        !           121:        rforkflags = SCARG(uap, flags);
        !           122:
        !           123:        if ((rforkflags & RFPROC) == 0)
        !           124:                return (EINVAL);
        !           125:
        !           126:        switch(rforkflags & (RFFDG|RFCFDG)) {
        !           127:        case (RFFDG|RFCFDG):
        !           128:                return EINVAL;
        !           129:        case RFCFDG:
        !           130:                flags |= FORK_CLEANFILES;
        !           131:                break;
        !           132:        case RFFDG:
        !           133:                break;
        !           134:        default:
        !           135:                flags |= FORK_SHAREFILES;
        !           136:                break;
        !           137:        }
        !           138:
        !           139:        if (rforkflags & RFNOWAIT)
        !           140:                flags |= FORK_NOZOMBIE;
        !           141:
        !           142:        if (rforkflags & RFMEM)
        !           143:                flags |= FORK_SHAREVM;
        !           144: #ifdef RTHREADS
        !           145:        if (rforkflags & RFTHREAD)
        !           146:                flags |= FORK_THREAD;
        !           147: #endif
        !           148:
        !           149:        return (fork1(p, SIGCHLD, flags, NULL, 0, NULL, NULL, retval, NULL));
        !           150: }
        !           151:
        !           152: /*
        !           153:  * Allocate and initialize a new process.
        !           154:  */
        !           155: void
        !           156: process_new(struct proc *newproc, struct proc *parent)
        !           157: {
        !           158:        struct process *pr;
        !           159:
        !           160:        pr = pool_get(&process_pool, PR_WAITOK);
        !           161:        pr->ps_mainproc = newproc;
        !           162:        TAILQ_INIT(&pr->ps_threads);
        !           163:        TAILQ_INSERT_TAIL(&pr->ps_threads, newproc, p_thr_link);
        !           164:        newproc->p_p = pr;
        !           165: }
        !           166:
        !           167: /* print the 'table full' message once per 10 seconds */
        !           168: struct timeval fork_tfmrate = { 10, 0 };
        !           169:
        !           170: int
        !           171: fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
        !           172:     void (*func)(void *), void *arg, register_t *retval,
        !           173:     struct proc **rnewprocp)
        !           174: {
        !           175:        struct proc *p2;
        !           176:        uid_t uid;
        !           177:        struct vmspace *vm;
        !           178:        int count;
        !           179:        vaddr_t uaddr;
        !           180:        int s;
        !           181:        extern void endtsleep(void *);
        !           182:        extern void realitexpire(void *);
        !           183:
        !           184:        /*
        !           185:         * Although process entries are dynamically created, we still keep
        !           186:         * a global limit on the maximum number we will create. We reserve
        !           187:         * the last 5 processes to root. The variable nprocs is the current
        !           188:         * number of processes, maxproc is the limit.
        !           189:         */
        !           190:        uid = p1->p_cred->p_ruid;
        !           191:        if ((nprocs >= maxproc - 5 && uid != 0) || nprocs >= maxproc) {
        !           192:                static struct timeval lasttfm;
        !           193:
        !           194:                if (ratecheck(&lasttfm, &fork_tfmrate))
        !           195:                        tablefull("proc");
        !           196:                return (EAGAIN);
        !           197:        }
        !           198:        nprocs++;
        !           199:
        !           200:        /*
        !           201:         * Increment the count of procs running with this uid. Don't allow
        !           202:         * a nonprivileged user to exceed their current limit.
        !           203:         */
        !           204:        count = chgproccnt(uid, 1);
        !           205:        if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) {
        !           206:                (void)chgproccnt(uid, -1);
        !           207:                nprocs--;
        !           208:                return (EAGAIN);
        !           209:        }
        !           210:
        !           211:        uaddr = uvm_km_alloc1(kernel_map, USPACE, USPACE_ALIGN, 1);
        !           212:        if (uaddr == 0) {
        !           213:                chgproccnt(uid, -1);
        !           214:                nprocs--;
        !           215:                return (ENOMEM);
        !           216:        }
        !           217:
        !           218:        /*
        !           219:         * From now on, we're committed to the fork and cannot fail.
        !           220:         */
        !           221:
        !           222:        /* Allocate new proc. */
        !           223:        p2 = pool_get(&proc_pool, PR_WAITOK);
        !           224:
        !           225:        p2->p_stat = SIDL;                      /* protect against others */
        !           226:        p2->p_exitsig = exitsig;
        !           227:        p2->p_forw = p2->p_back = NULL;
        !           228:
        !           229: #ifdef RTHREADS
        !           230:        if (flags & FORK_THREAD) {
        !           231:                atomic_setbits_int(&p2->p_flag, P_THREAD);
        !           232:                p2->p_p = p1->p_p;
        !           233:                TAILQ_INSERT_TAIL(&p2->p_p->ps_threads, p2, p_thr_link);
        !           234:        } else {
        !           235:                process_new(p2, p1);
        !           236:        }
        !           237: #else
        !           238:        process_new(p2, p1);
        !           239: #endif
        !           240:
        !           241:        /*
        !           242:         * Make a proc table entry for the new process.
        !           243:         * Start by zeroing the section of proc that is zero-initialized,
        !           244:         * then copy the section that is copied directly from the parent.
        !           245:         */
        !           246:        bzero(&p2->p_startzero,
        !           247:            (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero));
        !           248:        bcopy(&p1->p_startcopy, &p2->p_startcopy,
        !           249:            (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy));
        !           250:
        !           251:        /*
        !           252:         * Initialize the timeouts.
        !           253:         */
        !           254:        timeout_set(&p2->p_sleep_to, endtsleep, p2);
        !           255:        timeout_set(&p2->p_realit_to, realitexpire, p2);
        !           256:
        !           257:        p2->p_cpu = p1->p_cpu;
        !           258:
        !           259:        /*
        !           260:         * Duplicate sub-structures as needed.
        !           261:         * Increase reference counts on shared objects.
        !           262:         * The p_stats and p_sigacts substructs are set in vm_fork.
        !           263:         */
        !           264:        p2->p_flag = 0;
        !           265:        p2->p_emul = p1->p_emul;
        !           266:        if (p1->p_flag & P_PROFIL)
        !           267:                startprofclock(p2);
        !           268:        atomic_setbits_int(&p2->p_flag, p1->p_flag & (P_SUGID | P_SUGIDEXEC));
        !           269:        if (flags & FORK_PTRACE)
        !           270:                atomic_setbits_int(&p2->p_flag, p1->p_flag & P_TRACED);
        !           271: #ifdef RTHREADS
        !           272:        if (flags & FORK_THREAD) {
        !           273:                /* nothing */
        !           274:        } else
        !           275: #endif
        !           276:        {
        !           277:                p2->p_p->ps_cred = pool_get(&pcred_pool, PR_WAITOK);
        !           278:                bcopy(p1->p_p->ps_cred, p2->p_p->ps_cred, sizeof(*p2->p_p->ps_cred));
        !           279:                p2->p_p->ps_cred->p_refcnt = 1;
        !           280:                crhold(p1->p_ucred);
        !           281:        }
        !           282:
        !           283:        /* bump references to the text vnode (for procfs) */
        !           284:        p2->p_textvp = p1->p_textvp;
        !           285:        if (p2->p_textvp)
        !           286:                VREF(p2->p_textvp);
        !           287:
        !           288:        if (flags & FORK_CLEANFILES)
        !           289:                p2->p_fd = fdinit(p1);
        !           290:        else if (flags & FORK_SHAREFILES)
        !           291:                p2->p_fd = fdshare(p1);
        !           292:        else
        !           293:                p2->p_fd = fdcopy(p1);
        !           294:
        !           295:        /*
        !           296:         * If ps_limit is still copy-on-write, bump refcnt,
        !           297:         * otherwise get a copy that won't be modified.
        !           298:         * (If PL_SHAREMOD is clear, the structure is shared
        !           299:         * copy-on-write.)
        !           300:         */
        !           301: #ifdef RTHREADS
        !           302:        if (flags & FORK_THREAD) {
        !           303:                /* nothing */
        !           304:        } else
        !           305: #endif
        !           306:        {
        !           307:                if (p1->p_p->ps_limit->p_lflags & PL_SHAREMOD)
        !           308:                        p2->p_p->ps_limit = limcopy(p1->p_p->ps_limit);
        !           309:                else {
        !           310:                        p2->p_p->ps_limit = p1->p_p->ps_limit;
        !           311:                        p2->p_p->ps_limit->p_refcnt++;
        !           312:                }
        !           313:        }
        !           314:
        !           315:        if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
        !           316:                atomic_setbits_int(&p2->p_flag, P_CONTROLT);
        !           317:        if (flags & FORK_PPWAIT)
        !           318:                atomic_setbits_int(&p2->p_flag, P_PPWAIT);
        !           319:        p2->p_pptr = p1;
        !           320:        if (flags & FORK_NOZOMBIE)
        !           321:                atomic_setbits_int(&p2->p_flag, P_NOZOMBIE);
        !           322:        LIST_INIT(&p2->p_children);
        !           323:
        !           324: #ifdef KTRACE
        !           325:        /*
        !           326:         * Copy traceflag and tracefile if enabled.
        !           327:         * If not inherited, these were zeroed above.
        !           328:         */
        !           329:        if (p1->p_traceflag & KTRFAC_INHERIT) {
        !           330:                p2->p_traceflag = p1->p_traceflag;
        !           331:                if ((p2->p_tracep = p1->p_tracep) != NULL)
        !           332:                        VREF(p2->p_tracep);
        !           333:        }
        !           334: #endif
        !           335:
        !           336:        /*
        !           337:         * set priority of child to be that of parent
        !           338:         * XXX should move p_estcpu into the region of struct proc which gets
        !           339:         * copied.
        !           340:         */
        !           341:        scheduler_fork_hook(p1, p2);
        !           342:
        !           343:        /*
        !           344:         * Create signal actions for the child process.
        !           345:         */
        !           346:        if (flags & FORK_SIGHAND)
        !           347:                sigactsshare(p1, p2);
        !           348:        else
        !           349:                p2->p_sigacts = sigactsinit(p1);
        !           350:
        !           351:        /*
        !           352:         * If emulation has process fork hook, call it now.
        !           353:         */
        !           354:        if (p2->p_emul->e_proc_fork)
        !           355:                (*p2->p_emul->e_proc_fork)(p2, p1);
        !           356:
        !           357:        p2->p_addr = (struct user *)uaddr;
        !           358:
        !           359:        /*
        !           360:         * Finish creating the child process.  It will return through a
        !           361:         * different path later.
        !           362:         */
        !           363:        uvm_fork(p1, p2, ((flags & FORK_SHAREVM) ? TRUE : FALSE), stack,
        !           364:            stacksize, func ? func : child_return, arg ? arg : p2);
        !           365:
        !           366:        timeout_set(&p2->p_stats->p_virt_to, virttimer_trampoline, p2);
        !           367:        timeout_set(&p2->p_stats->p_prof_to, proftimer_trampoline, p2);
        !           368:
        !           369:        vm = p2->p_vmspace;
        !           370:
        !           371:        if (flags & FORK_FORK) {
        !           372:                forkstat.cntfork++;
        !           373:                forkstat.sizfork += vm->vm_dsize + vm->vm_ssize;
        !           374:        } else if (flags & FORK_VFORK) {
        !           375:                forkstat.cntvfork++;
        !           376:                forkstat.sizvfork += vm->vm_dsize + vm->vm_ssize;
        !           377:        } else if (flags & FORK_RFORK) {
        !           378:                forkstat.cntrfork++;
        !           379:                forkstat.sizrfork += vm->vm_dsize + vm->vm_ssize;
        !           380:        } else {
        !           381:                forkstat.cntkthread++;
        !           382:                forkstat.sizkthread += vm->vm_dsize + vm->vm_ssize;
        !           383:        }
        !           384:
        !           385:        /* Find an unused pid satisfying 1 <= lastpid <= PID_MAX */
        !           386:        do {
        !           387:                lastpid = 1 + (randompid ? arc4random() : lastpid) % PID_MAX;
        !           388:        } while (pidtaken(lastpid));
        !           389:        p2->p_pid = lastpid;
        !           390:
        !           391:        LIST_INSERT_HEAD(&allproc, p2, p_list);
        !           392:        LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
        !           393:        LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling);
        !           394:        LIST_INSERT_AFTER(p1, p2, p_pglist);
        !           395:        if (p2->p_flag & P_TRACED) {
        !           396:                p2->p_oppid = p1->p_pid;
        !           397:                if (p2->p_pptr != p1->p_pptr)
        !           398:                        proc_reparent(p2, p1->p_pptr);
        !           399:
        !           400:                /*
        !           401:                 * Set ptrace status.
        !           402:                 */
        !           403:                if (flags & FORK_FORK) {
        !           404:                        p2->p_ptstat = malloc(sizeof(*p2->p_ptstat),
        !           405:                            M_SUBPROC, M_WAITOK);
        !           406:                        p1->p_ptstat->pe_report_event = PTRACE_FORK;
        !           407:                        p2->p_ptstat->pe_report_event = PTRACE_FORK;
        !           408:                        p1->p_ptstat->pe_other_pid = p2->p_pid;
        !           409:                        p2->p_ptstat->pe_other_pid = p1->p_pid;
        !           410:                }
        !           411:        }
        !           412:
        !           413: #if NSYSTRACE > 0
        !           414:        if (ISSET(p1->p_flag, P_SYSTRACE))
        !           415:                systrace_fork(p1, p2);
        !           416: #endif
        !           417:
        !           418:        /*
        !           419:         * Make child runnable, set start time, and add to run queue.
        !           420:         */
        !           421:        SCHED_LOCK(s);
        !           422:        getmicrotime(&p2->p_stats->p_start);
        !           423:        p2->p_acflag = AFORK;
        !           424:        p2->p_stat = SRUN;
        !           425:        setrunqueue(p2);
        !           426:        SCHED_UNLOCK(s);
        !           427:
        !           428:        /*
        !           429:         * Notify any interested parties about the new process.
        !           430:         */
        !           431:        KNOTE(&p1->p_klist, NOTE_FORK | p2->p_pid);
        !           432:
        !           433:        /*
        !           434:         * Update stats now that we know the fork was successfull.
        !           435:         */
        !           436:        uvmexp.forks++;
        !           437:        if (flags & FORK_PPWAIT)
        !           438:                uvmexp.forks_ppwait++;
        !           439:        if (flags & FORK_SHAREVM)
        !           440:                uvmexp.forks_sharevm++;
        !           441:
        !           442:        /*
        !           443:         * Pass a pointer to the new process to the caller.
        !           444:         */
        !           445:        if (rnewprocp != NULL)
        !           446:                *rnewprocp = p2;
        !           447:
        !           448:        /*
        !           449:         * Preserve synchronization semantics of vfork.  If waiting for
        !           450:         * child to exec or exit, set P_PPWAIT on child, and sleep on our
        !           451:         * proc (in case of exit).
        !           452:         */
        !           453:        if (flags & FORK_PPWAIT)
        !           454:                while (p2->p_flag & P_PPWAIT)
        !           455:                        tsleep(p1, PWAIT, "ppwait", 0);
        !           456:
        !           457:        /*
        !           458:         * If we're tracing the child, alert the parent too.
        !           459:         */
        !           460:        if ((flags & FORK_PTRACE) && (p1->p_flag & P_TRACED))
        !           461:                psignal(p1, SIGTRAP);
        !           462:
        !           463:        /*
        !           464:         * Return child pid to parent process,
        !           465:         * marking us as parent via retval[1].
        !           466:         */
        !           467:        if (retval != NULL) {
        !           468:                retval[0] = p2->p_pid;
        !           469:                retval[1] = 0;
        !           470:        }
        !           471:        return (0);
        !           472: }
        !           473:
        !           474: /*
        !           475:  * Checks for current use of a pid, either as a pid or pgid.
        !           476:  */
        !           477: int
        !           478: pidtaken(pid_t pid)
        !           479: {
        !           480:        struct proc *p;
        !           481:
        !           482:        if (pfind(pid) != NULL)
        !           483:                return (1);
        !           484:        if (pgfind(pid) != NULL)
        !           485:                return (1);
        !           486:        LIST_FOREACH(p, &zombproc, p_list)
        !           487:                if (p->p_pid == pid || p->p_pgid == pid)
        !           488:                        return (1);
        !           489:        return (0);
        !           490: }
        !           491:
        !           492: #if defined(MULTIPROCESSOR)
        !           493: /*
        !           494:  * XXX This is a slight hack to get newly-formed processes to
        !           495:  * XXX acquire the kernel lock as soon as they run.
        !           496:  */
        !           497: void
        !           498: proc_trampoline_mp(void)
        !           499: {
        !           500:        struct proc *p;
        !           501:
        !           502:        p = curproc;
        !           503:
        !           504:        SCHED_ASSERT_UNLOCKED();
        !           505:        KERNEL_PROC_LOCK(p);
        !           506: }
        !           507: #endif

CVSweb