* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)kern_fork.c 7.10 (Berkeley) %G%
#include "../ufs/quota.h"
if (swpexpand(u
.u_dsize
, u
.u_ssize
, &u
.u_cdmap
, &u
.u_csmap
) == 0) {
register struct proc
*p1
, *p2
;
for (p1
= allproc
; p1
; p1
= p1
->p_nxt
)
if (p1
->p_uid
== u
.u_uid
)
for (p1
= zombproc
; p1
; p1
= p1
->p_nxt
)
if (p1
->p_uid
== u
.u_uid
)
* not su and too many procs owned; or
* not su and would take last slot.
if (p2
==NULL
|| (u
.u_uid
!=0 && (p2
->p_nxt
== NULL
|| a
>MAXUPRC
))) {
(void) vsexpand((size_t)0, &u
.u_cdmap
, 1);
(void) vsexpand((size_t)0, &u
.u_csmap
, 1);
u
.u_r
.r_val1
= p1
->p_pid
;
u
.u_r
.r_val2
= 1; /* child */
u
.u_r
.r_val1
= p2
->p_pid
;
* Create a new process-- the internal version of
* It returns 1 in the new process, 0 in the old.
register struct proc
*rpp
, *rip
;
register struct file
*fp
;
static int pidchecked
= 0;
* First, just locate a slot for a process
* and copy the useful info from this process into it.
* The panic "cannot happen" because fork has already
* checked for the existence of a slot.
if (mpid
>= pidchecked
) {
* Scan the proc table to check whether this pid
* is in use. Remember the lowest pid that's greater
* than mpid, so we can avoid checking for a while.
for (; rpp
!= NULL
; rpp
= rpp
->p_nxt
) {
if (rpp
->p_pid
== mpid
|| rpp
->p_pgrp
->pg_id
== mpid
) {
if (rpp
->p_pid
> mpid
&& pidchecked
> rpp
->p_pid
)
if (rpp
->p_pgrp
->pg_id
> mpid
&&
pidchecked
> rpp
->p_pgrp
->pg_id
)
pidchecked
= rpp
->p_pgrp
->pg_id
;
if ((rpp
= freeproc
) == NULL
)
freeproc
= rpp
->p_nxt
; /* off freeproc */
rpp
->p_nxt
= allproc
; /* onto allproc */
rpp
->p_nxt
->p_prev
= &rpp
->p_nxt
; /* (allproc is never NULL) */
* Make a proc table entry for the new process.
rpp
->p_quota
= rip
->p_quota
;
rpp
->p_ckey
= rip
->p_ckey
;
timerclear(&rpp
->p_realtimer
.it_value
);
rpp
->p_flag
= SLOAD
| (rip
->p_flag
& (SPAGV
|SCTTY
));
rpp
->p_ruid
= rip
->p_ruid
;
rpp
->p_rgid
= rip
->p_rgid
;
rpp
->p_pgrp
= rip
->p_pgrp
;
rpp
->p_pgrpnxt
= rip
->p_pgrpnxt
;
rpp
->p_nice
= rip
->p_nice
;
rpp
->p_textp
= isvfork
? 0 : rip
->p_textp
;
rpp
->p_ppid
= rip
->p_pid
;
rpp
->p_osptr
= rip
->p_cptr
;
rip
->p_cptr
->p_ysptr
= rpp
;
rpp
->p_sigmask
= rip
->p_sigmask
;
rpp
->p_sigcatch
= rip
->p_sigcatch
;
rpp
->p_sigignore
= rip
->p_sigignore
;
/* take along any pending signals like stops? */
rpp
->p_tsize
= rpp
->p_dsize
= rpp
->p_ssize
= 0;
rpp
->p_szpt
= clrnd(ctopt(UPAGES
));
forkstat
.sizvfork
+= rip
->p_dsize
+ rip
->p_ssize
;
rpp
->p_tsize
= rip
->p_tsize
;
rpp
->p_dsize
= rip
->p_dsize
;
rpp
->p_ssize
= rip
->p_ssize
;
rpp
->p_szpt
= rip
->p_szpt
;
forkstat
.sizfork
+= rip
->p_dsize
+ rip
->p_ssize
;
if ((rpp
->p_tracep
= rip
->p_tracep
) != NULL
)
rpp
->p_traceflag
= rip
->p_traceflag
;
rpp
->p_maxrss
= rip
->p_maxrss
;
rpp
->p_idhash
= pidhash
[n
];
* Increase reference counts on shared objects.
for (n
= 0; n
<= u
.u_lastfile
; n
++) {
* This begins the section where we must prevent the parent
if (procdup(rpp
, isvfork
))
* Make child runnable and add to run queue.
* Cause child to take a non-local goto as soon as it runs.
* On older systems this was done with SSWAP bit in proc
* table; on VAX we use u.u_pcb.pcb_sswap so don't need
* to do rpp->p_flag |= SSWAP. Actually do nothing here.
/* rpp->p_flag |= SSWAP; */
* If vfork make chain from parent process to child
* (where virtal memory is temporarily). Wait for
* child to finish, steal virtual memory back,
* and wakeup child to let it die.
u
.u_procp
->p_xlink
= rpp
;
u
.u_procp
->p_flag
|= SNOVM
;
while (rpp
->p_flag
& SVFORK
)
sleep((caddr_t
)rpp
, PZERO
- 1);
if ((rpp
->p_flag
& SLOAD
) == 0)
uaccess(rpp
, Vfmap
, &vfutl
);
vpassvm(rpp
, u
.u_procp
, &vfutl
, &u
, Vfmap
);
u
.u_procp
->p_flag
&= ~SNOVM
;