Commit | Line | Data |
---|---|---|
e8109af3 | 1 | /* kern_fork.c 6.4 84/07/14 */ |
50108d5c SL |
2 | |
3 | #include "../machine/reg.h" | |
4 | #include "../machine/pte.h" | |
5 | #include "../machine/psl.h" | |
6 | ||
7 | #include "../h/param.h" | |
8 | #include "../h/systm.h" | |
9 | #include "../h/map.h" | |
10 | #include "../h/dir.h" | |
11 | #include "../h/user.h" | |
12 | #include "../h/kernel.h" | |
13 | #include "../h/proc.h" | |
14 | #include "../h/inode.h" | |
15 | #include "../h/seg.h" | |
16 | #include "../h/vm.h" | |
17 | #include "../h/text.h" | |
18 | #include "../h/file.h" | |
19 | #include "../h/acct.h" | |
20 | #include "../h/quota.h" | |
21 | ||
22 | /* | |
23 | * fork system call. | |
24 | */ | |
25 | fork() | |
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 | ||
37 | vfork() | |
38 | { | |
39 | ||
40 | fork1(1); | |
41 | } | |
42 | ||
43 | fork1(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 | ||
85 | out: | |
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 | */ | |
94 | newproc(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 | 109 | retry: |
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; | |
124 | again: | |
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 | } |