xref: /csrg-svn/sys/kern/kern_synch.c (revision 8033)
1 /*	kern_synch.c	4.19	82/09/04	*/
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 #include "../h/quota.h"
15 
16 #define SQSIZE 0100	/* Must be power of 2 */
17 #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
18 struct proc *slpque[SQSIZE];
19 
20 /*
21  * Give up the processor till a wakeup occurs
22  * on chan, at which time the process
23  * enters the scheduling queue at priority pri.
24  * The most important effect of pri is that when
25  * pri<=PZERO a signal cannot disturb the sleep;
26  * if pri>PZERO signals will be processed.
27  * Callers of this routine must be prepared for
28  * premature return, and check that the reason for
29  * sleeping has gone away.
30  */
31 sleep(chan, pri)
32 	caddr_t chan;
33 	int pri;
34 {
35 	register struct proc *rp, **hp;
36 	register s;
37 
38 	rp = u.u_procp;
39 	s = spl6();
40 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
41 		panic("sleep");
42 	rp->p_wchan = chan;
43 	rp->p_slptime = 0;
44 	rp->p_pri = pri;
45 	hp = &slpque[HASH(chan)];
46 	rp->p_link = *hp;
47 	*hp = rp;
48 	if (pri > PZERO) {
49 		if (ISSIG(rp)) {
50 			if (rp->p_wchan)
51 				unsleep(rp);
52 			rp->p_stat = SRUN;
53 			(void) spl0();
54 			goto psig;
55 		}
56 		if (rp->p_wchan == 0)
57 			goto out;
58 		rp->p_stat = SSLEEP;
59 		(void) spl0();
60 		u.u_ru.ru_nvcsw++;
61 		swtch();
62 		if (ISSIG(rp))
63 			goto psig;
64 	} else {
65 		rp->p_stat = SSLEEP;
66 		(void) spl0();
67 		u.u_ru.ru_nvcsw++;
68 		swtch();
69 	}
70 out:
71 	splx(s);
72 	return;
73 
74 	/*
75 	 * If priority was low (>PZERO) and
76 	 * there has been a signal, execute non-local goto through
77 	 * u.u_qsav, aborting the system call in progress (see trap.c)
78 	 * (or finishing a tsleep, see below)
79 	 */
80 psig:
81 	longjmp(u.u_qsav);
82 	/*NOTREACHED*/
83 }
84 
85 /*
86  * Sleep on chan at pri for at most a specified amount of time.
87  * Return (TS_OK,TS_TIME,TS_SIG) on (normal,timeout,signal) condition.
88  */
89 tsleep(chan, pri, tvp)
90 	caddr_t chan;
91 	int pri;
92 	struct timeval *tvp;
93 {
94 	register struct proc *p = u.u_procp;
95 	int s, rval;
96 
97 	s = spl7();
98 	if (timercmp(tvp, &p->p_realtimer.itimer_value, >)) {
99 		/* alarm will occur first! */
100 		sleep(chan, pri);
101 		rval = TS_OK;		/* almost NOTREACHED modulo fuzz */
102 	} else {
103 		label_t lqsav;
104 
105 		bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
106 		p->p_seltimer = *tvp;
107 		if (setjmp(u.u_qsav))
108 			rval = TS_SIG;
109 		else {
110 			sleep(chan, pri);
111 			rval = TS_OK;
112 		}
113 		timerclear(&p->p_seltimer);
114 		bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
115 	}
116 	splx(s);
117 	return (rval);
118 }
119 
120 /*
121  * Remove a process from its wait queue
122  */
123 unsleep(p)
124 	register struct proc *p;
125 {
126 	register struct proc **hp;
127 	register s;
128 
129 	s = spl6();
130 	if (p->p_wchan) {
131 		hp = &slpque[HASH(p->p_wchan)];
132 		while (*hp != p)
133 			hp = &(*hp)->p_link;
134 		*hp = p->p_link;
135 		p->p_wchan = 0;
136 	}
137 	splx(s);
138 }
139 
140 /*
141  * Wake up all processes sleeping on chan.
142  */
143 wakeup(chan)
144 	register caddr_t chan;
145 {
146 	register struct proc *p, **q, **h;
147 	int s;
148 
149 	s = spl6();
150 	h = &slpque[HASH(chan)];
151 restart:
152 	for (q = h; p = *q; ) {
153 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
154 			panic("wakeup");
155 		if (p->p_wchan==chan) {
156 			p->p_wchan = 0;
157 			*q = p->p_link;
158 			p->p_slptime = 0;
159 			if (p->p_stat == SSLEEP) {
160 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
161 				p->p_stat = SRUN;
162 				if (p->p_flag & SLOAD)
163 					setrq(p);
164 				if (p->p_pri < curpri) {
165 					runrun++;
166 					aston();
167 				}
168 				if ((p->p_flag&SLOAD) == 0) {
169 					if (runout != 0) {
170 						runout = 0;
171 						wakeup((caddr_t)&runout);
172 					}
173 					wantin++;
174 				}
175 				/* END INLINE EXPANSION */
176 				goto restart;
177 			}
178 		} else
179 			q = &p->p_link;
180 	}
181 	splx(s);
182 }
183 
184 /*
185  * Initialize the (doubly-linked) run queues
186  * to be empty.
187  */
188 rqinit()
189 {
190 	register int i;
191 
192 	for (i = 0; i < NQS; i++)
193 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
194 }
195 
196 /*
197  * Set the process running;
198  * arrange for it to be swapped in if necessary.
199  */
200 setrun(p)
201 	register struct proc *p;
202 {
203 	register int s;
204 
205 	s = spl6();
206 	switch (p->p_stat) {
207 
208 	case 0:
209 	case SWAIT:
210 	case SRUN:
211 	case SZOMB:
212 	default:
213 		panic("setrun");
214 
215 	case SSTOP:
216 	case SSLEEP:
217 		unsleep(p);		/* e.g. when sending signals */
218 		break;
219 
220 	case SIDL:
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 		aston();
230 	}
231 	if ((p->p_flag&SLOAD) == 0) {
232 		if (runout != 0) {
233 			runout = 0;
234 			wakeup((caddr_t)&runout);
235 		}
236 		wantin++;
237 	}
238 }
239 
240 /*
241  * Set user priority.
242  * The rescheduling flag (runrun)
243  * is set if the priority is better
244  * than the currently running process.
245  */
246 setpri(pp)
247 	register struct proc *pp;
248 {
249 	register int p;
250 
251 	p = (pp->p_cpu & 0377)/4;
252 	p += PUSER + 2*(pp->p_nice - NZERO);
253 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
254 		p += 2*4;	/* effectively, nice(4) */
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  */
270 newproc(isvfork)
271 	int isvfork;
272 {
273 	register struct proc *p;
274 	register struct proc *rpp, *rip;
275 	register int n;
276 	register struct file *fp;
277 
278 	p = NULL;
279 	/*
280 	 * First, just locate a slot for a process
281 	 * and copy the useful info from this process into it.
282 	 * The panic "cannot happen" because fork has already
283 	 * checked for the existence of a slot.
284 	 */
285 retry:
286 	mpid++;
287 	if (mpid >= 30000) {
288 		mpid = 0;
289 		goto retry;
290 	}
291 	for (rpp = proc; rpp < procNPROC; rpp++) {
292 		if (rpp->p_stat == NULL && p==NULL)
293 			p = rpp;
294 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
295 			goto retry;
296 	}
297 	if ((rpp = p) == NULL)
298 		panic("no procs");
299 
300 	/*
301 	 * Make a proc table entry for the new process.
302 	 */
303 	rip = u.u_procp;
304 #ifdef QUOTA
305 	(rpp->p_quota = rip->p_quota)->q_cnt++;
306 #endif
307 	rpp->p_stat = SIDL;
308 	timerclear(&rpp->p_realtimer.itimer_value);
309 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG));
310 	if (isvfork) {
311 		rpp->p_flag |= SVFORK;
312 		rpp->p_ndx = rip->p_ndx;
313 	} else
314 		rpp->p_ndx = rpp - proc;
315 	rpp->p_uid = rip->p_uid;
316 	rpp->p_pgrp = rip->p_pgrp;
317 	rpp->p_nice = rip->p_nice;
318 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
319 	rpp->p_pid = mpid;
320 	rpp->p_ppid = rip->p_pid;
321 	rpp->p_pptr = rip;
322 	rpp->p_osptr = rip->p_cptr;
323 	if (rip->p_cptr)
324 		rip->p_cptr->p_ysptr = rpp;
325 	rpp->p_ysptr = NULL;
326 	rpp->p_cptr = NULL;
327 	rip->p_cptr = rpp;
328 	rpp->p_time = 0;
329 	rpp->p_cpu = 0;
330 	rpp->p_siga0 = rip->p_siga0;
331 	rpp->p_siga1 = rip->p_siga1;
332 	/* take along any pending signals, like stops? */
333 	if (isvfork) {
334 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
335 		rpp->p_szpt = clrnd(ctopt(UPAGES));
336 		forkstat.cntvfork++;
337 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
338 	} else {
339 		rpp->p_tsize = rip->p_tsize;
340 		rpp->p_dsize = rip->p_dsize;
341 		rpp->p_ssize = rip->p_ssize;
342 		rpp->p_szpt = rip->p_szpt;
343 		forkstat.cntfork++;
344 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
345 	}
346 	rpp->p_rssize = 0;
347 	rpp->p_maxrss = rip->p_maxrss;
348 	rpp->p_wchan = 0;
349 	rpp->p_slptime = 0;
350 	rpp->p_pctcpu = 0;
351 	rpp->p_cpticks = 0;
352 	n = PIDHASH(rpp->p_pid);
353 	p->p_idhash = pidhash[n];
354 	pidhash[n] = rpp - proc;
355 	multprog++;
356 
357 	/*
358 	 * Increase reference counts on shared objects.
359 	 */
360 	for (n = 0; n < NOFILE; n++) {
361 		fp = u.u_ofile[n];
362 		if (fp == NULL)
363 			continue;
364 		fp->f_count++;
365 		if (u.u_pofile[n]&RDLOCK)
366 			fp->f_inode->i_rdlockc++;
367 		if (u.u_pofile[n]&WRLOCK)
368 			fp->f_inode->i_wrlockc++;
369 	}
370 	u.u_cdir->i_count++;
371 	if (u.u_rdir)
372 		u.u_rdir->i_count++;
373 
374 	/*
375 	 * Partially simulate the environment
376 	 * of the new process so that when it is actually
377 	 * created (by copying) it will look right.
378 	 * This begins the section where we must prevent the parent
379 	 * from being swapped.
380 	 */
381 	rip->p_flag |= SKEEP;
382 	if (procdup(rpp, isvfork))
383 		return (1);
384 
385 	/*
386 	 * Make child runnable and add to run queue.
387 	 */
388 	(void) spl6();
389 	rpp->p_stat = SRUN;
390 	setrq(rpp);
391 	(void) spl0();
392 
393 	/*
394 	 * Cause child to take a non-local goto as soon as it runs.
395 	 * On older systems this was done with SSWAP bit in proc
396 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
397 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
398 	 */
399 	/* rpp->p_flag |= SSWAP; */
400 
401 	/*
402 	 * Now can be swapped.
403 	 */
404 	rip->p_flag &= ~SKEEP;
405 
406 	/*
407 	 * If vfork make chain from parent process to child
408 	 * (where virtal memory is temporarily).  Wait for
409 	 * child to finish, steal virtual memory back,
410 	 * and wakeup child to let it die.
411 	 */
412 	if (isvfork) {
413 		u.u_procp->p_xlink = rpp;
414 		u.u_procp->p_flag |= SNOVM;
415 		while (rpp->p_flag & SVFORK)
416 			sleep((caddr_t)rpp, PZERO - 1);
417 		if ((rpp->p_flag & SLOAD) == 0)
418 			panic("newproc vfork");
419 		uaccess(rpp, Vfmap, &vfutl);
420 		u.u_procp->p_xlink = 0;
421 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
422 		u.u_procp->p_flag &= ~SNOVM;
423 		rpp->p_ndx = rpp - proc;
424 		rpp->p_flag |= SVFDONE;
425 		wakeup((caddr_t)rpp);
426 	}
427 
428 	/*
429 	 * 0 return means parent.
430 	 */
431 	return (0);
432 }
433