rid of NPROC
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
86fd527f 1/* kern_synch.c 4.8 %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"
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 }
87d0f32e
BJ
176 if(runout != 0 && (p->p_flag&SLOAD) == 0) {
177 runout = 0;
178 wakeup((caddr_t)&runout);
179 }
180 /* END INLINE EXPANSION */
e5df4be8 181 goto restart;
a379cce8 182 }
e5df4be8
BJ
183 } else
184 q = &p->p_link;
a379cce8
BJ
185 }
186 splx(s);
187}
188
a379cce8
BJ
189/*
190 * Initialize the (doubly-linked) run queues
191 * to be empty.
192 */
193rqinit()
194{
195 register int i;
196
197 for (i = 0; i < NQS; i++)
198 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
199}
a379cce8
BJ
200
201/*
202 * Set the process running;
203 * arrange for it to be swapped in if necessary.
204 */
205setrun(p)
206register struct proc *p;
207{
a379cce8
BJ
208 register s;
209
210 s = spl6();
211 switch (p->p_stat) {
212
213 case 0:
214 case SWAIT:
215 case SRUN:
216 case SZOMB:
217 default:
218 panic("setrun");
219
6fdc0335 220 case SSTOP:
a379cce8 221 case SSLEEP:
87d0f32e 222 unsleep(p); /* e.g. when sending signals */
a379cce8
BJ
223 break;
224
225 case SIDL:
a379cce8
BJ
226 break;
227 }
228 p->p_stat = SRUN;
229 if (p->p_flag & SLOAD)
230 setrq(p);
231 splx(s);
534d9295 232 if(p->p_pri < curpri) {
a379cce8 233 runrun++;
534d9295
BJ
234 aston();
235 }
a379cce8
BJ
236 if(runout != 0 && (p->p_flag&SLOAD) == 0) {
237 runout = 0;
238 wakeup((caddr_t)&runout);
239 }
240}
241
242/*
243 * Set user priority.
244 * The rescheduling flag (runrun)
245 * is set if the priority is better
246 * than the currently running process.
247 */
248setpri(pp)
249register struct proc *pp;
250{
251 register p;
252
253 p = (pp->p_cpu & 0377)/16;
598563b5 254 p += PUSER + 2*(pp->p_nice - NZERO);
a379cce8
BJ
255 if(p > 127)
256 p = 127;
a51a6e74 257 if(p < curpri) {
a379cce8 258 runrun++;
a51a6e74
BJ
259 aston();
260 }
a379cce8
BJ
261 pp->p_usrpri = p;
262 return(p);
263}
264
265/*
266 * Create a new process-- the internal version of
267 * sys fork.
268 * It returns 1 in the new process, 0 in the old.
269 */
270newproc(isvfork)
271{
272 register struct proc *p;
273 register struct proc *rpp, *rip;
274 register int n;
275
276 p = NULL;
277 /*
278 * First, just locate a slot for a process
279 * and copy the useful info from this process into it.
280 * The panic "cannot happen" because fork has already
281 * checked for the existence of a slot.
282 */
283retry:
284 mpid++;
285 if(mpid >= 30000) {
286 mpid = 0;
287 goto retry;
288 }
86fd527f 289 for(rpp = proc; rpp < procNPROC; rpp++) {
a379cce8
BJ
290 if(rpp->p_stat == NULL && p==NULL)
291 p = rpp;
292 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
293 goto retry;
294 }
295 if ((rpp = p)==NULL)
296 panic("no procs");
297
298 /*
299 * make proc entry for new proc
300 */
301
302 rip = u.u_procp;
303 rpp->p_stat = SIDL;
304 rpp->p_clktim = 0;
49745575 305 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG));
a379cce8
BJ
306 if (isvfork) {
307 rpp->p_flag |= SVFORK;
308 rpp->p_ndx = rip->p_ndx;
309 } else
310 rpp->p_ndx = rpp - proc;
311 rpp->p_uid = rip->p_uid;
312 rpp->p_pgrp = rip->p_pgrp;
313 rpp->p_nice = rip->p_nice;
314 rpp->p_textp = isvfork ? 0 : rip->p_textp;
315 rpp->p_pid = mpid;
316 rpp->p_ppid = rip->p_pid;
87d0f32e 317 rpp->p_pptr = rip;
a379cce8
BJ
318 rpp->p_time = 0;
319 rpp->p_cpu = 0;
87d0f32e
BJ
320 rpp->p_siga0 = rip->p_siga0;
321 rpp->p_siga1 = rip->p_siga1;
322 /* take along any pending signals, like stops? */
a379cce8
BJ
323 if (isvfork) {
324 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
325 rpp->p_szpt = clrnd(ctopt(UPAGES));
326 forkstat.cntvfork++;
327 forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
328 } else {
329 rpp->p_tsize = rip->p_tsize;
330 rpp->p_dsize = rip->p_dsize;
331 rpp->p_ssize = rip->p_ssize;
332 rpp->p_szpt = rip->p_szpt;
333 forkstat.cntfork++;
334 forkstat.sizfork += rip->p_dsize + rip->p_ssize;
335 }
336 rpp->p_rssize = 0;
337 rpp->p_wchan = 0;
338 rpp->p_slptime = 0;
dd808ba3
BJ
339 rpp->p_pctcpu = 0;
340 rpp->p_cpticks = 0;
a379cce8
BJ
341 n = PIDHASH(rpp->p_pid);
342 p->p_idhash = pidhash[n];
343 pidhash[n] = rpp - proc;
344
345 /*
346 * make duplicate entries
347 * where needed
348 */
349
350 multprog++;
351
352 for(n=0; n<NOFILE; n++)
353 if(u.u_ofile[n] != NULL) {
75a44ba5
BJ
354#ifdef UCBIPC
355 if (u.u_pofile[n] & ISPORT)
356 u.u_oport[n]->pt_count++;
357 else {
358#endif
359 u.u_ofile[n]->f_count++;
360 if(!isvfork && u.u_vrpages[n])
361 u.u_ofile[n]->f_inode->i_vfdcnt++;
362#ifdef UCBIPC
363 }
364#endif UCBIPC
a379cce8
BJ
365 }
366
367 u.u_cdir->i_count++;
368 if (u.u_rdir)
369 u.u_rdir->i_count++;
370 /*
371 * Partially simulate the environment
372 * of the new process so that when it is actually
373 * created (by copying) it will look right.
374 */
375
376 rip->p_flag |= SKEEP; /* prevent parent from being swapped */
377
378 if (procdup(rpp, isvfork))
379 return (1);
380
934e4ecf 381 (void) spl6();
a379cce8
BJ
382 rpp->p_stat = SRUN;
383 setrq(rpp);
283cac0a 384 (void) spl0();
e56fe3d3 385 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
a379cce8
BJ
386 /* rpp->p_flag |= SSWAP; */
387 rip->p_flag &= ~SKEEP;
388 if (isvfork) {
389 u.u_procp->p_xlink = rpp;
390 u.u_procp->p_flag |= SNOVM;
391 while (rpp->p_flag & SVFORK)
392 sleep((caddr_t)rpp, PZERO - 1);
393 if ((rpp->p_flag & SLOAD) == 0)
394 panic("newproc vfork");
395 uaccess(rpp, Vfmap, &vfutl);
396 u.u_procp->p_xlink = 0;
397 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
398 for (n = 0; n < NOFILE; n++)
399 if (vfutl.u_vrpages[n]) {
400 if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
401 if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
402 panic("newproc i_vfdcnt");
403 vfutl.u_vrpages[n] = 0;
404 }
405 u.u_procp->p_flag &= ~SNOVM;
406 rpp->p_ndx = rpp - proc;
407 rpp->p_flag |= SVFDONE;
408 wakeup((caddr_t)rpp);
409 }
410 return (0);
411}