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