xref: /csrg-svn/sys/kern/kern_synch.c (revision 102)
1 /*	kern_synch.c	3.5	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 		if ((sec = pp->p_clktim-seconds) < 0)
105 			sec = 0;
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 	pp->p_clktim += sec;
121 	splx(n);
122 	return(rval);
123 }
124 
125 /*
126  * Wake up all processes sleeping on chan.
127  */
128 wakeup(chan)
129 register caddr_t chan;
130 {
131 	register struct proc *p, *q;
132 	register i;
133 	int s;
134 
135 	s = spl6();
136 	i = HASH(chan);
137 restart:
138 	p = slpque[i];
139 	q = NULL;
140 	while(p != NULL) {
141 		if (p->p_rlink || p->p_stat != SSLEEP)
142 			panic("wakeup");
143 		if (p->p_wchan==chan && p->p_stat!=SZOMB) {
144 			if (q == NULL)
145 				slpque[i] = p->p_link;
146 			else
147 				q->p_link = p->p_link;
148 			p->p_wchan = 0;
149 			p->p_slptime = 0;
150 			/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
151 			p->p_stat = SRUN;
152 			if (p->p_flag & SLOAD) {
153 #ifndef FASTVAX
154 				p->p_link = runq;
155 				runq = p->p_link;
156 #else
157 				setrq(p);
158 #endif
159 			}
160 			if(p->p_pri < curpri)
161 				runrun++;
162 			if(runout != 0 && (p->p_flag&SLOAD) == 0) {
163 				runout = 0;
164 				wakeup((caddr_t)&runout);
165 			}
166 			/* END INLINE EXPANSION */
167 			goto restart;
168 		}
169 		q = p;
170 		p = p->p_link;
171 	}
172 	splx(s);
173 }
174 
175 #ifdef FASTVAX
176 /*
177  * Initialize the (doubly-linked) run queues
178  * to be empty.
179  */
180 rqinit()
181 {
182 	register int i;
183 
184 	for (i = 0; i < NQS; i++)
185 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
186 }
187 #endif
188 
189 /*
190  * Set the process running;
191  * arrange for it to be swapped in if necessary.
192  */
193 setrun(p)
194 register struct proc *p;
195 {
196 	register caddr_t w;
197 	register s;
198 
199 	s = spl6();
200 	switch (p->p_stat) {
201 
202 	case 0:
203 	case SWAIT:
204 	case SRUN:
205 	case SZOMB:
206 	default:
207 		panic("setrun");
208 
209 	case SSLEEP:
210 		if (w = p->p_wchan) {
211 			wakeup(w);
212 			splx(s);
213 			return;
214 		}
215 		break;
216 
217 	case SIDL:
218 	case SSTOP:
219 		break;
220 	}
221 	p->p_stat = SRUN;
222 	if (p->p_flag & SLOAD)
223 		setrq(p);
224 	splx(s);
225 	if(p->p_pri < curpri)
226 		runrun++;
227 	if(runout != 0 && (p->p_flag&SLOAD) == 0) {
228 		runout = 0;
229 		wakeup((caddr_t)&runout);
230 	}
231 }
232 
233 /*
234  * Set user priority.
235  * The rescheduling flag (runrun)
236  * is set if the priority is better
237  * than the currently running process.
238  */
239 setpri(pp)
240 register struct proc *pp;
241 {
242 	register p;
243 
244 	p = (pp->p_cpu & 0377)/16;
245 	p += PUSER + pp->p_nice - NZERO;
246 	if(p > 127)
247 		p = 127;
248 	if(p < curpri)
249 		runrun++;
250 	pp->p_usrpri = p;
251 	return(p);
252 }
253 
254 /*
255  * Create a new process-- the internal version of
256  * sys fork.
257  * It returns 1 in the new process, 0 in the old.
258  */
259 newproc(isvfork)
260 {
261 	register struct proc *p;
262 	register struct proc *rpp, *rip;
263 	register int n;
264 
265 	p = NULL;
266 	/*
267 	 * First, just locate a slot for a process
268 	 * and copy the useful info from this process into it.
269 	 * The panic "cannot happen" because fork has already
270 	 * checked for the existence of a slot.
271 	 */
272 retry:
273 	mpid++;
274 	if(mpid >= 30000) {
275 		mpid = 0;
276 		goto retry;
277 	}
278 	for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
279 		if(rpp->p_stat == NULL && p==NULL)
280 			p = rpp;
281 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
282 			goto retry;
283 	}
284 	if ((rpp = p)==NULL)
285 		panic("no procs");
286 
287 	/*
288 	 * make proc entry for new proc
289 	 */
290 
291 	rip = u.u_procp;
292 	rpp->p_stat = SIDL;
293 	rpp->p_clktim = 0;
294 	rpp->p_flag = SLOAD | (rip->p_flag & SPAGI);
295 	if (isvfork) {
296 		rpp->p_flag |= SVFORK;
297 		rpp->p_ndx = rip->p_ndx;
298 	} else
299 		rpp->p_ndx = rpp - proc;
300 	rpp->p_uid = rip->p_uid;
301 	rpp->p_pgrp = rip->p_pgrp;
302 	rpp->p_nice = rip->p_nice;
303 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
304 	rpp->p_pid = mpid;
305 	rpp->p_ppid = rip->p_pid;
306 	rpp->p_time = 0;
307 	rpp->p_cpu = 0;
308 	if (isvfork) {
309 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
310 		rpp->p_szpt = clrnd(ctopt(UPAGES));
311 		forkstat.cntvfork++;
312 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
313 	} else {
314 		rpp->p_tsize = rip->p_tsize;
315 		rpp->p_dsize = rip->p_dsize;
316 		rpp->p_ssize = rip->p_ssize;
317 		rpp->p_szpt = rip->p_szpt;
318 		forkstat.cntfork++;
319 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
320 	}
321 	rpp->p_rssize = 0;
322 	rpp->p_wchan = 0;
323 	rpp->p_slptime = 0;
324 	rpp->p_aveflt = rip->p_aveflt;
325 	rate.v_pgin += rip->p_aveflt;
326 	rpp->p_faults = 0;
327 	n = PIDHASH(rpp->p_pid);
328 	p->p_idhash = pidhash[n];
329 	pidhash[n] = rpp - proc;
330 
331 	/*
332 	 * make duplicate entries
333 	 * where needed
334 	 */
335 
336 	multprog++;
337 
338 	for(n=0; n<NOFILE; n++)
339 		if(u.u_ofile[n] != NULL) {
340 			u.u_ofile[n]->f_count++;
341 			if(!isvfork && u.u_vrpages[n])
342 				u.u_ofile[n]->f_inode->i_vfdcnt++;
343 		}
344 
345 	u.u_cdir->i_count++;
346 	if (u.u_rdir)
347 		u.u_rdir->i_count++;
348 	/*
349 	 * Partially simulate the environment
350 	 * of the new process so that when it is actually
351 	 * created (by copying) it will look right.
352 	 */
353 
354 	rip->p_flag |= SKEEP;	/* prevent parent from being swapped */
355 
356 	if (procdup(rpp, isvfork))
357 		return (1);
358 
359 	spl6();
360 	rpp->p_stat = SRUN;
361 	setrq(rpp);
362 	spl0();
363 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
364 	/* rpp->p_flag |= SSWAP; */
365 	rip->p_flag &= ~SKEEP;
366 	if (isvfork) {
367 		u.u_procp->p_xlink = rpp;
368 		u.u_procp->p_flag |= SNOVM;
369 		while (rpp->p_flag & SVFORK)
370 			sleep((caddr_t)rpp, PZERO - 1);
371 		if ((rpp->p_flag & SLOAD) == 0)
372 			panic("newproc vfork");
373 		uaccess(rpp, Vfmap, &vfutl);
374 		u.u_procp->p_xlink = 0;
375 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
376 		for (n = 0; n < NOFILE; n++)
377 			if (vfutl.u_vrpages[n]) {
378 				if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
379 					if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
380 						panic("newproc i_vfdcnt");
381 				vfutl.u_vrpages[n] = 0;
382 			}
383 		u.u_procp->p_flag &= ~SNOVM;
384 		rpp->p_ndx = rpp - proc;
385 		rpp->p_flag |= SVFDONE;
386 		wakeup((caddr_t)rpp);
387 	}
388 	return (0);
389 }
390