xref: /csrg-svn/sys/kern/kern_synch.c (revision 187)
1 /*	kern_synch.c	3.9	10/14/12	*/
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 
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, h;
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 		if(runin != 0) {
59 			runin = 0;
60 			wakeup((caddr_t)&runin);
61 		}
62 		swtch();
63 		if(ISSIG(rp))
64 			goto psig;
65 	} else {
66 		(void) spl0();
67 		swtch();
68 	}
69 out:
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 	 */
80 psig:
81 	longjmp(u.u_qsav);
82 	/*NOTREACHED*/
83 }
84 
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  */
93 tsleep(chan, pri, seconds)
94 caddr_t chan;
95 {
96 	label_t lqsav;
97 	register struct proc *pp;
98 	register sec, n, rval;
99 
100 	pp = u.u_procp;
101 	n = spl7();
102 	sec = 0;
103 	rval = 0;
104 	if (pp->p_clktim && pp->p_clktim<seconds)
105 		seconds = 0;
106 	if (seconds) {
107 		pp->p_flag |= STIMO;
108 		sec = pp->p_clktim-seconds;
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));
123 	if (sec > 0)
124 		pp->p_clktim += sec;
125 	else
126 		pp->p_clktim = 0;
127 	splx(n);
128 	return(rval);
129 }
130 
131 /*
132  * Remove a process from its wait queue
133  */
134 unsleep(p)
135 register 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 
151 /*
152  * Wake up all processes sleeping on chan.
153  */
154 wakeup(chan)
155 register caddr_t chan;
156 {
157 	register struct proc *p, **q, **h;
158 	int s;
159 
160 	s = spl6();
161 	h = &slpque[HASH(chan)];
162 restart:
163 	for (q = h; p = *q; ) {
164 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
165 			panic("wakeup");
166 		if (p->p_wchan==chan && p->p_stat!=SZOMB) {
167 			p->p_wchan = 0;
168 			*q = p->p_link;
169 			p->p_slptime = 0;
170 			if (p->p_stat == SSLEEP) {
171 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
172 				p->p_stat = SRUN;
173 				if (p->p_flag & SLOAD) {
174 #ifndef FASTVAX
175 					p->p_link = runq;
176 					runq = p->p_link;
177 #else
178 					setrq(p);
179 #endif
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 */
188 				goto restart;
189 			}
190 		} else
191 			q = &p->p_link;
192 	}
193 	splx(s);
194 }
195 
196 #ifdef FASTVAX
197 /*
198  * Initialize the (doubly-linked) run queues
199  * to be empty.
200  */
201 rqinit()
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  */
214 setrun(p)
215 register 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:
231 		unsleep(p);		/* e.g. when sending signals */
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  */
256 setpri(pp)
257 register 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  */
276 newproc(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 	 */
289 retry:
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;
323 	rpp->p_pptr = rip;
324 	rpp->p_time = 0;
325 	rpp->p_cpu = 0;
326 	rpp->p_siga0 = rip->p_siga0;
327 	rpp->p_siga1 = rip->p_siga1;
328 	/* take along any pending signals, like stops? */
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();
384 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
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 }
411