xref: /original-bsd/sys/kern/kern_synch.c (revision 1f3a482a)
1 /*	kern_synch.c	4.14	81/06/11	*/
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))
17 struct 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  */
30 sleep(chan, pri)
31 caddr_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 	}
66 out:
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 	 */
77 psig:
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  */
90 tsleep(chan, pri, seconds)
91 caddr_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  */
131 unsleep(p)
132 register 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  */
151 wakeup(chan)
152 register caddr_t chan;
153 {
154 	register struct proc *p, **q, **h;
155 	int s;
156 
157 	s = spl6();
158 	h = &slpque[HASH(chan)];
159 restart:
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 ((p->p_flag&SLOAD) == 0) {
177 					if (runout != 0) {
178 						runout = 0;
179 						wakeup((caddr_t)&runout);
180 					}
181 					wantin++;
182 				}
183 				/* END INLINE EXPANSION */
184 				goto restart;
185 			}
186 		} else
187 			q = &p->p_link;
188 	}
189 	splx(s);
190 }
191 
192 /*
193  * Initialize the (doubly-linked) run queues
194  * to be empty.
195  */
196 rqinit()
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 }
203 
204 /*
205  * Set the process running;
206  * arrange for it to be swapped in if necessary.
207  */
208 setrun(p)
209 register struct proc *p;
210 {
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 
223 	case SSTOP:
224 	case SSLEEP:
225 		unsleep(p);		/* e.g. when sending signals */
226 		break;
227 
228 	case SIDL:
229 		break;
230 	}
231 	p->p_stat = SRUN;
232 	if (p->p_flag & SLOAD)
233 		setrq(p);
234 	splx(s);
235 	if(p->p_pri < curpri) {
236 		runrun++;
237 		aston();
238 	}
239 	if ((p->p_flag&SLOAD) == 0) {
240 		if(runout != 0) {
241 			runout = 0;
242 			wakeup((caddr_t)&runout);
243 		}
244 		wantin++;
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  */
254 setpri(pp)
255 register struct proc *pp;
256 {
257 	register p;
258 
259 	p = (pp->p_cpu & 0377)/4;
260 	p += PUSER + 2*(pp->p_nice - NZERO);
261 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
262 		p += 2*4;	/* effectively, nice(4) */
263 	if(p > 127)
264 		p = 127;
265 	if(p < curpri) {
266 		runrun++;
267 		aston();
268 	}
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  */
278 newproc(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 	 */
291 retry:
292 	mpid++;
293 	if(mpid >= 30000) {
294 		mpid = 0;
295 		goto retry;
296 	}
297 	for(rpp = proc; rpp < procNPROC; rpp++) {
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;
313 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG));
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;
325 	rpp->p_pptr = rip;
326 	rpp->p_time = 0;
327 	rpp->p_cpu = 0;
328 	rpp->p_siga0 = rip->p_siga0;
329 	rpp->p_siga1 = rip->p_siga1;
330 	/* take along any pending signals, like stops? */
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;
345 	rpp->p_maxrss = rip->p_maxrss;
346 	rpp->p_wchan = 0;
347 	rpp->p_slptime = 0;
348 	rpp->p_pctcpu = 0;
349 	rpp->p_cpticks = 0;
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) {
363 			u.u_ofile[n]->f_count++;
364 			if(!isvfork && u.u_vrpages[n])
365 				u.u_ofile[n]->f_inode->i_vfdcnt++;
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 
382 	(void) spl6();
383 	rpp->p_stat = SRUN;
384 	setrq(rpp);
385 	(void) spl0();
386 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
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 }
413