xref: /csrg-svn/sys/kern/kern_synch.c (revision 131)
1 /*	kern_synch.c	3.7	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 
13 
14 #define SQSIZE 0100	/* Must be power of 2 */
15 #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
16 struct proc *slpque[SQSIZE];
17 
18 /*
19  * Give up the processor till a wakeup occurs
20  * on chan, at which time the process
21  * enters the scheduling queue at priority pri.
22  * The most important effect of pri is that when
23  * pri<=PZERO a signal cannot disturb the sleep;
24  * if pri>PZERO signals will be processed.
25  * Callers of this routine must be prepared for
26  * premature return, and check that the reason for
27  * sleeping has gone away.
28  */
29 sleep(chan, pri)
30 caddr_t chan;
31 {
32 	register struct proc *rp;
33 	register s, h;
34 
35 	rp = u.u_procp;
36 	s = spl6();
37 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
38 		panic("sleep");
39 	rp->p_stat = SSLEEP;
40 	rp->p_wchan = chan;
41 	rp->p_slptime = 0;
42 	rp->p_pri = pri;
43 	h = HASH(chan);
44 	rp->p_link = slpque[h];
45 	slpque[h] = rp;
46 	if(pri > PZERO) {
47 		if(rp->p_sig && issig()) {
48 			rp->p_wchan = 0;
49 			rp->p_stat = SRUN;
50 			slpque[h] = rp->p_link;
51 			(void) spl0();
52 			goto psig;
53 		}
54 		(void) spl0();
55 		if(runin != 0) {
56 			runin = 0;
57 			wakeup((caddr_t)&runin);
58 		}
59 		swtch();
60 		if(rp->p_sig && issig())
61 			goto psig;
62 	} else {
63 		(void) spl0();
64 		swtch();
65 	}
66 	splx(s);
67 	return;
68 
69 	/*
70 	 * If priority was low (>PZERO) and
71 	 * there has been a signal,
72 	 * execute non-local goto to
73 	 * the qsav location.
74 	 * (see trap1/trap.c)
75 	 */
76 psig:
77 	longjmp(u.u_qsav);
78 	/*NOTREACHED*/
79 }
80 
81 /*
82  * Sleep on chan at pri.
83  * Return in no more than the indicated number of seconds.
84  * (If seconds==0, no timeout implied)
85  * Return	TS_OK if chan was awakened normally
86  *		TS_TIME if timeout occurred
87  *		TS_SIG if asynchronous signal occurred
88  */
89 tsleep(chan, pri, seconds)
90 caddr_t chan;
91 {
92 	label_t lqsav;
93 	register struct proc *pp;
94 	register sec, n, rval;
95 
96 	pp = u.u_procp;
97 	n = spl7();
98 	sec = 0;
99 	rval = 0;
100 	if (pp->p_clktim && pp->p_clktim<seconds)
101 		seconds = 0;
102 	if (seconds) {
103 		pp->p_flag |= STIMO;
104 		sec = pp->p_clktim-seconds;
105 		pp->p_clktim = seconds;
106 	}
107 	bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
108 	if (setjmp(u.u_qsav))
109 		rval = TS_SIG;
110 	else {
111 		sleep(chan, pri);
112 		if ((pp->p_flag&STIMO)==0 && seconds)
113 			rval = TS_TIME;
114 		else
115 			rval = TS_OK;
116 	}
117 	pp->p_flag &= ~STIMO;
118 	bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
119 	if (sec > 0)
120 		pp->p_clktim += sec;
121 	else
122 		pp->p_clktim = 0;
123 	splx(n);
124 	return(rval);
125 }
126 
127 /*
128  * Wake up all processes sleeping on chan.
129  */
130 wakeup(chan)
131 register caddr_t chan;
132 {
133 	register struct proc *p, *q;
134 	register i;
135 	int s;
136 
137 	s = spl6();
138 	i = HASH(chan);
139 restart:
140 	p = slpque[i];
141 	q = NULL;
142 	while(p != NULL) {
143 		if (p->p_rlink || p->p_stat != SSLEEP)
144 			panic("wakeup");
145 		if (p->p_wchan==chan && p->p_stat!=SZOMB) {
146 			if (q == NULL)
147 				slpque[i] = p->p_link;
148 			else
149 				q->p_link = p->p_link;
150 			p->p_wchan = 0;
151 			p->p_slptime = 0;
152 			/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
153 			p->p_stat = SRUN;
154 			if (p->p_flag & SLOAD) {
155 #ifndef FASTVAX
156 				p->p_link = runq;
157 				runq = p->p_link;
158 #else
159 				setrq(p);
160 #endif
161 			}
162 			if(p->p_pri < curpri)
163 				runrun++;
164 			if(runout != 0 && (p->p_flag&SLOAD) == 0) {
165 				runout = 0;
166 				wakeup((caddr_t)&runout);
167 			}
168 			/* END INLINE EXPANSION */
169 			goto restart;
170 		}
171 		q = p;
172 		p = p->p_link;
173 	}
174 	splx(s);
175 }
176 
177 #ifdef FASTVAX
178 /*
179  * Initialize the (doubly-linked) run queues
180  * to be empty.
181  */
182 rqinit()
183 {
184 	register int i;
185 
186 	for (i = 0; i < NQS; i++)
187 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
188 }
189 #endif
190 
191 /*
192  * Set the process running;
193  * arrange for it to be swapped in if necessary.
194  */
195 setrun(p)
196 register struct proc *p;
197 {
198 	register caddr_t w;
199 	register s;
200 
201 	s = spl6();
202 	switch (p->p_stat) {
203 
204 	case 0:
205 	case SWAIT:
206 	case SRUN:
207 	case SZOMB:
208 	default:
209 		panic("setrun");
210 
211 	case SSLEEP:
212 		if (w = p->p_wchan) {
213 			wakeup(w);
214 			splx(s);
215 			return;
216 		}
217 		break;
218 
219 	case SIDL:
220 	case SSTOP:
221 		break;
222 	}
223 	p->p_stat = SRUN;
224 	if (p->p_flag & SLOAD)
225 		setrq(p);
226 	splx(s);
227 	if(p->p_pri < curpri)
228 		runrun++;
229 	if(runout != 0 && (p->p_flag&SLOAD) == 0) {
230 		runout = 0;
231 		wakeup((caddr_t)&runout);
232 	}
233 }
234 
235 /*
236  * Set user priority.
237  * The rescheduling flag (runrun)
238  * is set if the priority is better
239  * than the currently running process.
240  */
241 setpri(pp)
242 register struct proc *pp;
243 {
244 	register p;
245 
246 	p = (pp->p_cpu & 0377)/16;
247 	p += PUSER + pp->p_nice - NZERO;
248 	if(p > 127)
249 		p = 127;
250 	if(p < curpri)
251 		runrun++;
252 	pp->p_usrpri = p;
253 	return(p);
254 }
255 
256 /*
257  * Create a new process-- the internal version of
258  * sys fork.
259  * It returns 1 in the new process, 0 in the old.
260  */
261 newproc(isvfork)
262 {
263 	register struct proc *p;
264 	register struct proc *rpp, *rip;
265 	register int n;
266 
267 	p = NULL;
268 	/*
269 	 * First, just locate a slot for a process
270 	 * and copy the useful info from this process into it.
271 	 * The panic "cannot happen" because fork has already
272 	 * checked for the existence of a slot.
273 	 */
274 retry:
275 	mpid++;
276 	if(mpid >= 30000) {
277 		mpid = 0;
278 		goto retry;
279 	}
280 	for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
281 		if(rpp->p_stat == NULL && p==NULL)
282 			p = rpp;
283 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
284 			goto retry;
285 	}
286 	if ((rpp = p)==NULL)
287 		panic("no procs");
288 
289 	/*
290 	 * make proc entry for new proc
291 	 */
292 
293 	rip = u.u_procp;
294 	rpp->p_stat = SIDL;
295 	rpp->p_clktim = 0;
296 	rpp->p_flag = SLOAD | (rip->p_flag & SPAGI);
297 	if (isvfork) {
298 		rpp->p_flag |= SVFORK;
299 		rpp->p_ndx = rip->p_ndx;
300 	} else
301 		rpp->p_ndx = rpp - proc;
302 	rpp->p_uid = rip->p_uid;
303 	rpp->p_pgrp = rip->p_pgrp;
304 	rpp->p_nice = rip->p_nice;
305 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
306 	rpp->p_pid = mpid;
307 	rpp->p_ppid = rip->p_pid;
308 	rpp->p_time = 0;
309 	rpp->p_cpu = 0;
310 	if (isvfork) {
311 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
312 		rpp->p_szpt = clrnd(ctopt(UPAGES));
313 		forkstat.cntvfork++;
314 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
315 	} else {
316 		rpp->p_tsize = rip->p_tsize;
317 		rpp->p_dsize = rip->p_dsize;
318 		rpp->p_ssize = rip->p_ssize;
319 		rpp->p_szpt = rip->p_szpt;
320 		forkstat.cntfork++;
321 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
322 	}
323 	rpp->p_rssize = 0;
324 	rpp->p_wchan = 0;
325 	rpp->p_slptime = 0;
326 	rpp->p_aveflt = rip->p_aveflt;
327 	rate.v_pgin += rip->p_aveflt;
328 	rpp->p_faults = 0;
329 	n = PIDHASH(rpp->p_pid);
330 	p->p_idhash = pidhash[n];
331 	pidhash[n] = rpp - proc;
332 
333 	/*
334 	 * make duplicate entries
335 	 * where needed
336 	 */
337 
338 	multprog++;
339 
340 	for(n=0; n<NOFILE; n++)
341 		if(u.u_ofile[n] != NULL) {
342 			u.u_ofile[n]->f_count++;
343 			if(!isvfork && u.u_vrpages[n])
344 				u.u_ofile[n]->f_inode->i_vfdcnt++;
345 		}
346 
347 	u.u_cdir->i_count++;
348 	if (u.u_rdir)
349 		u.u_rdir->i_count++;
350 	/*
351 	 * Partially simulate the environment
352 	 * of the new process so that when it is actually
353 	 * created (by copying) it will look right.
354 	 */
355 
356 	rip->p_flag |= SKEEP;	/* prevent parent from being swapped */
357 
358 	if (procdup(rpp, isvfork))
359 		return (1);
360 
361 	spl6();
362 	rpp->p_stat = SRUN;
363 	setrq(rpp);
364 	spl0();
365 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
366 	/* rpp->p_flag |= SSWAP; */
367 	rip->p_flag &= ~SKEEP;
368 	if (isvfork) {
369 		u.u_procp->p_xlink = rpp;
370 		u.u_procp->p_flag |= SNOVM;
371 		while (rpp->p_flag & SVFORK)
372 			sleep((caddr_t)rpp, PZERO - 1);
373 		if ((rpp->p_flag & SLOAD) == 0)
374 			panic("newproc vfork");
375 		uaccess(rpp, Vfmap, &vfutl);
376 		u.u_procp->p_xlink = 0;
377 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
378 		for (n = 0; n < NOFILE; n++)
379 			if (vfutl.u_vrpages[n]) {
380 				if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
381 					if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
382 						panic("newproc i_vfdcnt");
383 				vfutl.u_vrpages[n] = 0;
384 			}
385 		u.u_procp->p_flag &= ~SNOVM;
386 		rpp->p_ndx = rpp - proc;
387 		rpp->p_flag |= SVFDONE;
388 		wakeup((caddr_t)rpp);
389 	}
390 	return (0);
391 }
392