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