02050 #include "../h/param.h" 02051 #include "../h/systm.h" 02052 #include "../h/dir.h" 02053 #include "../h/user.h" 02054 #include "../h/proc.h" 02055 #include "../h/text.h" 02056 #include "../h/map.h" 02057 #include "../h/file.h" 02058 #include "../h/inode.h" 02059 #include "../h/buf.h" 02060 02061 #define SQSIZE 0100 /* Must be power of 2 */ 02062 #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 02063 struct proc *slpque[SQSIZE]; 02064 02065 /* 02066 * Give up the processor till a wakeup occurs 02067 * on chan, at which time the process 02068 * enters the scheduling queue at priority pri. 02069 * The most important effect of pri is that when 02070 * pri<=PZERO a signal cannot disturb the sleep; 02071 * if pri>PZERO signals will be processed. 02072 * Callers of this routine must be prepared for 02073 * premature return, and check that the reason for 02074 * sleeping has gone away. 02075 */ 02076 sleep(chan, pri) 02077 caddr_t chan; 02078 { 02079 register struct proc *rp; 02080 register s, h; 02081 02082 rp = u.u_procp; 02083 s = spl6(); 02084 if (chan==0) 02085 panic("zero wchan"); 02086 rp->p_stat = SSLEEP; 02087 rp->p_wchan = chan; 02088 if (chan==0) 02089 panic("Sleeping on wchan 0"); 02090 rp->p_pri = pri; 02091 h = HASH(chan); 02092 rp->p_link = slpque[h]; 02093 slpque[h] = rp; 02094 if(pri > PZERO) { 02095 if(issig()) { 02096 rp->p_wchan = 0; 02097 rp->p_stat = SRUN; 02098 slpque[h] = rp->p_link; 02099 spl0(); 02100 goto psig; 02101 } 02102 spl0(); 02103 if(runin != 0) { 02104 runin = 0; 02105 wakeup((caddr_t)&runin); 02106 } 02107 swtch(); 02108 if(issig()) 02109 goto psig; 02110 } else { 02111 spl0(); 02112 swtch(); 02113 } 02114 splx(s); 02115 return; 02116 02117 /* 02118 * If priority was low (>PZERO) and 02119 * there has been a signal, 02120 * execute non-local goto to 02121 * the qsav location. 02122 * (see trap1/trap.c) 02123 */ 02124 psig: 02125 resume(u.u_procp->p_addr, u.u_qsav); 02126 } 02127 02128 /* 02129 * Wake up all processes sleeping on chan. 02130 */ 02131 wakeup(chan) 02132 register caddr_t chan; 02133 { 02134 register struct proc *p, *q; 02135 register i; 02136 int s; 02137 02138 s = spl6(); 02139 i = HASH(chan); 02140 p = slpque[i]; 02141 q = NULL; 02142 while(p != NULL) { 02143 if(p->p_wchan==chan && p->p_stat!=SZOMB) { 02144 struct proc *sp; 02145 02146 if (q == NULL) 02147 sp = slpque[i] = p->p_link; 02148 else 02149 sp = q->p_link = p->p_link; 02150 p->p_wchan = 0; 02151 setrun(p); 02152 p = sp; 02153 continue; 02154 } 02155 q = p; 02156 p = p->p_link; 02157 } 02158 splx(s); 02159 } 02160 02161 /* 02162 * when you are sure that it 02163 * is impossible to get the 02164 * 'proc on q' diagnostic, the 02165 * diagnostic loop can be removed. 02166 */ 02167 setrq(p) 02168 struct proc *p; 02169 { 02170 register struct proc *q; 02171 register s; 02172 02173 s = spl6(); 02174 for(q=runq; q!=NULL; q=q->p_link) 02175 if(q == p) { 02176 printf("proc on q\n"); 02177 goto out; 02178 } 02179 p->p_link = runq; 02180 runq = p; 02181 out: 02182 splx(s); 02183 } 02184 02185 /* 02186 * Set the process running; 02187 * arrange for it to be swapped in if necessary. 02188 */ 02189 setrun(p) 02190 register struct proc *p; 02191 { 02192 register caddr_t w; 02193 02194 if (p->p_stat==0 || p->p_stat==SZOMB) 02195 panic("Running a dead proc"); 02196 /* 02197 * The assignment to w is necessary because of 02198 * race conditions. (Interrupt between test and use) 02199 */ 02200 if (w = p->p_wchan) { 02201 wakeup(w); 02202 return; 02203 } 02204 p->p_stat = SRUN; 02205 setrq(p); 02206 if(p->p_pri < curpri) 02207 runrun++; 02208 if(runout != 0 && (p->p_flag&SLOAD) == 0) { 02209 runout = 0; 02210 wakeup((caddr_t)&runout); 02211 } 02212 } 02213 02214 /* 02215 * Set user priority. 02216 * The rescheduling flag (runrun) 02217 * is set if the priority is better 02218 * than the currently running process. 02219 */ 02220 setpri(pp) 02221 register struct proc *pp; 02222 { 02223 register p; 02224 02225 p = (pp->p_cpu & 0377)/16; 02226 p += PUSER + pp->p_nice - NZERO; 02227 if(p > 127) 02228 p = 127; 02229 if(p < curpri) 02230 runrun++; 02231 pp->p_pri = p; 02232 return(p); 02233 } 02234 02235 /* 02236 * The main loop of the scheduling (swapping) 02237 * process. 02238 * The basic idea is: 02239 * see if anyone wants to be swapped in; 02240 * swap out processes until there is room; 02241 * swap him in; 02242 * repeat. 02243 * The runout flag is set whenever someone is swapped out. 02244 * Sched sleeps on it awaiting work. 02245 * 02246 * Sched sleeps on runin whenever it cannot find enough 02247 * core (by swapping out or otherwise) to fit the 02248 * selected swapped process. It is awakened when the 02249 * core situation changes and in any case once per second. 02250 */ 02251 sched() 02252 { 02253 register struct proc *rp, *p; 02254 register outage, inage; 02255 int maxsize; 02256 02257 /* 02258 * find user to swap in; 02259 * of users ready, select one out longest 02260 */ 02261 02262 loop: 02263 spl6(); 02264 outage = -20000; 02265 for (rp = &proc[0]; rp < &proc[NPROC]; rp++) 02266 if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 && 02267 rp->p_time - (rp->p_nice-NZERO)*8 > outage) { 02268 p = rp; 02269 outage = rp->p_time - (rp->p_nice-NZERO)*8; 02270 } 02271 /* 02272 * If there is no one there, wait. 02273 */ 02274 if (outage == -20000) { 02275 runout++; 02276 sleep((caddr_t)&runout, PSWP); 02277 goto loop; 02278 } 02279 spl0(); 02280 02281 /* 02282 * See if there is core for that process; 02283 * if so, swap it in. 02284 */ 02285 02286 if (swapin(p)) 02287 goto loop; 02288 02289 /* 02290 * none found. 02291 * look around for core. 02292 * Select the largest of those sleeping 02293 * at bad priority; if none, select the oldest. 02294 */ 02295 02296 spl6(); 02297 p = NULL; 02298 maxsize = -1; 02299 inage = -1; 02300 for (rp = &proc[0]; rp < &proc[NPROC]; rp++) { 02301 if (rp->p_stat==SZOMB 02302 || (rp->p_flag&(SSYS|SLOCK|SULOCK|SLOAD))!=SLOAD) 02303 continue; 02304 if (rp->p_textp && rp->p_textp->x_flag&XLOCK) 02305 continue; 02306 if (rp->p_stat==SSLEEP&&rp->p_pri>=PZERO || rp->p_stat==SSTOP) { 02307 if (maxsize < rp->p_size) { 02308 p = rp; 02309 maxsize = rp->p_size; 02310 } 02311 } else if (maxsize<0 && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) { 02312 if (rp->p_time+rp->p_nice-NZERO > inage) { 02313 p = rp; 02314 inage = rp->p_time+rp->p_nice-NZERO; 02315 } 02316 } 02317 } 02318 spl0(); 02319 /* 02320 * Swap found user out if sleeping at bad pri, 02321 * or if he has spent at least 2 seconds in core and 02322 * the swapped-out process has spent at least 3 seconds out. 02323 * Otherwise wait a bit and try again. 02324 */ 02325 if (maxsize>=0 || (outage>=3 && inage>=2)) { 02326 p->p_flag &= ~SLOAD; 02327 xswap(p, 1, 0); 02328 goto loop; 02329 } 02330 spl6(); 02331 runin++; 02332 sleep((caddr_t)&runin, PSWP); 02333 goto loop; 02334 } 02335 02336 /* 02337 * Swap a process in. 02338 * Allocate data and possible text separately. 02339 * It would be better to do largest first. 02340 */ 02341 swapin(p) 02342 register struct proc *p; 02343 { 02344 register struct text *xp; 02345 register int a; 02346 int x; 02347 02348 if ((a = malloc(coremap, p->p_size)) == NULL) 02349 return(0); 02350 if (xp = p->p_textp) { 02351 xlock(xp); 02352 if (xp->x_ccount==0) { 02353 if ((x = malloc(coremap, xp->x_size)) == NULL) { 02354 xunlock(xp); 02355 mfree(coremap, p->p_size, a); 02356 return(0); 02357 } 02358 xp->x_caddr = x; 02359 if ((xp->x_flag&XLOAD)==0) 02360 swap(xp->x_daddr,x,xp->x_size,B_READ); 02361 } 02362 xp->x_ccount++; 02363 xunlock(xp); 02364 } 02365 swap(p->p_addr, a, p->p_size, B_READ); 02366 mfree(swapmap, ctod(p->p_size), p->p_addr); 02367 p->p_addr = a; 02368 p->p_flag |= SLOAD; 02369 p->p_time = 0; 02370 return(1); 02371 } 02372 02373 /* 02374 * put the current process on 02375 * the Q of running processes and 02376 * call the scheduler. 02377 */ 02378 qswtch() 02379 { 02380 02381 setrq(u.u_procp); 02382 swtch(); 02383 } 02384 02385 /* 02386 * This routine is called to reschedule the CPU. 02387 * if the calling process is not in RUN state, 02388 * arrangements for it to restart must have 02389 * been made elsewhere, usually by calling via sleep. 02390 * There is a race here. A process may become 02391 * ready after it has been examined. 02392 * In this case, idle() will be called and 02393 * will return in at most 1HZ time. 02394 * i.e. its not worth putting an spl() in. 02395 */ 02396 swtch() 02397 { 02398 register n; 02399 register struct proc *p, *q, *pp, *pq; 02400 02401 /* 02402 * If not the idle process, resume the idle process. 02403 */ 02404 if (u.u_procp != &proc[0]) { 02405 if (save(u.u_rsav)) { 02406 sureg(); 02407 return; 02408 } 02409 if (u.u_fpsaved==0) { 02410 savfp(&u.u_fps); 02411 u.u_fpsaved = 1; 02412 } 02413 resume(proc[0].p_addr, u.u_qsav); 02414 } 02415 /* 02416 * The first save returns nonzero when proc 0 is resumed 02417 * by another process (above); then the second is not done 02418 * and the process-search loop is entered. 02419 * 02420 * The first save returns 0 when swtch is called in proc 0 02421 * from sched(). The second save returns 0 immediately, so 02422 * in this case too the process-search loop is entered. 02423 * Thus when proc 0 is awakened by being made runnable, it will 02424 * find itself and resume itself at rsav, and return to sched(). 02425 */ 02426 if (save(u.u_qsav)==0 && save(u.u_rsav)) 02427 return; 02428 loop: 02429 spl6(); 02430 runrun = 0; 02431 pp = NULL; 02432 q = NULL; 02433 n = 128; 02434 /* 02435 * Search for highest-priority runnable process 02436 */ 02437 for(p=runq; p!=NULL; p=p->p_link) { 02438 if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) { 02439 if(p->p_pri < n) { 02440 pp = p; 02441 pq = q; 02442 n = p->p_pri; 02443 } 02444 } 02445 q = p; 02446 } 02447 /* 02448 * If no process is runnable, idle. 02449 */ 02450 p = pp; 02451 if(p == NULL) { 02452 idle(); 02453 goto loop; 02454 } 02455 q = pq; 02456 if(q == NULL) 02457 runq = p->p_link; 02458 else 02459 q->p_link = p->p_link; 02460 curpri = n; 02461 spl0(); 02462 /* 02463 * The rsav (ssav) contents are interpreted in the new address space 02464 */ 02465 n = p->p_flag&SSWAP; 02466 p->p_flag &= ~SSWAP; 02467 resume(p->p_addr, n? u.u_ssav: u.u_rsav); 02468 } 02469 02470 /* 02471 * Create a new process-- the internal version of 02472 * sys fork. 02473 * It returns 1 in the new process, 0 in the old. 02474 */ 02475 newproc() 02476 { 02477 int a1, a2; 02478 struct proc *p, *up; 02479 register struct proc *rpp, *rip; 02480 register n; 02481 02482 p = NULL; 02483 /* 02484 * First, just locate a slot for a process 02485 * and copy the useful info from this process into it. 02486 * The panic "cannot happen" because fork has already 02487 * checked for the existence of a slot. 02488 */ 02489 retry: 02490 mpid++; 02491 if(mpid >= 30000) { 02492 mpid = 0; 02493 goto retry; 02494 } 02495 for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 02496 if(rpp->p_stat == NULL && p==NULL) 02497 p = rpp; 02498 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 02499 goto retry; 02500 } 02501 if ((rpp = p)==NULL) 02502 panic("no procs"); 02503 02504 /* 02505 * make proc entry for new proc 02506 */ 02507 02508 rip = u.u_procp; 02509 up = rip; 02510 rpp->p_stat = SRUN; 02511 rpp->p_clktim = 0; 02512 rpp->p_flag = SLOAD; 02513 rpp->p_uid = rip->p_uid; 02514 rpp->p_pgrp = rip->p_pgrp; 02515 rpp->p_nice = rip->p_nice; 02516 rpp->p_textp = rip->p_textp; 02517 rpp->p_pid = mpid; 02518 rpp->p_ppid = rip->p_pid; 02519 rpp->p_time = 0; 02520 rpp->p_cpu = 0; 02521 02522 /* 02523 * make duplicate entries 02524 * where needed 02525 */ 02526 02527 for(n=0; n02528 if(u.u_ofile[n] != NULL) 02529 u.u_ofile[n]->f_count++; 02530 if(up->p_textp != NULL) { 02531 up->p_textp->x_count++; 02532 up->p_textp->x_ccount++; 02533 } 02534 u.u_cdir->i_count++; 02535 if (u.u_rdir) 02536 u.u_rdir->i_count++; 02537 /* 02538 * Partially simulate the environment 02539 * of the new process so that when it is actually 02540 * created (by copying) it will look right. 02541 */ 02542 rpp = p; 02543 u.u_procp = rpp; 02544 rip = up; 02545 n = rip->p_size; 02546 a1 = rip->p_addr; 02547 rpp->p_size = n; 02548 /* 02549 * When the resume is executed for the new process, 02550 * here's where it will resume. 02551 */ 02552 if (save(u.u_ssav)) { 02553 sureg(); 02554 return(1); 02555 } 02556 a2 = malloc(coremap, n); 02557 /* 02558 * If there is not enough core for the 02559 * new process, swap out the current process to generate the 02560 * copy. 02561 */ 02562 if(a2 == NULL) { 02563 rip->p_stat = SIDL; 02564 rpp->p_addr = a1; 02565 xswap(rpp, 0, 0); 02566 rip->p_stat = SRUN; 02567 } else { 02568 /* 02569 * There is core, so just copy. 02570 */ 02571 rpp->p_addr = a2; 02572 while(n--) 02573 copyseg(a1++, a2++); 02574 } 02575 u.u_procp = rip; 02576 setrq(rpp); 02577 rpp->p_flag |= SSWAP; 02578 return(0); 02579 } 02580 02581 /* 02582 * Change the size of the data+stack regions of the process. 02583 * If the size is shrinking, it's easy-- just release the extra core. 02584 * If it's growing, and there is core, just allocate it 02585 * and copy the image, taking care to reset registers to account 02586 * for the fact that the system's stack has moved. 02587 * If there is no core, arrange for the process to be swapped 02588 * out after adjusting the size requirement-- when it comes 02589 * in, enough core will be allocated. 02590 * 02591 * After the expansion, the caller will take care of copying 02592 * the user's stack towards or away from the data area. 02593 */ 02594 expand(newsize) 02595 { 02596 register i, n; 02597 register struct proc *p; 02598 register a1, a2; 02599 02600 p = u.u_procp; 02601 n = p->p_size; 02602 p->p_size = newsize; 02603 a1 = p->p_addr; 02604 if(n >= newsize) { 02605 mfree(coremap, n-newsize, a1+newsize); 02606 return; 02607 } 02608 if (save(u.u_ssav)) { 02609 sureg(); 02610 return; 02611 } 02612 a2 = malloc(coremap, newsize); 02613 if(a2 == NULL) { 02614 xswap(p, 1, n); 02615 p->p_flag |= SSWAP; 02616 qswtch(); 02617 /* no return */ 02618 } 02619 p->p_addr = a2; 02620 for(i=0; i02621 copyseg(a1+i, a2+i); 02622 mfree(coremap, n, a1); 02623 resume(a2, u.u_ssav); 02624 } 02625 02626 02627 02628 02629 02630 02631 02632 02633 02634 02635 02636 02637 02638 02639 02640 02641 02642 02643 02644 02645 02646 02647 02648 02649