rid of NPROC
[unix-history] / usr / src / sys / kern / kern_synch.c
... / ...
CommitLineData
1/* kern_synch.c 4.8 %G% */
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"
12#include "../h/inline.h"
13#include "../h/mtpr.h"
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{
33 register struct proc *rp, **hp;
34 register s;
35
36 rp = u.u_procp;
37 s = spl6();
38 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
39 panic("sleep");
40 rp->p_wchan = chan;
41 rp->p_slptime = 0;
42 rp->p_pri = pri;
43 hp = &slpque[HASH(chan)];
44 rp->p_link = *hp;
45 *hp = rp;
46 if(pri > PZERO) {
47 if(ISSIG(rp)) {
48 if (rp->p_wchan)
49 unsleep(rp);
50 rp->p_stat = SRUN;
51 (void) spl0();
52 goto psig;
53 }
54 if (rp->p_wchan == 0)
55 goto out;
56 rp->p_stat = SSLEEP;
57 (void) spl0();
58 swtch();
59 if(ISSIG(rp))
60 goto psig;
61 } else {
62 rp->p_stat = SSLEEP;
63 (void) spl0();
64 swtch();
65 }
66out:
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:
78 longjmp(u.u_qsav);
79 /*NOTREACHED*/
80}
81
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;
98 n = spl7();
99 sec = 0;
100 rval = 0;
101 if (pp->p_clktim && pp->p_clktim<seconds)
102 seconds = 0;
103 if (seconds) {
104 pp->p_flag |= STIMO;
105 sec = pp->p_clktim-seconds;
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));
120 if (sec > 0)
121 pp->p_clktim += sec;
122 else
123 pp->p_clktim = 0;
124 splx(n);
125 return(rval);
126}
127
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
148/*
149 * Wake up all processes sleeping on chan.
150 */
151wakeup(chan)
152register caddr_t chan;
153{
154 register struct proc *p, **q, **h;
155 int s;
156
157 s = spl6();
158 h = &slpque[HASH(chan)];
159restart:
160 for (q = h; p = *q; ) {
161 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
162 panic("wakeup");
163 if (p->p_wchan==chan) {
164 p->p_wchan = 0;
165 *q = p->p_link;
166 p->p_slptime = 0;
167 if (p->p_stat == SSLEEP) {
168 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
169 p->p_stat = SRUN;
170 if (p->p_flag & SLOAD)
171 setrq(p);
172 if(p->p_pri < curpri) {
173 runrun++;
174 aston();
175 }
176 if(runout != 0 && (p->p_flag&SLOAD) == 0) {
177 runout = 0;
178 wakeup((caddr_t)&runout);
179 }
180 /* END INLINE EXPANSION */
181 goto restart;
182 }
183 } else
184 q = &p->p_link;
185 }
186 splx(s);
187}
188
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}
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{
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
220 case SSTOP:
221 case SSLEEP:
222 unsleep(p); /* e.g. when sending signals */
223 break;
224
225 case SIDL:
226 break;
227 }
228 p->p_stat = SRUN;
229 if (p->p_flag & SLOAD)
230 setrq(p);
231 splx(s);
232 if(p->p_pri < curpri) {
233 runrun++;
234 aston();
235 }
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;
254 p += PUSER + 2*(pp->p_nice - NZERO);
255 if(p > 127)
256 p = 127;
257 if(p < curpri) {
258 runrun++;
259 aston();
260 }
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 }
289 for(rpp = proc; rpp < procNPROC; rpp++) {
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;
305 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG));
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;
317 rpp->p_pptr = rip;
318 rpp->p_time = 0;
319 rpp->p_cpu = 0;
320 rpp->p_siga0 = rip->p_siga0;
321 rpp->p_siga1 = rip->p_siga1;
322 /* take along any pending signals, like stops? */
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;
339 rpp->p_pctcpu = 0;
340 rpp->p_cpticks = 0;
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) {
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
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
381 (void) spl6();
382 rpp->p_stat = SRUN;
383 setrq(rpp);
384 (void) spl0();
385 /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
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}