bug fix
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
e5df4be8 1/* kern_synch.c 3.9 %H% */
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"
a379cce8 13
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;
a379cce8
BJ
34 register s, h;
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
BJ
58 if(runin != 0) {
59 runin = 0;
60 wakeup((caddr_t)&runin);
61 }
62 swtch();
87d0f32e 63 if(ISSIG(rp))
a379cce8
BJ
64 goto psig;
65 } else {
81263dba 66 (void) spl0();
a379cce8
BJ
67 swtch();
68 }
e5df4be8 69out:
a379cce8
BJ
70 splx(s);
71 return;
72
73 /*
74 * If priority was low (>PZERO) and
75 * there has been a signal,
76 * execute non-local goto to
77 * the qsav location.
78 * (see trap1/trap.c)
79 */
80psig:
a379cce8 81 longjmp(u.u_qsav);
a379cce8
BJ
82 /*NOTREACHED*/
83}
84
a7bf190d
BJ
85/*
86 * Sleep on chan at pri.
87 * Return in no more than the indicated number of seconds.
88 * (If seconds==0, no timeout implied)
89 * Return TS_OK if chan was awakened normally
90 * TS_TIME if timeout occurred
91 * TS_SIG if asynchronous signal occurred
92 */
93tsleep(chan, pri, seconds)
94caddr_t chan;
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
BJ
127 splx(n);
128 return(rval);
129}
130
87d0f32e
BJ
131/*
132 * Remove a process from its wait queue
133 */
134unsleep(p)
135register struct proc *p;
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 */
154wakeup(chan)
155register caddr_t chan;
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 162restart:
e5df4be8 163 for (q = h; p = *q; ) {
87d0f32e 164 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
a379cce8
BJ
165 panic("wakeup");
166 if (p->p_wchan==chan && p->p_stat!=SZOMB) {
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;
173 if (p->p_flag & SLOAD) {
a379cce8 174#ifndef FASTVAX
87d0f32e
BJ
175 p->p_link = runq;
176 runq = p->p_link;
a379cce8 177#else
87d0f32e 178 setrq(p);
a379cce8 179#endif
87d0f32e
BJ
180 }
181 if(p->p_pri < curpri)
182 runrun++;
183 if(runout != 0 && (p->p_flag&SLOAD) == 0) {
184 runout = 0;
185 wakeup((caddr_t)&runout);
186 }
187 /* END INLINE EXPANSION */
e5df4be8 188 goto restart;
a379cce8 189 }
e5df4be8
BJ
190 } else
191 q = &p->p_link;
a379cce8
BJ
192 }
193 splx(s);
194}
195
196#ifdef FASTVAX
197/*
198 * Initialize the (doubly-linked) run queues
199 * to be empty.
200 */
201rqinit()
202{
203 register int i;
204
205 for (i = 0; i < NQS; i++)
206 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
207}
208#endif
209
210/*
211 * Set the process running;
212 * arrange for it to be swapped in if necessary.
213 */
214setrun(p)
215register struct proc *p;
216{
217 register caddr_t w;
218 register s;
219
220 s = spl6();
221 switch (p->p_stat) {
222
223 case 0:
224 case SWAIT:
225 case SRUN:
226 case SZOMB:
227 default:
228 panic("setrun");
229
230 case SSLEEP:
87d0f32e 231 unsleep(p); /* e.g. when sending signals */
a379cce8
BJ
232 break;
233
234 case SIDL:
235 case SSTOP:
236 break;
237 }
238 p->p_stat = SRUN;
239 if (p->p_flag & SLOAD)
240 setrq(p);
241 splx(s);
242 if(p->p_pri < curpri)
243 runrun++;
244 if(runout != 0 && (p->p_flag&SLOAD) == 0) {
245 runout = 0;
246 wakeup((caddr_t)&runout);
247 }
248}
249
250/*
251 * Set user priority.
252 * The rescheduling flag (runrun)
253 * is set if the priority is better
254 * than the currently running process.
255 */
256setpri(pp)
257register struct proc *pp;
258{
259 register p;
260
261 p = (pp->p_cpu & 0377)/16;
262 p += PUSER + pp->p_nice - NZERO;
263 if(p > 127)
264 p = 127;
265 if(p < curpri)
266 runrun++;
267 pp->p_usrpri = p;
268 return(p);
269}
270
271/*
272 * Create a new process-- the internal version of
273 * sys fork.
274 * It returns 1 in the new process, 0 in the old.
275 */
276newproc(isvfork)
277{
278 register struct proc *p;
279 register struct proc *rpp, *rip;
280 register int n;
281
282 p = NULL;
283 /*
284 * First, just locate a slot for a process
285 * and copy the useful info from this process into it.
286 * The panic "cannot happen" because fork has already
287 * checked for the existence of a slot.
288 */
289retry:
290 mpid++;
291 if(mpid >= 30000) {
292 mpid = 0;
293 goto retry;
294 }
295 for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
296 if(rpp->p_stat == NULL && p==NULL)
297 p = rpp;
298 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
299 goto retry;
300 }
301 if ((rpp = p)==NULL)
302 panic("no procs");
303
304 /*
305 * make proc entry for new proc
306 */
307
308 rip = u.u_procp;
309 rpp->p_stat = SIDL;
310 rpp->p_clktim = 0;
311 rpp->p_flag = SLOAD | (rip->p_flag & SPAGI);
312 if (isvfork) {
313 rpp->p_flag |= SVFORK;
314 rpp->p_ndx = rip->p_ndx;
315 } else
316 rpp->p_ndx = rpp - proc;
317 rpp->p_uid = rip->p_uid;
318 rpp->p_pgrp = rip->p_pgrp;
319 rpp->p_nice = rip->p_nice;
320 rpp->p_textp = isvfork ? 0 : rip->p_textp;
321 rpp->p_pid = mpid;
322 rpp->p_ppid = rip->p_pid;
87d0f32e 323 rpp->p_pptr = rip;
a379cce8
BJ
324 rpp->p_time = 0;
325 rpp->p_cpu = 0;
87d0f32e
BJ
326 rpp->p_siga0 = rip->p_siga0;
327 rpp->p_siga1 = rip->p_siga1;
328 /* take along any pending signals, like stops? */
a379cce8
BJ
329 if (isvfork) {
330 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
331 rpp->p_szpt = clrnd(ctopt(UPAGES));
332 forkstat.cntvfork++;
333 forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
334 } else {
335 rpp->p_tsize = rip->p_tsize;
336 rpp->p_dsize = rip->p_dsize;
337 rpp->p_ssize = rip->p_ssize;
338 rpp->p_szpt = rip->p_szpt;
339 forkstat.cntfork++;
340 forkstat.sizfork += rip->p_dsize + rip->p_ssize;
341 }
342 rpp->p_rssize = 0;
343 rpp->p_wchan = 0;
344 rpp->p_slptime = 0;
345 rpp->p_aveflt = rip->p_aveflt;
346 rate.v_pgin += rip->p_aveflt;
347 rpp->p_faults = 0;
348 n = PIDHASH(rpp->p_pid);
349 p->p_idhash = pidhash[n];
350 pidhash[n] = rpp - proc;
351
352 /*
353 * make duplicate entries
354 * where needed
355 */
356
357 multprog++;
358
359 for(n=0; n<NOFILE; n++)
360 if(u.u_ofile[n] != NULL) {
361 u.u_ofile[n]->f_count++;
362 if(!isvfork && u.u_vrpages[n])
363 u.u_ofile[n]->f_inode->i_vfdcnt++;
364 }
365
366 u.u_cdir->i_count++;
367 if (u.u_rdir)
368 u.u_rdir->i_count++;
369 /*
370 * Partially simulate the environment
371 * of the new process so that when it is actually
372 * created (by copying) it will look right.
373 */
374
375 rip->p_flag |= SKEEP; /* prevent parent from being swapped */
376
377 if (procdup(rpp, isvfork))
378 return (1);
379
380 spl6();
381 rpp->p_stat = SRUN;
382 setrq(rpp);
383 spl0();
e56fe3d3 384 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
a379cce8
BJ
385 /* rpp->p_flag |= SSWAP; */
386 rip->p_flag &= ~SKEEP;
387 if (isvfork) {
388 u.u_procp->p_xlink = rpp;
389 u.u_procp->p_flag |= SNOVM;
390 while (rpp->p_flag & SVFORK)
391 sleep((caddr_t)rpp, PZERO - 1);
392 if ((rpp->p_flag & SLOAD) == 0)
393 panic("newproc vfork");
394 uaccess(rpp, Vfmap, &vfutl);
395 u.u_procp->p_xlink = 0;
396 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
397 for (n = 0; n < NOFILE; n++)
398 if (vfutl.u_vrpages[n]) {
399 if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
400 if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
401 panic("newproc i_vfdcnt");
402 vfutl.u_vrpages[n] = 0;
403 }
404 u.u_procp->p_flag &= ~SNOVM;
405 rpp->p_ndx = rpp - proc;
406 rpp->p_flag |= SVFDONE;
407 wakeup((caddr_t)rpp);
408 }
409 return (0);
410}