Annotation of XNU/bsd/kern/kern_fork.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
        !            23: /*
        !            24:  * Copyright (c) 1982, 1986, 1989, 1991, 1993
        !            25:  *     The Regents of the University of California.  All rights reserved.
        !            26:  * (c) UNIX System Laboratories, Inc.
        !            27:  * All or some portions of this file are derived from material licensed
        !            28:  * to the University of California by American Telephone and Telegraph
        !            29:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
        !            30:  * the permission of UNIX System Laboratories, Inc.
        !            31:  *
        !            32:  * Redistribution and use in source and binary forms, with or without
        !            33:  * modification, are permitted provided that the following conditions
        !            34:  * are met:
        !            35:  * 1. Redistributions of source code must retain the above copyright
        !            36:  *    notice, this list of conditions and the following disclaimer.
        !            37:  * 2. Redistributions in binary form must reproduce the above copyright
        !            38:  *    notice, this list of conditions and the following disclaimer in the
        !            39:  *    documentation and/or other materials provided with the distribution.
        !            40:  * 3. All advertising materials mentioning features or use of this software
        !            41:  *    must display the following acknowledgement:
        !            42:  *     This product includes software developed by the University of
        !            43:  *     California, Berkeley and its contributors.
        !            44:  * 4. Neither the name of the University nor the names of its contributors
        !            45:  *    may be used to endorse or promote products derived from this software
        !            46:  *    without specific prior written permission.
        !            47:  *
        !            48:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            49:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            50:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            51:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            52:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            53:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            54:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            55:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            56:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            57:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            58:  * SUCH DAMAGE.
        !            59:  *
        !            60:  *     @(#)kern_fork.c 8.8 (Berkeley) 2/14/95
        !            61:  */
        !            62: 
        !            63: #include <sys/param.h>
        !            64: #include <sys/systm.h>
        !            65: #include <sys/filedesc.h>
        !            66: #include <sys/kernel.h>
        !            67: #include <sys/malloc.h>
        !            68: #include <sys/proc.h>
        !            69: #include <sys/user.h>
        !            70: #include <sys/resourcevar.h>
        !            71: #include <sys/vnode.h>
        !            72: #include <sys/file.h>
        !            73: #include <sys/acct.h>
        !            74: #include <sys/ktrace.h>
        !            75: 
        !            76: #import <mach/mach_types.h>
        !            77: #import <kern/mach_param.h>
        !            78: 
        !            79: #import <machine/spl.h>
        !            80: 
        !            81: thread_t       cloneproc(), procdup();
        !            82: 
        !            83: #define        DOFORK  0x1     /* fork() system call */
        !            84: #define        DOVFORK 0x2     /* vfork() system call */
        !            85: static int fork1(struct proc *, long, register_t *);
        !            86: 
        !            87: /*
        !            88:  * fork system call.
        !            89:  */
        !            90: int
        !            91: fork(p, uap, retval)
        !            92:        struct proc *p;
        !            93:        void *uap;
        !            94:        register_t *retval;
        !            95: {
        !            96:        return (fork1(p, (long)DOFORK, retval));
        !            97: }
        !            98: 
        !            99: /*
        !           100:  * vfork system call
        !           101:  */
        !           102: int
        !           103: vfork(p, uap, retval)
        !           104:        struct proc *p;
        !           105:        void *uap;
        !           106:        register_t *retval;
        !           107: {
        !           108:        return (fork1(p, (long)DOVFORK, retval));
        !           109: }
        !           110: 
        !           111: static int
        !           112: fork1(p1, flags, retval)
        !           113:        struct proc *p1;
        !           114:        long flags;
        !           115:        register_t *retval;
        !           116: {
        !           117:        register struct proc *p2;
        !           118:        register uid_t uid;
        !           119:        thread_t newth, self = current_thread();
        !           120:        int s, count;
        !           121: 
        !           122:        /*
        !           123:         * Although process entries are dynamically created, we still keep
        !           124:         * a global limit on the maximum number we will create.  Don't allow
        !           125:         * a nonprivileged user to use the last process; don't let root
        !           126:         * exceed the limit. The variable nprocs is the current number of
        !           127:         * processes, maxproc is the limit.
        !           128:         */
        !           129:        uid = p1->p_cred->p_ruid;
        !           130:        if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) {
        !           131:                tablefull("proc");
        !           132:                retval[1] = 0;
        !           133:                return (EAGAIN);
        !           134:        }
        !           135: 
        !           136:        /*
        !           137:         * Increment the count of procs running with this uid. Don't allow
        !           138:         * a nonprivileged user to exceed their current limit.
        !           139:         */
        !           140:        count = chgproccnt(uid, 1);
        !           141:        if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) {
        !           142:                (void)chgproccnt(uid, -1);
        !           143:                return (EAGAIN);
        !           144:        }
        !           145: 
        !           146:        newth = cloneproc(p1);
        !           147:        thread_dup(current_act(), newth);
        !           148:        /* p2 = newth->task->proc; */
        !           149:        p2 = (struct proc *)(get_bsdtask_info(get_threadtask(newth)));
        !           150: 
        !           151:        thread_set_child(newth, p2->p_pid);
        !           152: 
        !           153:        s = splhigh();
        !           154:        p2->p_stats->p_start = time;
        !           155:        splx(s);
        !           156:        p2->p_acflag = AFORK;
        !           157: 
        !           158:        /*
        !           159:         * Preserve synchronization semantics of vfork.  If waiting for
        !           160:         * child to exec or exit, set P_PPWAIT on child, and sleep on our
        !           161:         * proc (in case of exit).
        !           162:         */
        !           163:        if (flags == DOVFORK)
        !           164:                p2->p_flag |= P_PPWAIT;
        !           165: 
        !           166:        (void) thread_resume(newth);
        !           167: 
        !           168:        while (p2->p_flag & P_PPWAIT)
        !           169:                tsleep(p1, PWAIT, "ppwait", 0);
        !           170: 
        !           171:        retval[0] = p2->p_pid;
        !           172:        retval[1] = 0;                  /* mark parent */
        !           173: 
        !           174:        return (0);
        !           175: }
        !           176: 
        !           177: /*
        !           178:  * cloneproc()
        !           179:  *
        !           180:  * Create a new process from a specified process.
        !           181:  */
        !           182: thread_t
        !           183: cloneproc(p1)
        !           184:        register struct proc *p1;
        !           185: {
        !           186:        register struct proc *p2, *newproc;
        !           187:        static int nextpid = 0, pidchecked = 0;
        !           188:        thread_t th;
        !           189: 
        !           190:        /* Allocate new proc. */
        !           191:        MALLOC_ZONE(newproc, struct proc *,
        !           192:                        sizeof *newproc, M_PROC, M_WAITOK);
        !           193:        MALLOC_ZONE(newproc->p_cred, struct pcred *,
        !           194:                        sizeof *newproc->p_cred, M_SUBPROC, M_WAITOK);
        !           195:        MALLOC_ZONE(newproc->p_stats, struct pstats *,
        !           196:                        sizeof *newproc->p_stats, M_SUBPROC, M_WAITOK);
        !           197:        MALLOC_ZONE(newproc->p_sigacts, struct sigacts *,
        !           198:                        sizeof *newproc->p_sigacts, M_SUBPROC, M_WAITOK);
        !           199: 
        !           200:        /*
        !           201:         * Find an unused process ID.  We remember a range of unused IDs
        !           202:         * ready to use (from nextpid+1 through pidchecked-1).
        !           203:         */
        !           204:        nextpid++;
        !           205: retry:
        !           206:        /*
        !           207:         * If the process ID prototype has wrapped around,
        !           208:         * restart somewhat above 0, as the low-numbered procs
        !           209:         * tend to include daemons that don't exit.
        !           210:         */
        !           211:        if (nextpid >= PID_MAX) {
        !           212:                nextpid = 100;
        !           213:                pidchecked = 0;
        !           214:        }
        !           215:        if (nextpid >= pidchecked) {
        !           216:                int doingzomb = 0;
        !           217: 
        !           218:                pidchecked = PID_MAX;
        !           219:                /*
        !           220:                 * Scan the active and zombie procs to check whether this pid
        !           221:                 * is in use.  Remember the lowest pid that's greater
        !           222:                 * than nextpid, so we can avoid checking for a while.
        !           223:                 */
        !           224:                p2 = allproc.lh_first;
        !           225: again:
        !           226:                for (; p2 != 0; p2 = p2->p_list.le_next) {
        !           227:                        while (p2->p_pid == nextpid ||
        !           228:                            p2->p_pgrp->pg_id == nextpid) {
        !           229:                                nextpid++;
        !           230:                                if (nextpid >= pidchecked)
        !           231:                                        goto retry;
        !           232:                        }
        !           233:                        if (p2->p_pid > nextpid && pidchecked > p2->p_pid)
        !           234:                                pidchecked = p2->p_pid;
        !           235:                        if (p2->p_pgrp->pg_id > nextpid && 
        !           236:                            pidchecked > p2->p_pgrp->pg_id)
        !           237:                                pidchecked = p2->p_pgrp->pg_id;
        !           238:                }
        !           239:                if (!doingzomb) {
        !           240:                        doingzomb = 1;
        !           241:                        p2 = zombproc.lh_first;
        !           242:                        goto again;
        !           243:                }
        !           244:        }
        !           245: 
        !           246:        nprocs++;
        !           247:        p2 = newproc;
        !           248:        p2->p_stat = SIDL;
        !           249:        p2->p_pid = nextpid;
        !           250: 
        !           251:        /*
        !           252:         * Make a proc table entry for the new process.
        !           253:         * Start by zeroing the section of proc that is zero-initialized,
        !           254:         * then copy the section that is copied directly from the parent.
        !           255:         */
        !           256:        bzero(&p2->p_startzero,
        !           257:            (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero));
        !           258:        bcopy(&p1->p_startcopy, &p2->p_startcopy,
        !           259:            (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy));
        !           260:        p2->vm_shm = (void *)NULL; /* Make sure it is zero */
        !           261: 
        !           262:        /*
        !           263:         * Duplicate sub-structures as needed.
        !           264:         * Increase reference counts on shared objects.
        !           265:         * The p_stats and p_sigacts substructs are set in vm_fork.
        !           266:         */
        !           267:        p2->p_flag = P_INMEM;
        !           268:        if (p1->p_flag & P_PROFIL)
        !           269:                startprofclock(p2);
        !           270:        bcopy(p1->p_cred, p2->p_cred, sizeof(*p2->p_cred));
        !           271:        p2->p_cred->p_refcnt = 1;
        !           272:        crhold(p1->p_ucred);
        !           273:        lockinit(&p2->p_cred->pc_lock, PLOCK, "proc cred", 0, 0);
        !           274: 
        !           275:        /* bump references to the text vnode (for procfs) */
        !           276:        p2->p_textvp = p1->p_textvp;
        !           277:        if (p2->p_textvp)
        !           278:                VREF(p2->p_textvp);
        !           279: 
        !           280:        p2->p_fd = fdcopy(p1);
        !           281:        if (p1->vm_shm) {
        !           282:                shmfork(p1,p2);
        !           283:        }
        !           284:        /*
        !           285:         * If p_limit is still copy-on-write, bump refcnt,
        !           286:         * otherwise get a copy that won't be modified.
        !           287:         * (If PL_SHAREMOD is clear, the structure is shared
        !           288:         * copy-on-write.)
        !           289:         */
        !           290:        if (p1->p_limit->p_lflags & PL_SHAREMOD)
        !           291:                p2->p_limit = limcopy(p1->p_limit);
        !           292:        else {
        !           293:                p2->p_limit = p1->p_limit;
        !           294:                p2->p_limit->p_refcnt++;
        !           295:        }
        !           296: 
        !           297:        bzero(&p2->p_stats->pstat_startzero,
        !           298:            (unsigned) ((caddr_t)&p2->p_stats->pstat_endzero -
        !           299:            (caddr_t)&p2->p_stats->pstat_startzero));
        !           300:        bcopy(&p1->p_stats->pstat_startcopy, &p2->p_stats->pstat_startcopy,
        !           301:            ((caddr_t)&p2->p_stats->pstat_endcopy -
        !           302:             (caddr_t)&p2->p_stats->pstat_startcopy));
        !           303: 
        !           304:        if (p1->p_sigacts != NULL)
        !           305:                (void)memcpy(p2->p_sigacts,
        !           306:                                p1->p_sigacts, sizeof *p2->p_sigacts);
        !           307:        else
        !           308:                (void)memset(p2->p_sigacts, 0, sizeof *p2->p_sigacts);
        !           309: 
        !           310:        if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
        !           311:                p2->p_flag |= P_CONTROLT;
        !           312: 
        !           313:        p2->p_xstat = 0;
        !           314:        p2->p_ru = NULL;
        !           315: 
        !           316:        p2->p_debugger = 0;     /* don't inherit */
        !           317:        simple_lock_init(&p2->siglock);
        !           318:        p2->sigwait = FALSE;
        !           319:        p2->sigwait_thread = NULL;
        !           320:        p2->exit_thread = NULL;
        !           321:        p2->user_stack = p1->user_stack;
        !           322: 
        !           323: #if KTRACE
        !           324:        /*
        !           325:         * Copy traceflag and tracefile if enabled.
        !           326:         * If not inherited, these were zeroed above.
        !           327:         */
        !           328:        if (p1->p_traceflag&KTRFAC_INHERIT) {
        !           329:                p2->p_traceflag = p1->p_traceflag;
        !           330:                if ((p2->p_tracep = p1->p_tracep) != NULL)
        !           331:                        VREF(p2->p_tracep);
        !           332:        }
        !           333: #endif
        !           334: 
        !           335:        th = procdup(p2, p1);   /* child, parent */
        !           336:        LIST_INSERT_AFTER(p1, p2, p_pglist);
        !           337:        p2->p_pptr = p1;
        !           338:        LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling);
        !           339:        LIST_INIT(&p2->p_children);
        !           340:        LIST_INSERT_HEAD(&allproc, p2, p_list);
        !           341:        LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
        !           342:        TAILQ_INIT(&p2->p_evlist);
        !           343:        /*
        !           344:         * Make child runnable, set start time.
        !           345:         */
        !           346:        p2->p_stat = SRUN;
        !           347: 
        !           348:        return(th);
        !           349: }
        !           350: 
        !           351: struct zone    *u_thread_zone;
        !           352: 
        !           353: void
        !           354: uzone_init()
        !           355: {
        !           356:        u_thread_zone = zinit(sizeof(struct uthread),
        !           357:                        THREAD_MAX * sizeof(struct uthread),
        !           358:                        THREAD_CHUNK * sizeof(struct uthread),
        !           359:                        "uthreads");
        !           360: }
        !           361: 
        !           362: void
        !           363: uthread_free(uthread)
        !           364:        struct uthread  *uthread;
        !           365: {
        !           366:        zfree(u_thread_zone, (vm_offset_t) uthread);
        !           367: }
        !           368:        

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.