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