do not depend on having /usr/local/lib/w2a
[unix-history] / usr / src / sys / kern / kern_fork.c
CommitLineData
94368568 1/* kern_fork.c 6.5 84/08/29 */
50108d5c
SL
2
3#include "../machine/reg.h"
4#include "../machine/pte.h"
5#include "../machine/psl.h"
6
94368568
JB
7#include "param.h"
8#include "systm.h"
9#include "map.h"
10#include "dir.h"
11#include "user.h"
12#include "kernel.h"
13#include "proc.h"
14#include "inode.h"
15#include "seg.h"
16#include "vm.h"
17#include "text.h"
18#include "file.h"
19#include "acct.h"
20#include "quota.h"
50108d5c
SL
21
22/*
23 * fork system call.
24 */
25fork()
26{
27
28 u.u_cdmap = zdmap;
29 u.u_csmap = zdmap;
30 if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
31 u.u_r.r_val2 = 0;
32 return;
33 }
34 fork1(0);
35}
36
37vfork()
38{
39
40 fork1(1);
41}
42
43fork1(isvfork)
44 int isvfork;
45{
46 register struct proc *p1, *p2;
47 register a;
48
49 a = 0;
1d348849
MK
50 if (u.u_uid != 0) {
51 for (p1 = allproc; p1; p1 = p1->p_nxt)
52 if (p1->p_uid == u.u_uid)
53 a++;
54 for (p1 = zombproc; p1; p1 = p1->p_nxt)
55 if (p1->p_uid == u.u_uid)
50108d5c 56 a++;
50108d5c
SL
57 }
58 /*
59 * Disallow if
60 * No processes at all;
61 * not su and too many procs owned; or
62 * not su and would take last slot.
63 */
1d348849 64 p2 = freeproc;
50108d5c
SL
65 if (p2==NULL)
66 tablefull("proc");
1d348849 67 if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) {
50108d5c
SL
68 u.u_error = EAGAIN;
69 if (!isvfork) {
70 (void) vsexpand(0, &u.u_cdmap, 1);
71 (void) vsexpand(0, &u.u_csmap, 1);
72 }
73 goto out;
74 }
75 p1 = u.u_procp;
76 if (newproc(isvfork)) {
77 u.u_r.r_val1 = p1->p_pid;
78 u.u_r.r_val2 = 1; /* child */
e8109af3 79 u.u_start = time;
50108d5c
SL
80 u.u_acflag = AFORK;
81 return;
82 }
83 u.u_r.r_val1 = p2->p_pid;
84
85out:
86 u.u_r.r_val2 = 0;
87}
88
89/*
90 * Create a new process-- the internal version of
91 * sys fork.
92 * It returns 1 in the new process, 0 in the old.
93 */
94newproc(isvfork)
95 int isvfork;
96{
50108d5c
SL
97 register struct proc *rpp, *rip;
98 register int n;
99 register struct file *fp;
1d348849 100 static int pidchecked = 0;
50108d5c 101
50108d5c
SL
102 /*
103 * First, just locate a slot for a process
104 * and copy the useful info from this process into it.
105 * The panic "cannot happen" because fork has already
106 * checked for the existence of a slot.
107 */
50108d5c 108 mpid++;
1d348849 109retry:
50108d5c 110 if (mpid >= 30000) {
1d348849
MK
111 mpid = 100;
112 pidchecked = 0;
50108d5c 113 }
1d348849
MK
114 if (mpid >= pidchecked) {
115 int doingzomb = 0;
e9539440 116
1d348849
MK
117 pidchecked = 30000;
118 /*
119 * Scan the proc table to check whether this pid
120 * is in use. Remember the lowest pid that's greater
121 * than mpid, so we can avoid checking for a while.
122 */
123 rpp = allproc;
124again:
125 for (; rpp != NULL; rpp = rpp->p_nxt) {
e9539440 126 if (rpp->p_pid == mpid || rpp->p_pgrp == mpid) {
1d348849
MK
127 mpid++;
128 if (mpid >= pidchecked)
129 goto retry;
130 }
e9539440 131 if (rpp->p_pid > mpid && pidchecked > rpp->p_pid)
1d348849 132 pidchecked = rpp->p_pid;
e9539440 133 if (rpp->p_pgrp > mpid && pidchecked > rpp->p_pgrp)
1d348849
MK
134 pidchecked = rpp->p_pgrp;
135 }
136 if (!doingzomb) {
137 doingzomb = 1;
138 rpp = zombproc;
139 goto again;
140 }
50108d5c 141 }
1d348849 142 if ((rpp = freeproc) == NULL)
50108d5c
SL
143 panic("no procs");
144
1d348849
MK
145 freeproc = rpp->p_nxt; /* off freeproc */
146 rpp->p_nxt = allproc; /* onto allproc */
147 rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */
148 rpp->p_prev = &allproc;
149 allproc = rpp;
150
50108d5c
SL
151 /*
152 * Make a proc table entry for the new process.
153 */
154 rip = u.u_procp;
155#ifdef QUOTA
156 rpp->p_quota = rip->p_quota;
157 rpp->p_quota->q_cnt++;
158#endif
159 rpp->p_stat = SIDL;
160 timerclear(&rpp->p_realtimer.it_value);
dd012d1e 161 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG));
50108d5c
SL
162 if (isvfork) {
163 rpp->p_flag |= SVFORK;
164 rpp->p_ndx = rip->p_ndx;
165 } else
166 rpp->p_ndx = rpp - proc;
167 rpp->p_uid = rip->p_uid;
168 rpp->p_pgrp = rip->p_pgrp;
169 rpp->p_nice = rip->p_nice;
170 rpp->p_textp = isvfork ? 0 : rip->p_textp;
171 rpp->p_pid = mpid;
172 rpp->p_ppid = rip->p_pid;
173 rpp->p_pptr = rip;
174 rpp->p_osptr = rip->p_cptr;
175 if (rip->p_cptr)
176 rip->p_cptr->p_ysptr = rpp;
177 rpp->p_ysptr = NULL;
178 rpp->p_cptr = NULL;
179 rip->p_cptr = rpp;
180 rpp->p_time = 0;
181 rpp->p_cpu = 0;
dd012d1e
SL
182 rpp->p_sigmask = rip->p_sigmask;
183 rpp->p_sigcatch = rip->p_sigcatch;
184 rpp->p_sigignore = rip->p_sigignore;
185 /* take along any pending signals like stops? */
50108d5c
SL
186 if (isvfork) {
187 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
188 rpp->p_szpt = clrnd(ctopt(UPAGES));
189 forkstat.cntvfork++;
190 forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
191 } else {
192 rpp->p_tsize = rip->p_tsize;
193 rpp->p_dsize = rip->p_dsize;
194 rpp->p_ssize = rip->p_ssize;
195 rpp->p_szpt = rip->p_szpt;
196 forkstat.cntfork++;
197 forkstat.sizfork += rip->p_dsize + rip->p_ssize;
198 }
199 rpp->p_rssize = 0;
200 rpp->p_maxrss = rip->p_maxrss;
201 rpp->p_wchan = 0;
202 rpp->p_slptime = 0;
203 rpp->p_pctcpu = 0;
204 rpp->p_cpticks = 0;
205 n = PIDHASH(rpp->p_pid);
1d348849 206 rpp->p_idhash = pidhash[n];
50108d5c
SL
207 pidhash[n] = rpp - proc;
208 multprog++;
209
210 /*
211 * Increase reference counts on shared objects.
212 */
213 for (n = 0; n < NOFILE; n++) {
214 fp = u.u_ofile[n];
215 if (fp == NULL)
216 continue;
217 fp->f_count++;
50108d5c
SL
218 }
219 u.u_cdir->i_count++;
220 if (u.u_rdir)
221 u.u_rdir->i_count++;
222
223 /*
50108d5c
SL
224 * This begins the section where we must prevent the parent
225 * from being swapped.
226 */
227 rip->p_flag |= SKEEP;
228 if (procdup(rpp, isvfork))
229 return (1);
230
231 /*
232 * Make child runnable and add to run queue.
233 */
234 (void) spl6();
235 rpp->p_stat = SRUN;
236 setrq(rpp);
237 (void) spl0();
238
239 /*
240 * Cause child to take a non-local goto as soon as it runs.
241 * On older systems this was done with SSWAP bit in proc
242 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
243 * to do rpp->p_flag |= SSWAP. Actually do nothing here.
244 */
245 /* rpp->p_flag |= SSWAP; */
246
247 /*
248 * Now can be swapped.
249 */
250 rip->p_flag &= ~SKEEP;
251
252 /*
253 * If vfork make chain from parent process to child
254 * (where virtal memory is temporarily). Wait for
255 * child to finish, steal virtual memory back,
256 * and wakeup child to let it die.
257 */
258 if (isvfork) {
259 u.u_procp->p_xlink = rpp;
260 u.u_procp->p_flag |= SNOVM;
261 while (rpp->p_flag & SVFORK)
262 sleep((caddr_t)rpp, PZERO - 1);
263 if ((rpp->p_flag & SLOAD) == 0)
264 panic("newproc vfork");
265 uaccess(rpp, Vfmap, &vfutl);
266 u.u_procp->p_xlink = 0;
267 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
268 u.u_procp->p_flag &= ~SNOVM;
269 rpp->p_ndx = rpp - proc;
270 rpp->p_flag |= SVFDONE;
271 wakeup((caddr_t)rpp);
272 }
273
274 /*
275 * 0 return means parent.
276 */
277 return (0);
278}