1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)kern_fork.c 8.6 (Berkeley) 4/8/94 39af8ad83eSPeter Wemm * $Id: kern_fork.c,v 1.56 1999/03/02 00:28:08 julian Exp $ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 42db6a20e2SGarrett Wollman #include "opt_ktrace.h" 43db6a20e2SGarrett Wollman 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 46d2d3e875SBruce Evans #include <sys/sysproto.h> 47df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 48df8bae1dSRodney W. Grimes #include <sys/kernel.h> 49c76e95c3SPeter Wemm #include <sys/sysctl.h> 50df8bae1dSRodney W. Grimes #include <sys/malloc.h> 51df8bae1dSRodney W. Grimes #include <sys/proc.h> 52df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 53df8bae1dSRodney W. Grimes #include <sys/vnode.h> 54df8bae1dSRodney W. Grimes #include <sys/acct.h> 55df8bae1dSRodney W. Grimes #include <sys/ktrace.h> 56b71fec07SBruce Evans #include <sys/unistd.h> 57df8bae1dSRodney W. Grimes 58d93f860cSPoul-Henning Kamp #include <vm/vm.h> 59996c772fSJohn Dyson #include <sys/lock.h> 60dabee6feSPeter Wemm #include <vm/pmap.h> 61dabee6feSPeter Wemm #include <vm/vm_map.h> 62efeaf95aSDavid Greenman #include <vm/vm_extern.h> 632d8acc0fSJohn Dyson #include <vm/vm_zone.h> 64d93f860cSPoul-Henning Kamp 656626c604SJulian Elischer #include <machine/frame.h> 66dc9c271aSJulian Elischer #include <sys/user.h> 6788c5ea45SJulian Elischer 68c76e95c3SPeter Wemm #ifdef SMP 69be67169aSBruce Evans static int fast_vfork = 0; /* Doesn't work on SMP yet. */ 70c76e95c3SPeter Wemm #else 71be67169aSBruce Evans static int fast_vfork = 1; 72c76e95c3SPeter Wemm #endif 73c76e95c3SPeter Wemm SYSCTL_INT(_kern, OID_AUTO, fast_vfork, CTLFLAG_RW, &fast_vfork, 0, ""); 74c76e95c3SPeter Wemm 75fed06968SJulian Elischer /* 76e0d898b4SJulian Elischer * These are the stuctures used to create a callout list for things to do 77e0d898b4SJulian Elischer * when forking a process 78fed06968SJulian Elischer */ 79fed06968SJulian Elischer typedef struct fork_list_element { 80fed06968SJulian Elischer struct fork_list_element *next; 81fed06968SJulian Elischer forklist_fn function; 82fed06968SJulian Elischer } *fle_p; 83fed06968SJulian Elischer 84fed06968SJulian Elischer static fle_p fork_list; 85fed06968SJulian Elischer 86d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 87ad7507e2SSteven Wallace struct fork_args { 88ad7507e2SSteven Wallace int dummy; 89ad7507e2SSteven Wallace }; 90d2d3e875SBruce Evans #endif 91ad7507e2SSteven Wallace 92df8bae1dSRodney W. Grimes /* ARGSUSED */ 9326f9a767SRodney W. Grimes int 94cb226aaaSPoul-Henning Kamp fork(p, uap) 95df8bae1dSRodney W. Grimes struct proc *p; 96df8bae1dSRodney W. Grimes struct fork_args *uap; 97df8bae1dSRodney W. Grimes { 98be67169aSBruce Evans 99be67169aSBruce Evans return (fork1(p, RFFDG | RFPROC)); 100df8bae1dSRodney W. Grimes } 101df8bae1dSRodney W. Grimes 102df8bae1dSRodney W. Grimes /* ARGSUSED */ 10326f9a767SRodney W. Grimes int 104cb226aaaSPoul-Henning Kamp vfork(p, uap) 105df8bae1dSRodney W. Grimes struct proc *p; 106dabee6feSPeter Wemm struct vfork_args *uap; 107df8bae1dSRodney W. Grimes { 108be67169aSBruce Evans 109be67169aSBruce Evans return (fork1(p, RFFDG | RFPROC | RFPPWAIT | (fast_vfork ? RFMEM : 0))); 110df8bae1dSRodney W. Grimes } 111df8bae1dSRodney W. Grimes 112dabee6feSPeter Wemm /* ARGSUSED */ 113dabee6feSPeter Wemm int 114cb226aaaSPoul-Henning Kamp rfork(p, uap) 115dabee6feSPeter Wemm struct proc *p; 116dabee6feSPeter Wemm struct rfork_args *uap; 117dabee6feSPeter Wemm { 118be67169aSBruce Evans 119be67169aSBruce Evans return (fork1(p, uap->flags)); 120dabee6feSPeter Wemm } 121dabee6feSPeter Wemm 122dabee6feSPeter Wemm 123df8bae1dSRodney W. Grimes int nprocs = 1; /* process 0 */ 12451068190SWolfram Schneider static int nextpid = 0; 125df8bae1dSRodney W. Grimes 12674b2192aSJohn Dyson int 127be67169aSBruce Evans fork1(p1, flags) 128df8bae1dSRodney W. Grimes register struct proc *p1; 1290e3eb7eeSSujal Patel int flags; 130df8bae1dSRodney W. Grimes { 1310e3eb7eeSSujal Patel register struct proc *p2, *pptr; 132df8bae1dSRodney W. Grimes register uid_t uid; 133df8bae1dSRodney W. Grimes struct proc *newproc; 134df8bae1dSRodney W. Grimes int count; 13551068190SWolfram Schneider static int pidchecked = 0; 136e0d898b4SJulian Elischer fle_p ep ; 137dabee6feSPeter Wemm 138e0d898b4SJulian Elischer ep = fork_list; 1395856e12eSJohn Dyson 1400e3eb7eeSSujal Patel if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) 141dabee6feSPeter Wemm return (EINVAL); 142df8bae1dSRodney W. Grimes 143b3196e4bSPeter Wemm #ifdef SMP 144b3196e4bSPeter Wemm /* 145b3196e4bSPeter Wemm * FATAL now, we cannot have the same PTD on both cpus, the PTD 146b3196e4bSPeter Wemm * needs to move out of PTmap and be per-process, even for shared 147b3196e4bSPeter Wemm * page table processes. Unfortunately, this means either removing 148b3196e4bSPeter Wemm * PTD[] as a fixed virtual address, or move it to the per-cpu map 149b3196e4bSPeter Wemm * area for SMP mode. Both cases require seperate management of 150b3196e4bSPeter Wemm * the per-process-even-if-PTmap-is-shared PTD. 151b3196e4bSPeter Wemm */ 152e384a980SPeter Wemm if (flags & RFMEM) { 153e384a980SPeter Wemm printf("shared address space fork attempted: pid: %d\n", 154e384a980SPeter Wemm p1->p_pid); 155b3196e4bSPeter Wemm return (EOPNOTSUPP); 156e384a980SPeter Wemm } 157b3196e4bSPeter Wemm #endif 158b3196e4bSPeter Wemm 159df8bae1dSRodney W. Grimes /* 1605856e12eSJohn Dyson * Here we don't create a new process, but we divorce 1615856e12eSJohn Dyson * certain parts of a process from itself. 1625856e12eSJohn Dyson */ 1635856e12eSJohn Dyson if ((flags & RFPROC) == 0) { 1645856e12eSJohn Dyson 1655856e12eSJohn Dyson /* 1665856e12eSJohn Dyson * Divorce the memory, if it is shared, essentially 1675856e12eSJohn Dyson * this changes shared memory amongst threads, into 1685856e12eSJohn Dyson * COW locally. 1695856e12eSJohn Dyson */ 1705856e12eSJohn Dyson if ((flags & RFMEM) == 0) { 1715856e12eSJohn Dyson if (p1->p_vmspace->vm_refcnt > 1) { 1725856e12eSJohn Dyson vmspace_unshare(p1); 1735856e12eSJohn Dyson } 1745856e12eSJohn Dyson } 1755856e12eSJohn Dyson 1765856e12eSJohn Dyson /* 1775856e12eSJohn Dyson * Close all file descriptors. 1785856e12eSJohn Dyson */ 1795856e12eSJohn Dyson if (flags & RFCFDG) { 1805856e12eSJohn Dyson struct filedesc *fdtmp; 1815856e12eSJohn Dyson fdtmp = fdinit(p1); 1825856e12eSJohn Dyson fdfree(p1); 1835856e12eSJohn Dyson p1->p_fd = fdtmp; 1845856e12eSJohn Dyson } 1855856e12eSJohn Dyson 1865856e12eSJohn Dyson /* 1875856e12eSJohn Dyson * Unshare file descriptors (from parent.) 1885856e12eSJohn Dyson */ 1895856e12eSJohn Dyson if (flags & RFFDG) { 1905856e12eSJohn Dyson if (p1->p_fd->fd_refcnt > 1) { 1915856e12eSJohn Dyson struct filedesc *newfd; 1925856e12eSJohn Dyson newfd = fdcopy(p1); 1935856e12eSJohn Dyson fdfree(p1); 1945856e12eSJohn Dyson p1->p_fd = newfd; 1955856e12eSJohn Dyson } 1965856e12eSJohn Dyson } 1975856e12eSJohn Dyson return (0); 1985856e12eSJohn Dyson } 1995856e12eSJohn Dyson 2005856e12eSJohn Dyson /* 201df8bae1dSRodney W. Grimes * Although process entries are dynamically created, we still keep 202df8bae1dSRodney W. Grimes * a global limit on the maximum number we will create. Don't allow 203df8bae1dSRodney W. Grimes * a nonprivileged user to use the last process; don't let root 204df8bae1dSRodney W. Grimes * exceed the limit. The variable nprocs is the current number of 205df8bae1dSRodney W. Grimes * processes, maxproc is the limit. 206df8bae1dSRodney W. Grimes */ 207df8bae1dSRodney W. Grimes uid = p1->p_cred->p_ruid; 208df8bae1dSRodney W. Grimes if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) { 209df8bae1dSRodney W. Grimes tablefull("proc"); 210df8bae1dSRodney W. Grimes return (EAGAIN); 211df8bae1dSRodney W. Grimes } 212df8bae1dSRodney W. Grimes /* 213ef5dc8a9SJohn Dyson * Increment the nprocs resource before blocking can occur. There 214ef5dc8a9SJohn Dyson * are hard-limits as to the number of processes that can run. 215ef5dc8a9SJohn Dyson */ 216ef5dc8a9SJohn Dyson nprocs++; 217ef5dc8a9SJohn Dyson 218ef5dc8a9SJohn Dyson /* 219df8bae1dSRodney W. Grimes * Increment the count of procs running with this uid. Don't allow 220df8bae1dSRodney W. Grimes * a nonprivileged user to exceed their current limit. 221df8bae1dSRodney W. Grimes */ 222df8bae1dSRodney W. Grimes count = chgproccnt(uid, 1); 223df8bae1dSRodney W. Grimes if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) { 224df8bae1dSRodney W. Grimes (void)chgproccnt(uid, -1); 225ef5dc8a9SJohn Dyson /* 226ef5dc8a9SJohn Dyson * Back out the process count 227ef5dc8a9SJohn Dyson */ 228ef5dc8a9SJohn Dyson nprocs--; 229df8bae1dSRodney W. Grimes return (EAGAIN); 230df8bae1dSRodney W. Grimes } 231df8bae1dSRodney W. Grimes 232df8bae1dSRodney W. Grimes /* Allocate new proc. */ 2332d8acc0fSJohn Dyson newproc = zalloc(proc_zone); 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes /* 2362c1011f7SJohn Dyson * Setup linkage for kernel based threading 2372c1011f7SJohn Dyson */ 2382c1011f7SJohn Dyson if((flags & RFTHREAD) != 0) { 2392c1011f7SJohn Dyson newproc->p_peers = p1->p_peers; 2402c1011f7SJohn Dyson p1->p_peers = newproc; 2412c1011f7SJohn Dyson newproc->p_leader = p1->p_leader; 2422c1011f7SJohn Dyson } else { 2432c1011f7SJohn Dyson newproc->p_peers = 0; 2442c1011f7SJohn Dyson newproc->p_leader = newproc; 2452c1011f7SJohn Dyson } 2462c1011f7SJohn Dyson 2472c1011f7SJohn Dyson newproc->p_wakeup = 0; 2482c1011f7SJohn Dyson 2492c1011f7SJohn Dyson /* 250df8bae1dSRodney W. Grimes * Find an unused process ID. We remember a range of unused IDs 251df8bae1dSRodney W. Grimes * ready to use (from nextpid+1 through pidchecked-1). 252df8bae1dSRodney W. Grimes */ 253df8bae1dSRodney W. Grimes nextpid++; 254df8bae1dSRodney W. Grimes retry: 255df8bae1dSRodney W. Grimes /* 256df8bae1dSRodney W. Grimes * If the process ID prototype has wrapped around, 257df8bae1dSRodney W. Grimes * restart somewhat above 0, as the low-numbered procs 258df8bae1dSRodney W. Grimes * tend to include daemons that don't exit. 259df8bae1dSRodney W. Grimes */ 260df8bae1dSRodney W. Grimes if (nextpid >= PID_MAX) { 261df8bae1dSRodney W. Grimes nextpid = 100; 262df8bae1dSRodney W. Grimes pidchecked = 0; 263df8bae1dSRodney W. Grimes } 264df8bae1dSRodney W. Grimes if (nextpid >= pidchecked) { 265df8bae1dSRodney W. Grimes int doingzomb = 0; 266df8bae1dSRodney W. Grimes 267df8bae1dSRodney W. Grimes pidchecked = PID_MAX; 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * Scan the active and zombie procs to check whether this pid 270df8bae1dSRodney W. Grimes * is in use. Remember the lowest pid that's greater 271df8bae1dSRodney W. Grimes * than nextpid, so we can avoid checking for a while. 272df8bae1dSRodney W. Grimes */ 273b75356e1SJeffrey Hsu p2 = allproc.lh_first; 274df8bae1dSRodney W. Grimes again: 275b75356e1SJeffrey Hsu for (; p2 != 0; p2 = p2->p_list.le_next) { 276df8bae1dSRodney W. Grimes while (p2->p_pid == nextpid || 277643a8daaSDon Lewis p2->p_pgrp->pg_id == nextpid || 278643a8daaSDon Lewis p2->p_session->s_sid == nextpid) { 279df8bae1dSRodney W. Grimes nextpid++; 280df8bae1dSRodney W. Grimes if (nextpid >= pidchecked) 281df8bae1dSRodney W. Grimes goto retry; 282df8bae1dSRodney W. Grimes } 283df8bae1dSRodney W. Grimes if (p2->p_pid > nextpid && pidchecked > p2->p_pid) 284df8bae1dSRodney W. Grimes pidchecked = p2->p_pid; 285df8bae1dSRodney W. Grimes if (p2->p_pgrp->pg_id > nextpid && 286df8bae1dSRodney W. Grimes pidchecked > p2->p_pgrp->pg_id) 287df8bae1dSRodney W. Grimes pidchecked = p2->p_pgrp->pg_id; 288643a8daaSDon Lewis if (p2->p_session->s_sid > nextpid && 289643a8daaSDon Lewis pidchecked > p2->p_session->s_sid) 290643a8daaSDon Lewis pidchecked = p2->p_session->s_sid; 291df8bae1dSRodney W. Grimes } 292df8bae1dSRodney W. Grimes if (!doingzomb) { 293df8bae1dSRodney W. Grimes doingzomb = 1; 294b75356e1SJeffrey Hsu p2 = zombproc.lh_first; 295df8bae1dSRodney W. Grimes goto again; 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes } 298df8bae1dSRodney W. Grimes 299df8bae1dSRodney W. Grimes p2 = newproc; 300b75356e1SJeffrey Hsu p2->p_stat = SIDL; /* protect against others */ 301b75356e1SJeffrey Hsu p2->p_pid = nextpid; 302b75356e1SJeffrey Hsu LIST_INSERT_HEAD(&allproc, p2, p_list); 303b75356e1SJeffrey Hsu LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); 304df8bae1dSRodney W. Grimes 305df8bae1dSRodney W. Grimes /* 306df8bae1dSRodney W. Grimes * Make a proc table entry for the new process. 307df8bae1dSRodney W. Grimes * Start by zeroing the section of proc that is zero-initialized, 308df8bae1dSRodney W. Grimes * then copy the section that is copied directly from the parent. 309df8bae1dSRodney W. Grimes */ 310df8bae1dSRodney W. Grimes bzero(&p2->p_startzero, 311df8bae1dSRodney W. Grimes (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero)); 312df8bae1dSRodney W. Grimes bcopy(&p1->p_startcopy, &p2->p_startcopy, 313df8bae1dSRodney W. Grimes (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy)); 314df8bae1dSRodney W. Grimes 3152244ea07SJohn Dyson p2->p_aioinfo = NULL; 3162244ea07SJohn Dyson 317df8bae1dSRodney W. Grimes /* 318df8bae1dSRodney W. Grimes * Duplicate sub-structures as needed. 319df8bae1dSRodney W. Grimes * Increase reference counts on shared objects. 320df8bae1dSRodney W. Grimes * The p_stats and p_sigacts substructs are set in vm_fork. 321df8bae1dSRodney W. Grimes */ 322df8bae1dSRodney W. Grimes p2->p_flag = P_INMEM; 323df8bae1dSRodney W. Grimes if (p1->p_flag & P_PROFIL) 324df8bae1dSRodney W. Grimes startprofclock(p2); 325df8bae1dSRodney W. Grimes MALLOC(p2->p_cred, struct pcred *, sizeof(struct pcred), 326df8bae1dSRodney W. Grimes M_SUBPROC, M_WAITOK); 327df8bae1dSRodney W. Grimes bcopy(p1->p_cred, p2->p_cred, sizeof(*p2->p_cred)); 328df8bae1dSRodney W. Grimes p2->p_cred->p_refcnt = 1; 329df8bae1dSRodney W. Grimes crhold(p1->p_ucred); 330df8bae1dSRodney W. Grimes 3316626c604SJulian Elischer if (flags & RFSIGSHARE) { 332dc9c271aSJulian Elischer p2->p_procsig = p1->p_procsig; 3336626c604SJulian Elischer p2->p_procsig->ps_refcnt++; 334dc9c271aSJulian Elischer if (p1->p_sigacts == &p1->p_addr->u_sigacts) { 335dc9c271aSJulian Elischer struct sigacts *newsigacts; 336dc9c271aSJulian Elischer int s; 337dc9c271aSJulian Elischer 338dc9c271aSJulian Elischer if (p2->p_procsig->ps_refcnt != 2) 339dc9c271aSJulian Elischer printf ("PID:%d Creating shared sigacts with procsig->ps_refcnt %d\n", 340dc9c271aSJulian Elischer p2->p_pid, p2->p_procsig->ps_refcnt); 341dc9c271aSJulian Elischer /* Create the shared sigacts structure */ 342dc9c271aSJulian Elischer MALLOC (newsigacts, struct sigacts *, sizeof (struct sigacts), 343dc9c271aSJulian Elischer M_SUBPROC, M_WAITOK); 344dc9c271aSJulian Elischer s = splhigh(); 345dc9c271aSJulian Elischer /* Set p_sigacts to the new shared structure. Note that this 346dc9c271aSJulian Elischer * is updating p1->p_sigacts at the same time, since p_sigacts 347dc9c271aSJulian Elischer * is just a pointer to the shared p_procsig->ps_sigacts. 348dc9c271aSJulian Elischer */ 349dc9c271aSJulian Elischer p2->p_sigacts = newsigacts; 350dc9c271aSJulian Elischer /* Copy in the values from the u area */ 351dc9c271aSJulian Elischer *p2->p_sigacts = p1->p_addr->u_sigacts; 352dc9c271aSJulian Elischer splx (s); 353dc9c271aSJulian Elischer } 3546626c604SJulian Elischer } else { 355dc9c271aSJulian Elischer MALLOC (p2->p_procsig, struct procsig *, sizeof(struct procsig), 356dc9c271aSJulian Elischer M_SUBPROC, M_WAITOK); 3576626c604SJulian Elischer bcopy(&p1->p_procsig->ps_begincopy, &p2->p_procsig->ps_begincopy, 3586626c604SJulian Elischer (unsigned)&p1->p_procsig->ps_endcopy - 3596626c604SJulian Elischer (unsigned)&p1->p_procsig->ps_begincopy); 360dc9c271aSJulian Elischer p2->p_procsig->ps_refcnt = 1; 361dc9c271aSJulian Elischer /* Note that we fill in the values of sigacts in vm_fork */ 362dc9c271aSJulian Elischer p2->p_sigacts = NULL; 3636626c604SJulian Elischer } 3644ac9ae70SJulian Elischer if (flags & RFLINUXTHPN) 3656626c604SJulian Elischer p2->p_sigparent = SIGUSR1; 3664ac9ae70SJulian Elischer else 3674ac9ae70SJulian Elischer p2->p_sigparent = SIGCHLD; 36888c5ea45SJulian Elischer 369df8bae1dSRodney W. Grimes /* bump references to the text vnode (for procfs) */ 370df8bae1dSRodney W. Grimes p2->p_textvp = p1->p_textvp; 371df8bae1dSRodney W. Grimes if (p2->p_textvp) 372df8bae1dSRodney W. Grimes VREF(p2->p_textvp); 373df8bae1dSRodney W. Grimes 3740e3eb7eeSSujal Patel if (flags & RFCFDG) 375dabee6feSPeter Wemm p2->p_fd = fdinit(p1); 3760e3eb7eeSSujal Patel else if (flags & RFFDG) 377df8bae1dSRodney W. Grimes p2->p_fd = fdcopy(p1); 378dabee6feSPeter Wemm else 379dabee6feSPeter Wemm p2->p_fd = fdshare(p1); 380dabee6feSPeter Wemm 381df8bae1dSRodney W. Grimes /* 382df8bae1dSRodney W. Grimes * If p_limit is still copy-on-write, bump refcnt, 383df8bae1dSRodney W. Grimes * otherwise get a copy that won't be modified. 384df8bae1dSRodney W. Grimes * (If PL_SHAREMOD is clear, the structure is shared 385df8bae1dSRodney W. Grimes * copy-on-write.) 386df8bae1dSRodney W. Grimes */ 387df8bae1dSRodney W. Grimes if (p1->p_limit->p_lflags & PL_SHAREMOD) 388df8bae1dSRodney W. Grimes p2->p_limit = limcopy(p1->p_limit); 389df8bae1dSRodney W. Grimes else { 390df8bae1dSRodney W. Grimes p2->p_limit = p1->p_limit; 391df8bae1dSRodney W. Grimes p2->p_limit->p_refcnt++; 392df8bae1dSRodney W. Grimes } 393df8bae1dSRodney W. Grimes 39470e534e7SDavid Greenman /* 395be67169aSBruce Evans * Preserve some more flags in subprocess. P_PROFIL has already 396be67169aSBruce Evans * been preserved. 39770e534e7SDavid Greenman */ 39870e534e7SDavid Greenman p2->p_flag |= p1->p_flag & P_SUGID; 399df8bae1dSRodney W. Grimes if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) 400df8bae1dSRodney W. Grimes p2->p_flag |= P_CONTROLT; 4010e3eb7eeSSujal Patel if (flags & RFPPWAIT) 402df8bae1dSRodney W. Grimes p2->p_flag |= P_PPWAIT; 403be67169aSBruce Evans 404b75356e1SJeffrey Hsu LIST_INSERT_AFTER(p1, p2, p_pglist); 4050e3eb7eeSSujal Patel 4060e3eb7eeSSujal Patel /* 4070e3eb7eeSSujal Patel * Attach the new process to its parent. 4080e3eb7eeSSujal Patel * 4090e3eb7eeSSujal Patel * If RFNOWAIT is set, the newly created process becomes a child 4100e3eb7eeSSujal Patel * of init. This effectively disassociates the child from the 4110e3eb7eeSSujal Patel * parent. 4120e3eb7eeSSujal Patel */ 4130e3eb7eeSSujal Patel if (flags & RFNOWAIT) 4140e3eb7eeSSujal Patel pptr = initproc; 4150e3eb7eeSSujal Patel else 4160e3eb7eeSSujal Patel pptr = p1; 4170e3eb7eeSSujal Patel p2->p_pptr = pptr; 4180e3eb7eeSSujal Patel LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling); 419b75356e1SJeffrey Hsu LIST_INIT(&p2->p_children); 420b75356e1SJeffrey Hsu 421df8bae1dSRodney W. Grimes #ifdef KTRACE 422df8bae1dSRodney W. Grimes /* 423df8bae1dSRodney W. Grimes * Copy traceflag and tracefile if enabled. 424df8bae1dSRodney W. Grimes * If not inherited, these were zeroed above. 425df8bae1dSRodney W. Grimes */ 426df8bae1dSRodney W. Grimes if (p1->p_traceflag&KTRFAC_INHERIT) { 427df8bae1dSRodney W. Grimes p2->p_traceflag = p1->p_traceflag; 428df8bae1dSRodney W. Grimes if ((p2->p_tracep = p1->p_tracep) != NULL) 429df8bae1dSRodney W. Grimes VREF(p2->p_tracep); 430df8bae1dSRodney W. Grimes } 431df8bae1dSRodney W. Grimes #endif 432df8bae1dSRodney W. Grimes 433df8bae1dSRodney W. Grimes /* 4340d2afceeSDavid Greenman * set priority of child to be that of parent 4350d2afceeSDavid Greenman */ 4360d2afceeSDavid Greenman p2->p_estcpu = p1->p_estcpu; 4370d2afceeSDavid Greenman 4380d2afceeSDavid Greenman /* 439df8bae1dSRodney W. Grimes * This begins the section where we must prevent the parent 440df8bae1dSRodney W. Grimes * from being swapped. 441df8bae1dSRodney W. Grimes */ 442af8ad83eSPeter Wemm PHOLD(p1); 4430d2afceeSDavid Greenman 444df8bae1dSRodney W. Grimes /* 445a2a1c95cSPeter Wemm * Finish creating the child process. It will return via a different 446a2a1c95cSPeter Wemm * execution path later. (ie: directly into user mode) 447dabee6feSPeter Wemm */ 448a2a1c95cSPeter Wemm vm_fork(p1, p2, flags); 449df8bae1dSRodney W. Grimes 450df8bae1dSRodney W. Grimes /* 451e0d898b4SJulian Elischer * Both processes are set up, now check if any LKMs want 452e0d898b4SJulian Elischer * to adjust anything. 453fed06968SJulian Elischer * What if they have an error? XXX 454fed06968SJulian Elischer */ 455fed06968SJulian Elischer while (ep) { 456fed06968SJulian Elischer (*ep->function)(p1, p2, flags); 457fed06968SJulian Elischer ep = ep->next; 458fed06968SJulian Elischer } 459fed06968SJulian Elischer 460fed06968SJulian Elischer /* 461df8bae1dSRodney W. Grimes * Make child runnable and add to run queue. 462df8bae1dSRodney W. Grimes */ 463a2a1c95cSPeter Wemm microtime(&(p2->p_stats->p_start)); 464a2a1c95cSPeter Wemm p2->p_acflag = AFORK; 465df8bae1dSRodney W. Grimes (void) splhigh(); 466df8bae1dSRodney W. Grimes p2->p_stat = SRUN; 467df8bae1dSRodney W. Grimes setrunqueue(p2); 468df8bae1dSRodney W. Grimes (void) spl0(); 469df8bae1dSRodney W. Grimes 470df8bae1dSRodney W. Grimes /* 471df8bae1dSRodney W. Grimes * Now can be swapped. 472df8bae1dSRodney W. Grimes */ 473af8ad83eSPeter Wemm PRELE(p1); 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes /* 476df8bae1dSRodney W. Grimes * Preserve synchronization semantics of vfork. If waiting for 477df8bae1dSRodney W. Grimes * child to exec or exit, set P_PPWAIT on child, and sleep on our 478df8bae1dSRodney W. Grimes * proc (in case of exit). 479df8bae1dSRodney W. Grimes */ 480df8bae1dSRodney W. Grimes while (p2->p_flag & P_PPWAIT) 481df8bae1dSRodney W. Grimes tsleep(p1, PWAIT, "ppwait", 0); 482df8bae1dSRodney W. Grimes 483df8bae1dSRodney W. Grimes /* 484df8bae1dSRodney W. Grimes * Return child pid to parent process, 485be67169aSBruce Evans * marking us as parent via p1->p_retval[1]. 486df8bae1dSRodney W. Grimes */ 487be67169aSBruce Evans p1->p_retval[0] = p2->p_pid; 488be67169aSBruce Evans p1->p_retval[1] = 0; 489df8bae1dSRodney W. Grimes return (0); 490df8bae1dSRodney W. Grimes } 491fed06968SJulian Elischer 492e0d898b4SJulian Elischer /* 493e0d898b4SJulian Elischer * The next two functionms are general routines to handle adding/deleting 494e0d898b4SJulian Elischer * items on the fork callout list. 495e0d898b4SJulian Elischer * 496e0d898b4SJulian Elischer * at_fork(): 497e0d898b4SJulian Elischer * Take the arguments given and put them onto the fork callout list, 498fed06968SJulian Elischer * However first make sure that it's not already there. 499e0d898b4SJulian Elischer * Returns 0 on success or a standard error number. 500fed06968SJulian Elischer */ 501fed06968SJulian Elischer int 502eb776aeaSBruce Evans at_fork(function) 503eb776aeaSBruce Evans forklist_fn function; 504fed06968SJulian Elischer { 505fed06968SJulian Elischer fle_p ep; 506e0d898b4SJulian Elischer 507e0d898b4SJulian Elischer /* let the programmer know if he's been stupid */ 508e0d898b4SJulian Elischer if (rm_at_fork(function)) 509fed06968SJulian Elischer printf("fork callout entry already present\n"); 510fed06968SJulian Elischer ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 511e0d898b4SJulian Elischer if (ep == NULL) 512e0d898b4SJulian Elischer return (ENOMEM); 513fed06968SJulian Elischer ep->next = fork_list; 514fed06968SJulian Elischer ep->function = function; 515fed06968SJulian Elischer fork_list = ep; 516e0d898b4SJulian Elischer return (0); 517fed06968SJulian Elischer } 518e0d898b4SJulian Elischer 519fed06968SJulian Elischer /* 520fed06968SJulian Elischer * Scan the exit callout list for the given items and remove them. 521fed06968SJulian Elischer * Returns the number of items removed. 522e0d898b4SJulian Elischer * Theoretically this value can only be 0 or 1. 523fed06968SJulian Elischer */ 524fed06968SJulian Elischer int 525eb776aeaSBruce Evans rm_at_fork(function) 526eb776aeaSBruce Evans forklist_fn function; 527fed06968SJulian Elischer { 528fed06968SJulian Elischer fle_p *epp, ep; 529e0d898b4SJulian Elischer int count; 530fed06968SJulian Elischer 531e0d898b4SJulian Elischer count= 0; 532fed06968SJulian Elischer epp = &fork_list; 533fed06968SJulian Elischer ep = *epp; 534fed06968SJulian Elischer while (ep) { 535fed06968SJulian Elischer if (ep->function == function) { 536fed06968SJulian Elischer *epp = ep->next; 537fed06968SJulian Elischer free(ep, M_TEMP); 538fed06968SJulian Elischer count++; 539fed06968SJulian Elischer } else { 540fed06968SJulian Elischer epp = &ep->next; 541fed06968SJulian Elischer } 542fed06968SJulian Elischer ep = *epp; 543fed06968SJulian Elischer } 544e0d898b4SJulian Elischer return (count); 545fed06968SJulian Elischer } 546