1: /*
2: * Copyright (c) 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)kern_fork.c 1.6 (2.11BSD) 1999/8/11
7: */
8:
9: #include "param.h"
10: #include "../machine/reg.h"
11: #include "../machine/seg.h"
12:
13: #include "systm.h"
14: #include "map.h"
15: #include "user.h"
16: #include "proc.h"
17: #include "inode.h"
18: #include "acct.h"
19: #include "file.h"
20: #include "vm.h"
21: #include "text.h"
22: #include "kernel.h"
23: #ifdef QUOTA
24: #include "quota.h"
25: #endif
26:
27: /*
28: * fork --
29: * fork system call
30: */
31: fork()
32: {
33: fork1(0);
34: }
35:
36: /*
37: * vfork --
38: * vfork system call, fast version of fork
39: */
40: vfork()
41: {
42: fork1(1);
43: }
44:
45: fork1(isvfork)
46: {
47: register int a;
48: register struct proc *p1, *p2;
49:
50: a = 0;
51: if (u.u_uid != 0) {
52: for (p1 = allproc; p1; p1 = p1->p_nxt)
53: if (p1->p_uid == u.u_uid)
54: a++;
55: for (p1 = zombproc; p1; p1 = p1->p_nxt)
56: if (p1->p_uid == u.u_uid)
57: a++;
58: }
59: /*
60: * Disallow if
61: * No processes at all;
62: * not su and too many procs owned; or
63: * not su and would take last slot.
64: */
65: p2 = freeproc;
66: if (p2==NULL)
67: tablefull("proc");
68: if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) {
69: u.u_error = EAGAIN;
70: goto out;
71: }
72: p1 = u.u_procp;
73: if (newproc(isvfork)) {
74: u.u_r.r_val1 = p1->p_pid;
75: #ifndef pdp11
76: u.u_r.r_val2 = 1; /* child */
77: #endif
78: u.u_start = time.tv_sec;
79: /* set forked but preserve suid/gid state */
80: u.u_acflag = AFORK | (u.u_acflag & ASUGID);
81: bzero(&u.u_ru, sizeof(u.u_ru));
82: bzero(&u.u_cru, sizeof(u.u_cru));
83: return;
84: }
85: u.u_r.r_val1 = p2->p_pid;
86:
87: out:
88: #ifdef pdp11 /* see libc/pdp/sys/fork.s */
89: u.u_ar0[R7] += NBPW;
90: #else
91: u.u_r.r_val2 = 0;
92: #endif
93: }
94:
95: /*
96: * newproc --
97: * Create a new process -- the internal version of system call fork.
98: * It returns 1 in the new process, 0 in the old.
99: */
100: newproc(isvfork)
101: int isvfork;
102: {
103: register struct proc *rpp, *rip;
104: register int n;
105: static int pidchecked = 0;
106: struct file *fp;
107: int a1, s;
108: memaddr a[3];
109:
110: /*
111: * First, just locate a slot for a process
112: * and copy the useful info from this process into it.
113: * The panic "cannot happen" because fork has already
114: * checked for the existence of a slot.
115: */
116: mpid++;
117: retry:
118: if (mpid >= 30000) {
119: mpid = 100;
120: pidchecked = 0;
121: }
122: if (mpid >= pidchecked) {
123: int doingzomb = 0;
124:
125: pidchecked = 30000;
126: /*
127: * Scan the proc table to check whether this pid
128: * is in use. Remember the lowest pid that's greater
129: * than mpid, so we can avoid checking for a while.
130: */
131: rpp = allproc;
132: again:
133: for (; rpp != NULL; rpp = rpp->p_nxt) {
134: if (rpp->p_pid == mpid || rpp->p_pgrp == mpid) {
135: mpid++;
136: if (mpid >= pidchecked)
137: goto retry;
138: }
139: if (rpp->p_pid > mpid && pidchecked > rpp->p_pid)
140: pidchecked = rpp->p_pid;
141: if (rpp->p_pgrp > mpid && pidchecked > rpp->p_pgrp)
142: pidchecked = rpp->p_pgrp;
143: }
144: if (!doingzomb) {
145: doingzomb = 1;
146: rpp = zombproc;
147: goto again;
148: }
149: }
150: if ((rpp = freeproc) == NULL)
151: panic("no procs");
152:
153: freeproc = rpp->p_nxt; /* off freeproc */
154:
155: /*
156: * Make a proc table entry for the new process.
157: */
158: rip = u.u_procp;
159: #ifdef QUOTA
160: QUOTAMAP();
161: u.u_quota->q_cnt++;
162: QUOTAUNMAP();
163: #endif
164: rpp->p_stat = SIDL;
165: rpp->p_realtimer.it_value = 0;
166: rpp->p_flag = SLOAD;
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 = rip->p_textp;
171: rpp->p_pid = mpid;
172: rpp->p_ppid = rip->p_pid;
173: rpp->p_pptr = rip;
174: rpp->p_time = 0;
175: rpp->p_cpu = 0;
176: rpp->p_sigmask = rip->p_sigmask;
177: rpp->p_sigcatch = rip->p_sigcatch;
178: rpp->p_sigignore = rip->p_sigignore;
179: /* take along any pending signals like stops? */
180: #ifdef UCB_METER
181: if (isvfork) {
182: forkstat.cntvfork++;
183: forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
184: } else {
185: forkstat.cntfork++;
186: forkstat.sizfork += rip->p_dsize + rip->p_ssize;
187: }
188: #endif
189: rpp->p_wchan = 0;
190: rpp->p_slptime = 0;
191: {
192: struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)];
193:
194: rpp->p_hash = *hash;
195: *hash = rpp;
196: }
197: /*
198: * some shuffling here -- in most UNIX kernels, the allproc assign
199: * is done after grabbing the struct off of the freeproc list. We
200: * wait so that if the clock interrupts us and vmtotal walks allproc
201: * the text pointer isn't garbage.
202: */
203: rpp->p_nxt = allproc; /* onto allproc */
204: rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */
205: rpp->p_prev = &allproc;
206: allproc = rpp;
207:
208: /*
209: * Increase reference counts on shared objects.
210: */
211: for (n = 0; n <= u.u_lastfile; n++) {
212: fp = u.u_ofile[n];
213: if (fp == NULL)
214: continue;
215: fp->f_count++;
216: }
217: if ((rip->p_textp != NULL) && !isvfork) {
218: rip->p_textp->x_count++;
219: rip->p_textp->x_ccount++;
220: }
221: u.u_cdir->i_count++;
222: if (u.u_rdir)
223: u.u_rdir->i_count++;
224:
225: /*
226: * When the longjmp is executed for the new process,
227: * here's where it will resume.
228: */
229: if (setjmp(&u.u_ssave)) {
230: sureg();
231: return(1);
232: }
233:
234: rpp->p_dsize = rip->p_dsize;
235: rpp->p_ssize = rip->p_ssize;
236: rpp->p_daddr = rip->p_daddr;
237: rpp->p_saddr = rip->p_saddr;
238: a1 = rip->p_addr;
239: if (isvfork)
240: a[2] = malloc(coremap,USIZE);
241: else
242: a[2] = malloc3(coremap, rip->p_dsize, rip->p_ssize, USIZE, a);
243:
244: /*
245: * Partially simulate the environment of the new process so that
246: * when it is actually created (by copying) it will look right.
247: */
248: u.u_procp = rpp;
249:
250: /*
251: * If there is not enough core for the new process, swap out the
252: * current process to generate the copy.
253: */
254: if (a[2] == NULL) {
255: rip->p_stat = SIDL;
256: rpp->p_addr = a1;
257: rpp->p_stat = SRUN;
258: swapout(rpp, X_DONTFREE, X_OLDSIZE, X_OLDSIZE);
259: rip->p_stat = SRUN;
260: u.u_procp = rip;
261: }
262: else {
263: /*
264: * There is core, so just copy.
265: */
266: rpp->p_addr = a[2];
267: copy(a1, rpp->p_addr, USIZE);
268: u.u_procp = rip;
269: if (isvfork == 0) {
270: rpp->p_daddr = a[0];
271: copy(rip->p_daddr, rpp->p_daddr, rpp->p_dsize);
272: rpp->p_saddr = a[1];
273: copy(rip->p_saddr, rpp->p_saddr, rpp->p_ssize);
274: }
275: s = splhigh();
276: rpp->p_stat = SRUN;
277: setrq(rpp);
278: splx(s);
279: }
280: rpp->p_flag |= SSWAP;
281: if (isvfork) {
282: /*
283: * Set the parent's sizes to 0, since the child now
284: * has the data and stack.
285: * (If we had to swap, just free parent resources.)
286: * Then wait for the child to finish with it.
287: */
288: if (a[2] == NULL) {
289: mfree(coremap,rip->p_dsize,rip->p_daddr);
290: mfree(coremap,rip->p_ssize,rip->p_saddr);
291: }
292: rip->p_dsize = 0;
293: rip->p_ssize = 0;
294: rip->p_textp = NULL;
295: rpp->p_flag |= SVFORK;
296: rip->p_flag |= SVFPRNT;
297: while (rpp->p_flag & SVFORK)
298: sleep((caddr_t)rpp,PSWP+1);
299: if ((rpp->p_flag & SLOAD) == 0)
300: panic("newproc vfork");
301: u.u_dsize = rip->p_dsize = rpp->p_dsize;
302: rip->p_daddr = rpp->p_daddr;
303: rpp->p_dsize = 0;
304: u.u_ssize = rip->p_ssize = rpp->p_ssize;
305: rip->p_saddr = rpp->p_saddr;
306: rpp->p_ssize = 0;
307: rip->p_textp = rpp->p_textp;
308: rpp->p_textp = NULL;
309: rpp->p_flag |= SVFDONE;
310: wakeup((caddr_t)rip);
311: /* must do estabur if dsize/ssize are different */
312: estabur(u.u_tsize,u.u_dsize,u.u_ssize,u.u_sep,RO);
313: rip->p_flag &= ~SVFPRNT;
314: }
315: return(0);
316: }
Defined functions
fork
defined in line
31; used 2 times
fork1
defined in line
45; used 2 times
vfork
defined in line
40; used 2 times