%cpu
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
dd808ba3 1/* kern_synch.c 3.15 %G% */
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;
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
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 {
6fdc0335 66 rp->p_stat = SSLEEP;
81263dba 67 (void) spl0();
a379cce8
BJ
68 swtch();
69 }
e5df4be8 70out:
a379cce8
BJ
71 splx(s);
72 return;
73
74 /*
75 * If priority was low (>PZERO) and
76 * there has been a signal,
77 * execute non-local goto to
78 * the qsav location.
79 * (see trap1/trap.c)
80 */
81psig:
a379cce8 82 longjmp(u.u_qsav);
a379cce8
BJ
83 /*NOTREACHED*/
84}
85
a7bf190d
BJ
86/*
87 * Sleep on chan at pri.
88 * Return in no more than the indicated number of seconds.
89 * (If seconds==0, no timeout implied)
90 * Return TS_OK if chan was awakened normally
91 * TS_TIME if timeout occurred
92 * TS_SIG if asynchronous signal occurred
93 */
94tsleep(chan, pri, seconds)
95caddr_t chan;
96{
97 label_t lqsav;
98 register struct proc *pp;
99 register sec, n, rval;
100
101 pp = u.u_procp;
b05a921d 102 n = spl7();
a7bf190d
BJ
103 sec = 0;
104 rval = 0;
a7bf190d
BJ
105 if (pp->p_clktim && pp->p_clktim<seconds)
106 seconds = 0;
107 if (seconds) {
108 pp->p_flag |= STIMO;
06f9e714 109 sec = pp->p_clktim-seconds;
a7bf190d
BJ
110 pp->p_clktim = seconds;
111 }
112 bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
113 if (setjmp(u.u_qsav))
114 rval = TS_SIG;
115 else {
116 sleep(chan, pri);
117 if ((pp->p_flag&STIMO)==0 && seconds)
118 rval = TS_TIME;
119 else
120 rval = TS_OK;
121 }
122 pp->p_flag &= ~STIMO;
123 bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
06f9e714
BJ
124 if (sec > 0)
125 pp->p_clktim += sec;
126 else
127 pp->p_clktim = 0;
a7bf190d
BJ
128 splx(n);
129 return(rval);
130}
131
87d0f32e
BJ
132/*
133 * Remove a process from its wait queue
134 */
135unsleep(p)
136register struct proc *p;
137{
138 register struct proc **hp;
139 register s;
140
141 s = spl6();
142 if (p->p_wchan) {
143 hp = &slpque[HASH(p->p_wchan)];
144 while (*hp != p)
145 hp = &(*hp)->p_link;
146 *hp = p->p_link;
147 p->p_wchan = 0;
148 }
149 splx(s);
150}
151
a379cce8
BJ
152/*
153 * Wake up all processes sleeping on chan.
154 */
155wakeup(chan)
156register caddr_t chan;
157{
e5df4be8 158 register struct proc *p, **q, **h;
a379cce8
BJ
159 int s;
160
161 s = spl6();
e5df4be8 162 h = &slpque[HASH(chan)];
a379cce8 163restart:
e5df4be8 164 for (q = h; p = *q; ) {
87d0f32e 165 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
a379cce8 166 panic("wakeup");
6fdc0335 167 if (p->p_wchan==chan) {
a379cce8 168 p->p_wchan = 0;
e5df4be8 169 *q = p->p_link;
a379cce8 170 p->p_slptime = 0;
87d0f32e
BJ
171 if (p->p_stat == SSLEEP) {
172 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
173 p->p_stat = SRUN;
174 if (p->p_flag & SLOAD) {
a379cce8 175#ifndef FASTVAX
87d0f32e
BJ
176 p->p_link = runq;
177 runq = p->p_link;
a379cce8 178#else
87d0f32e 179 setrq(p);
a379cce8 180#endif
87d0f32e
BJ
181 }
182 if(p->p_pri < curpri)
183 runrun++;
184 if(runout != 0 && (p->p_flag&SLOAD) == 0) {
185 runout = 0;
186 wakeup((caddr_t)&runout);
187 }
188 /* END INLINE EXPANSION */
e5df4be8 189 goto restart;
a379cce8 190 }
e5df4be8
BJ
191 } else
192 q = &p->p_link;
a379cce8
BJ
193 }
194 splx(s);
195}
196
197#ifdef FASTVAX
198/*
199 * Initialize the (doubly-linked) run queues
200 * to be empty.
201 */
202rqinit()
203{
204 register int i;
205
206 for (i = 0; i < NQS; i++)
207 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
208}
209#endif
210
211/*
212 * Set the process running;
213 * arrange for it to be swapped in if necessary.
214 */
215setrun(p)
216register struct proc *p;
217{
a379cce8
BJ
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
6fdc0335 230 case SSTOP:
a379cce8 231 case SSLEEP:
87d0f32e 232 unsleep(p); /* e.g. when sending signals */
a379cce8
BJ
233 break;
234
235 case SIDL:
a379cce8
BJ
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;
49745575 311 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG));
a379cce8
BJ
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;
dd808ba3
BJ
345 rpp->p_pctcpu = 0;
346 rpp->p_cpticks = 0;
a379cce8
BJ
347 n = PIDHASH(rpp->p_pid);
348 p->p_idhash = pidhash[n];
349 pidhash[n] = rpp - proc;
350
351 /*
352 * make duplicate entries
353 * where needed
354 */
355
356 multprog++;
357
358 for(n=0; n<NOFILE; n++)
359 if(u.u_ofile[n] != NULL) {
360 u.u_ofile[n]->f_count++;
361 if(!isvfork && u.u_vrpages[n])
362 u.u_ofile[n]->f_inode->i_vfdcnt++;
363 }
364
365 u.u_cdir->i_count++;
366 if (u.u_rdir)
367 u.u_rdir->i_count++;
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.
372 */
373
374 rip->p_flag |= SKEEP; /* prevent parent from being swapped */
375
376 if (procdup(rpp, isvfork))
377 return (1);
378
379 spl6();
380 rpp->p_stat = SRUN;
381 setrq(rpp);
382 spl0();
e56fe3d3 383 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
a379cce8
BJ
384 /* rpp->p_flag |= SSWAP; */
385 rip->p_flag &= ~SKEEP;
386 if (isvfork) {
387 u.u_procp->p_xlink = rpp;
388 u.u_procp->p_flag |= SNOVM;
389 while (rpp->p_flag & SVFORK)
390 sleep((caddr_t)rpp, PZERO - 1);
391 if ((rpp->p_flag & SLOAD) == 0)
392 panic("newproc vfork");
393 uaccess(rpp, Vfmap, &vfutl);
394 u.u_procp->p_xlink = 0;
395 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
396 for (n = 0; n < NOFILE; n++)
397 if (vfutl.u_vrpages[n]) {
398 if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
399 if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
400 panic("newproc i_vfdcnt");
401 vfutl.u_vrpages[n] = 0;
402 }
403 u.u_procp->p_flag &= ~SNOVM;
404 rpp->p_ndx = rpp - proc;
405 rpp->p_flag |= SVFDONE;
406 wakeup((caddr_t)rpp);
407 }
408 return (0);
409}