make escape escape force escape
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
16a64baa 1/* kern_synch.c 4.14 81/06/11 */
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))
17struct 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 */
30sleep(chan, pri)
31caddr_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;
a379cce8 46 if(pri > PZERO) {
87d0f32e 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();
87d0f32e 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 66out:
a379cce8
BJ
67 splx(s);
68 return;
69
70 /*
71 * If priority was low (>PZERO) and
72 * there has been a signal,
73 * execute non-local goto to
74 * the qsav location.
75 * (see trap1/trap.c)
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
89 */
90tsleep(chan, pri, seconds)
91caddr_t chan;
92{
93 label_t lqsav;
94 register struct proc *pp;
95 register sec, n, rval;
96
97 pp = u.u_procp;
b05a921d 98 n = spl7();
a7bf190d
BJ
99 sec = 0;
100 rval = 0;
a7bf190d
BJ
101 if (pp->p_clktim && pp->p_clktim<seconds)
102 seconds = 0;
103 if (seconds) {
104 pp->p_flag |= STIMO;
06f9e714 105 sec = pp->p_clktim-seconds;
a7bf190d
BJ
106 pp->p_clktim = seconds;
107 }
108 bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
109 if (setjmp(u.u_qsav))
110 rval = TS_SIG;
111 else {
112 sleep(chan, pri);
113 if ((pp->p_flag&STIMO)==0 && seconds)
114 rval = TS_TIME;
115 else
116 rval = TS_OK;
117 }
118 pp->p_flag &= ~STIMO;
119 bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
06f9e714
BJ
120 if (sec > 0)
121 pp->p_clktim += sec;
122 else
123 pp->p_clktim = 0;
a7bf190d
BJ
124 splx(n);
125 return(rval);
126}
127
87d0f32e
BJ
128/*
129 * Remove a process from its wait queue
130 */
131unsleep(p)
132register struct proc *p;
133{
134 register struct proc **hp;
135 register s;
136
137 s = spl6();
138 if (p->p_wchan) {
139 hp = &slpque[HASH(p->p_wchan)];
140 while (*hp != p)
141 hp = &(*hp)->p_link;
142 *hp = p->p_link;
143 p->p_wchan = 0;
144 }
145 splx(s);
146}
147
a379cce8
BJ
148/*
149 * Wake up all processes sleeping on chan.
150 */
151wakeup(chan)
152register caddr_t chan;
153{
e5df4be8 154 register struct proc *p, **q, **h;
a379cce8
BJ
155 int s;
156
157 s = spl6();
e5df4be8 158 h = &slpque[HASH(chan)];
a379cce8 159restart:
e5df4be8 160 for (q = h; p = *q; ) {
87d0f32e 161 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
a379cce8 162 panic("wakeup");
6fdc0335 163 if (p->p_wchan==chan) {
a379cce8 164 p->p_wchan = 0;
e5df4be8 165 *q = p->p_link;
a379cce8 166 p->p_slptime = 0;
87d0f32e
BJ
167 if (p->p_stat == SSLEEP) {
168 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
169 p->p_stat = SRUN;
c74c8a79 170 if (p->p_flag & SLOAD)
87d0f32e 171 setrq(p);
534d9295 172 if(p->p_pri < curpri) {
87d0f32e 173 runrun++;
534d9295
BJ
174 aston();
175 }
7eb2e67e
BJ
176 if ((p->p_flag&SLOAD) == 0) {
177 if (runout != 0) {
178 runout = 0;
179 wakeup((caddr_t)&runout);
180 }
181 wantin++;
87d0f32e
BJ
182 }
183 /* END INLINE EXPANSION */
e5df4be8 184 goto restart;
a379cce8 185 }
e5df4be8
BJ
186 } else
187 q = &p->p_link;
a379cce8
BJ
188 }
189 splx(s);
190}
191
a379cce8
BJ
192/*
193 * Initialize the (doubly-linked) run queues
194 * to be empty.
195 */
196rqinit()
197{
198 register int i;
199
200 for (i = 0; i < NQS; i++)
201 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
202}
a379cce8
BJ
203
204/*
205 * Set the process running;
206 * arrange for it to be swapped in if necessary.
207 */
208setrun(p)
209register struct proc *p;
210{
a379cce8
BJ
211 register s;
212
213 s = spl6();
214 switch (p->p_stat) {
215
216 case 0:
217 case SWAIT:
218 case SRUN:
219 case SZOMB:
220 default:
221 panic("setrun");
222
6fdc0335 223 case SSTOP:
a379cce8 224 case SSLEEP:
87d0f32e 225 unsleep(p); /* e.g. when sending signals */
a379cce8
BJ
226 break;
227
228 case SIDL:
a379cce8
BJ
229 break;
230 }
231 p->p_stat = SRUN;
232 if (p->p_flag & SLOAD)
233 setrq(p);
234 splx(s);
534d9295 235 if(p->p_pri < curpri) {
a379cce8 236 runrun++;
534d9295
BJ
237 aston();
238 }
7eb2e67e
BJ
239 if ((p->p_flag&SLOAD) == 0) {
240 if(runout != 0) {
241 runout = 0;
242 wakeup((caddr_t)&runout);
243 }
244 wantin++;
a379cce8
BJ
245 }
246}
247
248/*
249 * Set user priority.
250 * The rescheduling flag (runrun)
251 * is set if the priority is better
252 * than the currently running process.
253 */
254setpri(pp)
255register struct proc *pp;
256{
257 register p;
258
16a64baa 259 p = (pp->p_cpu & 0377)/4;
598563b5 260 p += PUSER + 2*(pp->p_nice - NZERO);
9afea775
BJ
261 if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
262 p += 2*4; /* effectively, nice(4) */
a379cce8
BJ
263 if(p > 127)
264 p = 127;
a51a6e74 265 if(p < curpri) {
a379cce8 266 runrun++;
a51a6e74
BJ
267 aston();
268 }
a379cce8
BJ
269 pp->p_usrpri = p;
270 return(p);
271}
272
273/*
274 * Create a new process-- the internal version of
275 * sys fork.
276 * It returns 1 in the new process, 0 in the old.
277 */
278newproc(isvfork)
279{
280 register struct proc *p;
281 register struct proc *rpp, *rip;
282 register int n;
283
284 p = NULL;
285 /*
286 * First, just locate a slot for a process
287 * and copy the useful info from this process into it.
288 * The panic "cannot happen" because fork has already
289 * checked for the existence of a slot.
290 */
291retry:
292 mpid++;
293 if(mpid >= 30000) {
294 mpid = 0;
295 goto retry;
296 }
86fd527f 297 for(rpp = proc; rpp < procNPROC; rpp++) {
a379cce8
BJ
298 if(rpp->p_stat == NULL && p==NULL)
299 p = rpp;
300 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
301 goto retry;
302 }
303 if ((rpp = p)==NULL)
304 panic("no procs");
305
306 /*
307 * make proc entry for new proc
308 */
309
310 rip = u.u_procp;
311 rpp->p_stat = SIDL;
312 rpp->p_clktim = 0;
49745575 313 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG));
a379cce8
BJ
314 if (isvfork) {
315 rpp->p_flag |= SVFORK;
316 rpp->p_ndx = rip->p_ndx;
317 } else
318 rpp->p_ndx = rpp - proc;
319 rpp->p_uid = rip->p_uid;
320 rpp->p_pgrp = rip->p_pgrp;
321 rpp->p_nice = rip->p_nice;
322 rpp->p_textp = isvfork ? 0 : rip->p_textp;
323 rpp->p_pid = mpid;
324 rpp->p_ppid = rip->p_pid;
87d0f32e 325 rpp->p_pptr = rip;
a379cce8
BJ
326 rpp->p_time = 0;
327 rpp->p_cpu = 0;
87d0f32e
BJ
328 rpp->p_siga0 = rip->p_siga0;
329 rpp->p_siga1 = rip->p_siga1;
330 /* take along any pending signals, like stops? */
a379cce8
BJ
331 if (isvfork) {
332 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
333 rpp->p_szpt = clrnd(ctopt(UPAGES));
334 forkstat.cntvfork++;
335 forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
336 } else {
337 rpp->p_tsize = rip->p_tsize;
338 rpp->p_dsize = rip->p_dsize;
339 rpp->p_ssize = rip->p_ssize;
340 rpp->p_szpt = rip->p_szpt;
341 forkstat.cntfork++;
342 forkstat.sizfork += rip->p_dsize + rip->p_ssize;
343 }
344 rpp->p_rssize = 0;
f3ba10a3 345 rpp->p_maxrss = rip->p_maxrss;
a379cce8
BJ
346 rpp->p_wchan = 0;
347 rpp->p_slptime = 0;
dd808ba3
BJ
348 rpp->p_pctcpu = 0;
349 rpp->p_cpticks = 0;
a379cce8
BJ
350 n = PIDHASH(rpp->p_pid);
351 p->p_idhash = pidhash[n];
352 pidhash[n] = rpp - proc;
353
354 /*
355 * make duplicate entries
356 * where needed
357 */
358
359 multprog++;
360
361 for(n=0; n<NOFILE; n++)
362 if(u.u_ofile[n] != NULL) {
62901f34
BJ
363 u.u_ofile[n]->f_count++;
364 if(!isvfork && u.u_vrpages[n])
365 u.u_ofile[n]->f_inode->i_vfdcnt++;
a379cce8
BJ
366 }
367
368 u.u_cdir->i_count++;
369 if (u.u_rdir)
370 u.u_rdir->i_count++;
371 /*
372 * Partially simulate the environment
373 * of the new process so that when it is actually
374 * created (by copying) it will look right.
375 */
376
377 rip->p_flag |= SKEEP; /* prevent parent from being swapped */
378
379 if (procdup(rpp, isvfork))
380 return (1);
381
934e4ecf 382 (void) spl6();
a379cce8
BJ
383 rpp->p_stat = SRUN;
384 setrq(rpp);
283cac0a 385 (void) spl0();
e56fe3d3 386 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
a379cce8
BJ
387 /* rpp->p_flag |= SSWAP; */
388 rip->p_flag &= ~SKEEP;
389 if (isvfork) {
390 u.u_procp->p_xlink = rpp;
391 u.u_procp->p_flag |= SNOVM;
392 while (rpp->p_flag & SVFORK)
393 sleep((caddr_t)rpp, PZERO - 1);
394 if ((rpp->p_flag & SLOAD) == 0)
395 panic("newproc vfork");
396 uaccess(rpp, Vfmap, &vfutl);
397 u.u_procp->p_xlink = 0;
398 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
399 for (n = 0; n < NOFILE; n++)
400 if (vfutl.u_vrpages[n]) {
401 if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
402 if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
403 panic("newproc i_vfdcnt");
404 vfutl.u_vrpages[n] = 0;
405 }
406 u.u_procp->p_flag &= ~SNOVM;
407 rpp->p_ndx = rpp - proc;
408 rpp->p_flag |= SVFDONE;
409 wakeup((caddr_t)rpp);
410 }
411 return (0);
412}