Commit | Line | Data |
---|---|---|
a81e9a81 | 1 | /* kern_synch.c 4.18 82/08/10 */ |
a379cce8 BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
5 | #include "../h/dir.h" | |
6 | #include "../h/user.h" | |
7 | #include "../h/proc.h" | |
8 | #include "../h/file.h" | |
9 | #include "../h/inode.h" | |
10 | #include "../h/vm.h" | |
11 | #include "../h/pte.h" | |
87d0f32e | 12 | #include "../h/inline.h" |
534d9295 | 13 | #include "../h/mtpr.h" |
9c25520d | 14 | #include "../h/quota.h" |
a379cce8 BJ |
15 | |
16 | #define SQSIZE 0100 /* Must be power of 2 */ | |
17 | #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) | |
18 | struct proc *slpque[SQSIZE]; | |
19 | ||
20 | /* | |
21 | * Give up the processor till a wakeup occurs | |
22 | * on chan, at which time the process | |
23 | * enters the scheduling queue at priority pri. | |
24 | * The most important effect of pri is that when | |
25 | * pri<=PZERO a signal cannot disturb the sleep; | |
26 | * if pri>PZERO signals will be processed. | |
27 | * Callers of this routine must be prepared for | |
28 | * premature return, and check that the reason for | |
29 | * sleeping has gone away. | |
30 | */ | |
31 | sleep(chan, pri) | |
32 | caddr_t chan; | |
33 | { | |
e5df4be8 | 34 | register struct proc *rp, **hp; |
6fdc0335 | 35 | register s; |
a379cce8 BJ |
36 | |
37 | rp = u.u_procp; | |
38 | s = spl6(); | |
39 | if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) | |
40 | panic("sleep"); | |
a379cce8 BJ |
41 | rp->p_wchan = chan; |
42 | rp->p_slptime = 0; | |
43 | rp->p_pri = pri; | |
e5df4be8 BJ |
44 | hp = &slpque[HASH(chan)]; |
45 | rp->p_link = *hp; | |
46 | *hp = rp; | |
18a4549b BJ |
47 | if (pri > PZERO) { |
48 | if (ISSIG(rp)) { | |
e5df4be8 BJ |
49 | if (rp->p_wchan) |
50 | unsleep(rp); | |
a379cce8 | 51 | rp->p_stat = SRUN; |
81263dba | 52 | (void) spl0(); |
a379cce8 BJ |
53 | goto psig; |
54 | } | |
e5df4be8 BJ |
55 | if (rp->p_wchan == 0) |
56 | goto out; | |
57 | rp->p_stat = SSLEEP; | |
81263dba | 58 | (void) spl0(); |
a379cce8 | 59 | swtch(); |
18a4549b | 60 | if (ISSIG(rp)) |
a379cce8 BJ |
61 | goto psig; |
62 | } else { | |
6fdc0335 | 63 | rp->p_stat = SSLEEP; |
81263dba | 64 | (void) spl0(); |
a379cce8 BJ |
65 | swtch(); |
66 | } | |
e5df4be8 | 67 | out: |
a379cce8 BJ |
68 | splx(s); |
69 | return; | |
70 | ||
71 | /* | |
72 | * If priority was low (>PZERO) and | |
18a4549b BJ |
73 | * there has been a signal, execute non-local goto through |
74 | * u.u_qsav, aborting the system call in progress (see trap.c) | |
75 | * (or finishing a tsleep, see below) | |
a379cce8 BJ |
76 | */ |
77 | psig: | |
a379cce8 | 78 | longjmp(u.u_qsav); |
a379cce8 BJ |
79 | /*NOTREACHED*/ |
80 | } | |
81 | ||
a7bf190d BJ |
82 | /* |
83 | * Sleep on chan at pri. | |
84 | * Return in no more than the indicated number of seconds. | |
85 | * (If seconds==0, no timeout implied) | |
86 | * Return TS_OK if chan was awakened normally | |
87 | * TS_TIME if timeout occurred | |
88 | * TS_SIG if asynchronous signal occurred | |
18a4549b BJ |
89 | * |
90 | * SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN | |
91 | * INCREMENT IN MILLISECONDS! | |
a7bf190d BJ |
92 | */ |
93 | tsleep(chan, pri, seconds) | |
18a4549b BJ |
94 | caddr_t chan; |
95 | int pri, seconds; | |
a7bf190d BJ |
96 | { |
97 | label_t lqsav; | |
98 | register struct proc *pp; | |
9c25520d | 99 | register sec, n, rval, sov; |
a7bf190d BJ |
100 | |
101 | pp = u.u_procp; | |
b05a921d | 102 | n = spl7(); |
a7bf190d BJ |
103 | sec = 0; |
104 | rval = 0; | |
9c25520d | 105 | sov = 0; |
a7bf190d | 106 | if (pp->p_clktim && pp->p_clktim<seconds) |
9c25520d RE |
107 | if (pri > PZERO) |
108 | seconds = 0; | |
109 | else | |
110 | sov++; | |
a7bf190d BJ |
111 | if (seconds) { |
112 | pp->p_flag |= STIMO; | |
06f9e714 | 113 | sec = pp->p_clktim-seconds; |
a7bf190d BJ |
114 | pp->p_clktim = seconds; |
115 | } | |
116 | bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); | |
117 | if (setjmp(u.u_qsav)) | |
118 | rval = TS_SIG; | |
119 | else { | |
120 | sleep(chan, pri); | |
121 | if ((pp->p_flag&STIMO)==0 && seconds) | |
122 | rval = TS_TIME; | |
123 | else | |
124 | rval = TS_OK; | |
125 | } | |
126 | pp->p_flag &= ~STIMO; | |
127 | bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); | |
06f9e714 BJ |
128 | if (sec > 0) |
129 | pp->p_clktim += sec; | |
9c25520d RE |
130 | else if (sov) { |
131 | if ((pp->p_clktim += sec) <= 0) { | |
132 | pp->p_clktim = 0; | |
133 | psignal(pp, SIGALRM); | |
134 | } | |
135 | } else | |
06f9e714 | 136 | pp->p_clktim = 0; |
a7bf190d | 137 | splx(n); |
18a4549b | 138 | return (rval); |
a7bf190d BJ |
139 | } |
140 | ||
87d0f32e BJ |
141 | /* |
142 | * Remove a process from its wait queue | |
143 | */ | |
144 | unsleep(p) | |
18a4549b | 145 | register struct proc *p; |
87d0f32e BJ |
146 | { |
147 | register struct proc **hp; | |
148 | register s; | |
149 | ||
150 | s = spl6(); | |
151 | if (p->p_wchan) { | |
152 | hp = &slpque[HASH(p->p_wchan)]; | |
153 | while (*hp != p) | |
154 | hp = &(*hp)->p_link; | |
155 | *hp = p->p_link; | |
156 | p->p_wchan = 0; | |
157 | } | |
158 | splx(s); | |
159 | } | |
160 | ||
a379cce8 BJ |
161 | /* |
162 | * Wake up all processes sleeping on chan. | |
163 | */ | |
164 | wakeup(chan) | |
18a4549b | 165 | register caddr_t chan; |
a379cce8 | 166 | { |
e5df4be8 | 167 | register struct proc *p, **q, **h; |
a379cce8 BJ |
168 | int s; |
169 | ||
170 | s = spl6(); | |
e5df4be8 | 171 | h = &slpque[HASH(chan)]; |
a379cce8 | 172 | restart: |
e5df4be8 | 173 | for (q = h; p = *q; ) { |
87d0f32e | 174 | if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) |
a379cce8 | 175 | panic("wakeup"); |
6fdc0335 | 176 | if (p->p_wchan==chan) { |
a379cce8 | 177 | p->p_wchan = 0; |
e5df4be8 | 178 | *q = p->p_link; |
a379cce8 | 179 | p->p_slptime = 0; |
87d0f32e BJ |
180 | if (p->p_stat == SSLEEP) { |
181 | /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ | |
182 | p->p_stat = SRUN; | |
c74c8a79 | 183 | if (p->p_flag & SLOAD) |
87d0f32e | 184 | setrq(p); |
18a4549b | 185 | if (p->p_pri < curpri) { |
87d0f32e | 186 | runrun++; |
534d9295 BJ |
187 | aston(); |
188 | } | |
7eb2e67e BJ |
189 | if ((p->p_flag&SLOAD) == 0) { |
190 | if (runout != 0) { | |
191 | runout = 0; | |
192 | wakeup((caddr_t)&runout); | |
193 | } | |
194 | wantin++; | |
87d0f32e BJ |
195 | } |
196 | /* END INLINE EXPANSION */ | |
e5df4be8 | 197 | goto restart; |
a379cce8 | 198 | } |
e5df4be8 BJ |
199 | } else |
200 | q = &p->p_link; | |
a379cce8 BJ |
201 | } |
202 | splx(s); | |
203 | } | |
204 | ||
a379cce8 BJ |
205 | /* |
206 | * Initialize the (doubly-linked) run queues | |
207 | * to be empty. | |
208 | */ | |
209 | rqinit() | |
210 | { | |
211 | register int i; | |
212 | ||
213 | for (i = 0; i < NQS; i++) | |
214 | qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; | |
215 | } | |
a379cce8 BJ |
216 | |
217 | /* | |
218 | * Set the process running; | |
219 | * arrange for it to be swapped in if necessary. | |
220 | */ | |
221 | setrun(p) | |
18a4549b | 222 | register struct proc *p; |
a379cce8 | 223 | { |
18a4549b | 224 | register int s; |
a379cce8 BJ |
225 | |
226 | s = spl6(); | |
227 | switch (p->p_stat) { | |
228 | ||
229 | case 0: | |
230 | case SWAIT: | |
231 | case SRUN: | |
232 | case SZOMB: | |
233 | default: | |
234 | panic("setrun"); | |
235 | ||
6fdc0335 | 236 | case SSTOP: |
a379cce8 | 237 | case SSLEEP: |
87d0f32e | 238 | unsleep(p); /* e.g. when sending signals */ |
a379cce8 BJ |
239 | break; |
240 | ||
241 | case SIDL: | |
a379cce8 BJ |
242 | break; |
243 | } | |
244 | p->p_stat = SRUN; | |
245 | if (p->p_flag & SLOAD) | |
246 | setrq(p); | |
247 | splx(s); | |
18a4549b | 248 | if (p->p_pri < curpri) { |
a379cce8 | 249 | runrun++; |
534d9295 BJ |
250 | aston(); |
251 | } | |
7eb2e67e | 252 | if ((p->p_flag&SLOAD) == 0) { |
18a4549b | 253 | if (runout != 0) { |
7eb2e67e BJ |
254 | runout = 0; |
255 | wakeup((caddr_t)&runout); | |
256 | } | |
257 | wantin++; | |
a379cce8 BJ |
258 | } |
259 | } | |
260 | ||
261 | /* | |
262 | * Set user priority. | |
263 | * The rescheduling flag (runrun) | |
264 | * is set if the priority is better | |
265 | * than the currently running process. | |
266 | */ | |
267 | setpri(pp) | |
18a4549b | 268 | register struct proc *pp; |
a379cce8 | 269 | { |
18a4549b | 270 | register int p; |
a379cce8 | 271 | |
16a64baa | 272 | p = (pp->p_cpu & 0377)/4; |
598563b5 | 273 | p += PUSER + 2*(pp->p_nice - NZERO); |
9afea775 BJ |
274 | if (pp->p_rssize > pp->p_maxrss && freemem < desfree) |
275 | p += 2*4; /* effectively, nice(4) */ | |
18a4549b | 276 | if (p > 127) |
a379cce8 | 277 | p = 127; |
18a4549b | 278 | if (p < curpri) { |
a379cce8 | 279 | runrun++; |
a51a6e74 BJ |
280 | aston(); |
281 | } | |
a379cce8 | 282 | pp->p_usrpri = p; |
18a4549b | 283 | return (p); |
a379cce8 BJ |
284 | } |
285 | ||
286 | /* | |
287 | * Create a new process-- the internal version of | |
288 | * sys fork. | |
289 | * It returns 1 in the new process, 0 in the old. | |
290 | */ | |
291 | newproc(isvfork) | |
18a4549b | 292 | int isvfork; |
a379cce8 BJ |
293 | { |
294 | register struct proc *p; | |
295 | register struct proc *rpp, *rip; | |
296 | register int n; | |
a81e9a81 | 297 | register struct file *fp; |
a379cce8 BJ |
298 | |
299 | p = NULL; | |
300 | /* | |
301 | * First, just locate a slot for a process | |
302 | * and copy the useful info from this process into it. | |
303 | * The panic "cannot happen" because fork has already | |
304 | * checked for the existence of a slot. | |
305 | */ | |
306 | retry: | |
307 | mpid++; | |
18a4549b | 308 | if (mpid >= 30000) { |
a379cce8 BJ |
309 | mpid = 0; |
310 | goto retry; | |
311 | } | |
18a4549b BJ |
312 | for (rpp = proc; rpp < procNPROC; rpp++) { |
313 | if (rpp->p_stat == NULL && p==NULL) | |
a379cce8 BJ |
314 | p = rpp; |
315 | if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) | |
316 | goto retry; | |
317 | } | |
18a4549b | 318 | if ((rpp = p) == NULL) |
a379cce8 BJ |
319 | panic("no procs"); |
320 | ||
321 | /* | |
18a4549b | 322 | * Make a proc table entry for the new process. |
a379cce8 | 323 | */ |
a379cce8 | 324 | rip = u.u_procp; |
9c25520d RE |
325 | #ifdef QUOTA |
326 | (rpp->p_quota = rip->p_quota)->q_cnt++; | |
327 | #endif | |
a379cce8 BJ |
328 | rpp->p_stat = SIDL; |
329 | rpp->p_clktim = 0; | |
7ac93404 | 330 | rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); |
a379cce8 BJ |
331 | if (isvfork) { |
332 | rpp->p_flag |= SVFORK; | |
333 | rpp->p_ndx = rip->p_ndx; | |
334 | } else | |
335 | rpp->p_ndx = rpp - proc; | |
336 | rpp->p_uid = rip->p_uid; | |
337 | rpp->p_pgrp = rip->p_pgrp; | |
338 | rpp->p_nice = rip->p_nice; | |
339 | rpp->p_textp = isvfork ? 0 : rip->p_textp; | |
340 | rpp->p_pid = mpid; | |
341 | rpp->p_ppid = rip->p_pid; | |
87d0f32e | 342 | rpp->p_pptr = rip; |
9c25520d RE |
343 | rpp->p_osptr = rip->p_cptr; |
344 | if (rip->p_cptr) | |
345 | rip->p_cptr->p_ysptr = rpp; | |
346 | rpp->p_ysptr = NULL; | |
347 | rpp->p_cptr = NULL; | |
348 | rip->p_cptr = rpp; | |
a379cce8 BJ |
349 | rpp->p_time = 0; |
350 | rpp->p_cpu = 0; | |
87d0f32e BJ |
351 | rpp->p_siga0 = rip->p_siga0; |
352 | rpp->p_siga1 = rip->p_siga1; | |
353 | /* take along any pending signals, like stops? */ | |
a379cce8 BJ |
354 | if (isvfork) { |
355 | rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; | |
356 | rpp->p_szpt = clrnd(ctopt(UPAGES)); | |
357 | forkstat.cntvfork++; | |
358 | forkstat.sizvfork += rip->p_dsize + rip->p_ssize; | |
359 | } else { | |
360 | rpp->p_tsize = rip->p_tsize; | |
361 | rpp->p_dsize = rip->p_dsize; | |
362 | rpp->p_ssize = rip->p_ssize; | |
363 | rpp->p_szpt = rip->p_szpt; | |
364 | forkstat.cntfork++; | |
365 | forkstat.sizfork += rip->p_dsize + rip->p_ssize; | |
366 | } | |
367 | rpp->p_rssize = 0; | |
f3ba10a3 | 368 | rpp->p_maxrss = rip->p_maxrss; |
a379cce8 BJ |
369 | rpp->p_wchan = 0; |
370 | rpp->p_slptime = 0; | |
dd808ba3 BJ |
371 | rpp->p_pctcpu = 0; |
372 | rpp->p_cpticks = 0; | |
a379cce8 BJ |
373 | n = PIDHASH(rpp->p_pid); |
374 | p->p_idhash = pidhash[n]; | |
375 | pidhash[n] = rpp - proc; | |
18a4549b | 376 | multprog++; |
a379cce8 BJ |
377 | |
378 | /* | |
18a4549b | 379 | * Increase reference counts on shared objects. |
a379cce8 | 380 | */ |
a81e9a81 SL |
381 | for (n = 0; n < NOFILE; n++) { |
382 | fp = u.u_ofile[n]; | |
383 | if (fp == NULL) | |
384 | continue; | |
385 | fp->f_count++; | |
386 | if (u.u_pofile[n]&RDLOCK) | |
387 | fp->f_inode->i_rdlockc++; | |
388 | if (u.u_pofile[n]&WRLOCK) | |
389 | fp->f_inode->i_wrlockc++; | |
390 | } | |
a379cce8 BJ |
391 | u.u_cdir->i_count++; |
392 | if (u.u_rdir) | |
393 | u.u_rdir->i_count++; | |
18a4549b | 394 | |
a379cce8 BJ |
395 | /* |
396 | * Partially simulate the environment | |
397 | * of the new process so that when it is actually | |
398 | * created (by copying) it will look right. | |
18a4549b BJ |
399 | * This begins the section where we must prevent the parent |
400 | * from being swapped. | |
a379cce8 | 401 | */ |
18a4549b | 402 | rip->p_flag |= SKEEP; |
a379cce8 BJ |
403 | if (procdup(rpp, isvfork)) |
404 | return (1); | |
405 | ||
18a4549b BJ |
406 | /* |
407 | * Make child runnable and add to run queue. | |
408 | */ | |
934e4ecf | 409 | (void) spl6(); |
a379cce8 BJ |
410 | rpp->p_stat = SRUN; |
411 | setrq(rpp); | |
283cac0a | 412 | (void) spl0(); |
18a4549b BJ |
413 | |
414 | /* | |
415 | * Cause child to take a non-local goto as soon as it runs. | |
416 | * On older systems this was done with SSWAP bit in proc | |
417 | * table; on VAX we use u.u_pcb.pcb_sswap so don't need | |
418 | * to do rpp->p_flag |= SSWAP. Actually do nothing here. | |
419 | */ | |
a379cce8 | 420 | /* rpp->p_flag |= SSWAP; */ |
18a4549b BJ |
421 | |
422 | /* | |
423 | * Now can be swapped. | |
424 | */ | |
a379cce8 | 425 | rip->p_flag &= ~SKEEP; |
18a4549b BJ |
426 | |
427 | /* | |
428 | * If vfork make chain from parent process to child | |
429 | * (where virtal memory is temporarily). Wait for | |
430 | * child to finish, steal virtual memory back, | |
431 | * and wakeup child to let it die. | |
432 | */ | |
a379cce8 BJ |
433 | if (isvfork) { |
434 | u.u_procp->p_xlink = rpp; | |
435 | u.u_procp->p_flag |= SNOVM; | |
436 | while (rpp->p_flag & SVFORK) | |
437 | sleep((caddr_t)rpp, PZERO - 1); | |
438 | if ((rpp->p_flag & SLOAD) == 0) | |
439 | panic("newproc vfork"); | |
440 | uaccess(rpp, Vfmap, &vfutl); | |
441 | u.u_procp->p_xlink = 0; | |
442 | vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); | |
a379cce8 BJ |
443 | u.u_procp->p_flag &= ~SNOVM; |
444 | rpp->p_ndx = rpp - proc; | |
445 | rpp->p_flag |= SVFDONE; | |
446 | wakeup((caddr_t)rpp); | |
447 | } | |
18a4549b BJ |
448 | |
449 | /* | |
450 | * 0 return means parent. | |
451 | */ | |
a379cce8 BJ |
452 | return (0); |
453 | } |