Commit | Line | Data |
---|---|---|
a379cce8 BJ |
1 | /* kern_synch.c 3.1 %H% */ |
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 | /* THE SSWAP BIT IS REPLACED BY u.u_pcb.pcb_sswap SEE procdup */ | |
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 | } |