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