use rdwri()
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
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))
18struct 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 */
31sleep(chan, pri)
32caddr_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 67out:
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 */
77psig:
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 */
93tsleep(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 */
144unsleep(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 */
164wakeup(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 172restart:
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 */
209rqinit()
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 */
221setrun(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 */
267setpri(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 */
291newproc(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 */
306retry:
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}