1*8102Sroot /* kern_synch.c 4.20 82/09/06 */ 233Sbill 333Sbill #include "../h/param.h" 433Sbill #include "../h/systm.h" 533Sbill #include "../h/dir.h" 633Sbill #include "../h/user.h" 733Sbill #include "../h/proc.h" 833Sbill #include "../h/file.h" 933Sbill #include "../h/inode.h" 1033Sbill #include "../h/vm.h" 1133Sbill #include "../h/pte.h" 12181Sbill #include "../h/inline.h" 132443Swnj #include "../h/mtpr.h" 14*8102Sroot #ifdef MUSH 157485Skre #include "../h/quota.h" 16*8102Sroot #include "../h/share.h" 17*8102Sroot #endif 18*8102Sroot #include "../h/kernel.h" 19*8102Sroot #include "../h/buf.h" 2033Sbill 21*8102Sroot /* 22*8102Sroot * Force switch among equal priority processes every 100ms. 23*8102Sroot */ 24*8102Sroot roundrobin() 25*8102Sroot { 26*8102Sroot 27*8102Sroot runrun++; 28*8102Sroot aston(); 29*8102Sroot timeout(roundrobin, 0, hz / 10); 30*8102Sroot } 31*8102Sroot 32*8102Sroot /* 33*8102Sroot * The digital decay cpu usage priority assignment is scaled to run in 34*8102Sroot * time as expanded by the 1 minute load average. Each second we 35*8102Sroot * multiply the the previous cpu usage estimate by 36*8102Sroot * nrscale*avenrun[0] 37*8102Sroot * The following relates the load average to the period over which 38*8102Sroot * cpu usage is 90% forgotten: 39*8102Sroot * loadav 1 5 seconds 40*8102Sroot * loadav 5 24 seconds 41*8102Sroot * loadav 10 47 seconds 42*8102Sroot * loadav 20 93 seconds 43*8102Sroot * This is a great improvement on the previous algorithm which 44*8102Sroot * decayed the priorities by a constant, and decayed away all knowledge 45*8102Sroot * of previous activity in about 20 seconds. Under heavy load, 46*8102Sroot * the previous algorithm degenerated to round-robin with poor response 47*8102Sroot * time when there was a high load average. 48*8102Sroot */ 49*8102Sroot #undef ave 50*8102Sroot #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 51*8102Sroot int nrscale = 2; 52*8102Sroot double avenrun[]; 53*8102Sroot 54*8102Sroot /* 55*8102Sroot * Constant for decay filter for cpu usage field 56*8102Sroot * in process table (used by ps au). 57*8102Sroot */ 58*8102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 59*8102Sroot 60*8102Sroot #ifdef MELB 61*8102Sroot /* 62*8102Sroot * Automatic niceness rate & max constants 63*8102Sroot */ 64*8102Sroot #define MAXNICE (8 + NZERO) /* maximum auto nice value */ 65*8102Sroot #define NFACT (40 * hz) /* nice++ every 40 secs cpu+sys time */ 66*8102Sroot #endif 67*8102Sroot 68*8102Sroot /* 69*8102Sroot * Recompute process priorities, once a second 70*8102Sroot */ 71*8102Sroot schedcpu() 72*8102Sroot { 73*8102Sroot register struct proc *p; 74*8102Sroot register int s, a; 75*8102Sroot 76*8102Sroot s = spl6(); time.tv_sec += lbolt / hz; lbolt %= hz; splx(s); 77*8102Sroot wakeup((caddr_t)&lbolt); 78*8102Sroot 79*8102Sroot for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) { 80*8102Sroot #ifdef MUSH 81*8102Sroot /* 82*8102Sroot * Charge process for memory in use 83*8102Sroot */ 84*8102Sroot if (p->p_quota->q_uid) 85*8102Sroot p->p_quota->q_cost += 86*8102Sroot shconsts.sc_click * p->p_rssize; 87*8102Sroot #endif 88*8102Sroot if (p->p_time != 127) 89*8102Sroot p->p_time++; 90*8102Sroot if (timerisset(&p->p_seltimer) && 91*8102Sroot --p->p_seltimer.tv_sec <= 0) { 92*8102Sroot timerclear(&p->p_seltimer); 93*8102Sroot s = spl6(); 94*8102Sroot switch (p->p_stat) { 95*8102Sroot 96*8102Sroot case SSLEEP: 97*8102Sroot setrun(p); 98*8102Sroot break; 99*8102Sroot 100*8102Sroot case SSTOP: 101*8102Sroot unsleep(p); 102*8102Sroot break; 103*8102Sroot } 104*8102Sroot splx(s); 105*8102Sroot } 106*8102Sroot if (timerisset(&p->p_realtimer.it_value) && 107*8102Sroot itimerdecr(&p->p_realtimer, 1000000) == 0) 108*8102Sroot psignal(p, SIGALRM); 109*8102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 110*8102Sroot if (p->p_slptime != 127) 111*8102Sroot p->p_slptime++; 112*8102Sroot if (p->p_flag&SLOAD) 113*8102Sroot p->p_pctcpu = ccpu * p->p_pctcpu + 114*8102Sroot (1.0 - ccpu) * (p->p_cpticks/(float)hz); 115*8102Sroot p->p_cpticks = 0; 116*8102Sroot #ifdef MUSH 117*8102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 118*8102Sroot p->p_nice - NZERO + p->p_quota->q_nice; 119*8102Sroot #else 120*8102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 121*8102Sroot p->p_nice - NZERO; 122*8102Sroot #endif 123*8102Sroot if (a < 0) 124*8102Sroot a = 0; 125*8102Sroot if (a > 255) 126*8102Sroot a = 255; 127*8102Sroot p->p_cpu = a; 128*8102Sroot (void) setpri(p); 129*8102Sroot s = spl6(); /* prevent state changes */ 130*8102Sroot if (p->p_pri >= PUSER) { 131*8102Sroot if ((p != u.u_procp || noproc) && 132*8102Sroot p->p_stat == SRUN && 133*8102Sroot (p->p_flag & SLOAD) && 134*8102Sroot p->p_pri != p->p_usrpri) { 135*8102Sroot remrq(p); 136*8102Sroot p->p_pri = p->p_usrpri; 137*8102Sroot setrq(p); 138*8102Sroot } else 139*8102Sroot p->p_pri = p->p_usrpri; 140*8102Sroot } 141*8102Sroot splx(s); 142*8102Sroot } 143*8102Sroot vmmeter(); 144*8102Sroot if (runin!=0) { 145*8102Sroot runin = 0; 146*8102Sroot wakeup((caddr_t)&runin); 147*8102Sroot } 148*8102Sroot if (bclnlist != NULL) 149*8102Sroot wakeup((caddr_t)&proc[2]); 150*8102Sroot timeout(schedcpu, 0, hz); 151*8102Sroot } 152*8102Sroot 15333Sbill #define SQSIZE 0100 /* Must be power of 2 */ 15433Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 15533Sbill struct proc *slpque[SQSIZE]; 15633Sbill 15733Sbill /* 15833Sbill * Give up the processor till a wakeup occurs 15933Sbill * on chan, at which time the process 16033Sbill * enters the scheduling queue at priority pri. 16133Sbill * The most important effect of pri is that when 16233Sbill * pri<=PZERO a signal cannot disturb the sleep; 16333Sbill * if pri>PZERO signals will be processed. 16433Sbill * Callers of this routine must be prepared for 16533Sbill * premature return, and check that the reason for 16633Sbill * sleeping has gone away. 16733Sbill */ 16833Sbill sleep(chan, pri) 1698033Sroot caddr_t chan; 1708033Sroot int pri; 17133Sbill { 172187Sbill register struct proc *rp, **hp; 173207Sbill register s; 17433Sbill 17533Sbill rp = u.u_procp; 17633Sbill s = spl6(); 17733Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 17833Sbill panic("sleep"); 17933Sbill rp->p_wchan = chan; 18033Sbill rp->p_slptime = 0; 18133Sbill rp->p_pri = pri; 182187Sbill hp = &slpque[HASH(chan)]; 183187Sbill rp->p_link = *hp; 184187Sbill *hp = rp; 1854826Swnj if (pri > PZERO) { 1864826Swnj if (ISSIG(rp)) { 187187Sbill if (rp->p_wchan) 188187Sbill unsleep(rp); 18933Sbill rp->p_stat = SRUN; 190131Sbill (void) spl0(); 19133Sbill goto psig; 19233Sbill } 193187Sbill if (rp->p_wchan == 0) 194187Sbill goto out; 195187Sbill rp->p_stat = SSLEEP; 196131Sbill (void) spl0(); 1978033Sroot u.u_ru.ru_nvcsw++; 19833Sbill swtch(); 1994826Swnj if (ISSIG(rp)) 20033Sbill goto psig; 20133Sbill } else { 202207Sbill rp->p_stat = SSLEEP; 203131Sbill (void) spl0(); 2048033Sroot u.u_ru.ru_nvcsw++; 20533Sbill swtch(); 20633Sbill } 207187Sbill out: 20833Sbill splx(s); 20933Sbill return; 21033Sbill 21133Sbill /* 21233Sbill * If priority was low (>PZERO) and 2134826Swnj * there has been a signal, execute non-local goto through 2144826Swnj * u.u_qsav, aborting the system call in progress (see trap.c) 2154826Swnj * (or finishing a tsleep, see below) 21633Sbill */ 21733Sbill psig: 21833Sbill longjmp(u.u_qsav); 21933Sbill /*NOTREACHED*/ 22033Sbill } 22133Sbill 22233Sbill /* 2238033Sroot * Sleep on chan at pri for at most a specified amount of time. 2248033Sroot * Return (TS_OK,TS_TIME,TS_SIG) on (normal,timeout,signal) condition. 225100Sbill */ 2268033Sroot tsleep(chan, pri, tvp) 2274826Swnj caddr_t chan; 2288033Sroot int pri; 2298033Sroot struct timeval *tvp; 230100Sbill { 2318033Sroot register struct proc *p = u.u_procp; 2328033Sroot int s, rval; 233100Sbill 2348033Sroot s = spl7(); 235*8102Sroot if (timercmp(tvp, &p->p_realtimer.it_value, >)) { 2368033Sroot /* alarm will occur first! */ 237100Sbill sleep(chan, pri); 2388033Sroot rval = TS_OK; /* almost NOTREACHED modulo fuzz */ 2398033Sroot } else { 2408033Sroot label_t lqsav; 2418033Sroot 2428033Sroot bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 2438033Sroot p->p_seltimer = *tvp; 2448033Sroot if (setjmp(u.u_qsav)) 2458033Sroot rval = TS_SIG; 2468033Sroot else { 2478033Sroot sleep(chan, pri); 248100Sbill rval = TS_OK; 2498033Sroot } 2508033Sroot timerclear(&p->p_seltimer); 2518033Sroot bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 252100Sbill } 2538033Sroot splx(s); 2544826Swnj return (rval); 255100Sbill } 256100Sbill 257100Sbill /* 258181Sbill * Remove a process from its wait queue 259181Sbill */ 260181Sbill unsleep(p) 2614826Swnj register struct proc *p; 262181Sbill { 263181Sbill register struct proc **hp; 264181Sbill register s; 265181Sbill 266181Sbill s = spl6(); 267181Sbill if (p->p_wchan) { 268181Sbill hp = &slpque[HASH(p->p_wchan)]; 269181Sbill while (*hp != p) 270181Sbill hp = &(*hp)->p_link; 271181Sbill *hp = p->p_link; 272181Sbill p->p_wchan = 0; 273181Sbill } 274181Sbill splx(s); 275181Sbill } 276181Sbill 277181Sbill /* 27833Sbill * Wake up all processes sleeping on chan. 27933Sbill */ 28033Sbill wakeup(chan) 2814826Swnj register caddr_t chan; 28233Sbill { 283187Sbill register struct proc *p, **q, **h; 28433Sbill int s; 28533Sbill 28633Sbill s = spl6(); 287187Sbill h = &slpque[HASH(chan)]; 28833Sbill restart: 289187Sbill for (q = h; p = *q; ) { 290181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 29133Sbill panic("wakeup"); 292207Sbill if (p->p_wchan==chan) { 29333Sbill p->p_wchan = 0; 294187Sbill *q = p->p_link; 29533Sbill p->p_slptime = 0; 296181Sbill if (p->p_stat == SSLEEP) { 297181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 298181Sbill p->p_stat = SRUN; 2992702Swnj if (p->p_flag & SLOAD) 300181Sbill setrq(p); 3014826Swnj if (p->p_pri < curpri) { 302181Sbill runrun++; 3032443Swnj aston(); 3042443Swnj } 3053545Swnj if ((p->p_flag&SLOAD) == 0) { 3063545Swnj if (runout != 0) { 3073545Swnj runout = 0; 3083545Swnj wakeup((caddr_t)&runout); 3093545Swnj } 3103545Swnj wantin++; 311181Sbill } 312181Sbill /* END INLINE EXPANSION */ 313187Sbill goto restart; 31433Sbill } 315187Sbill } else 316187Sbill q = &p->p_link; 31733Sbill } 31833Sbill splx(s); 31933Sbill } 32033Sbill 32133Sbill /* 32233Sbill * Initialize the (doubly-linked) run queues 32333Sbill * to be empty. 32433Sbill */ 32533Sbill rqinit() 32633Sbill { 32733Sbill register int i; 32833Sbill 32933Sbill for (i = 0; i < NQS; i++) 33033Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 33133Sbill } 33233Sbill 33333Sbill /* 33433Sbill * Set the process running; 33533Sbill * arrange for it to be swapped in if necessary. 33633Sbill */ 33733Sbill setrun(p) 3384826Swnj register struct proc *p; 33933Sbill { 3404826Swnj register int s; 34133Sbill 34233Sbill s = spl6(); 34333Sbill switch (p->p_stat) { 34433Sbill 34533Sbill case 0: 34633Sbill case SWAIT: 34733Sbill case SRUN: 34833Sbill case SZOMB: 34933Sbill default: 35033Sbill panic("setrun"); 35133Sbill 352207Sbill case SSTOP: 35333Sbill case SSLEEP: 354181Sbill unsleep(p); /* e.g. when sending signals */ 35533Sbill break; 35633Sbill 35733Sbill case SIDL: 35833Sbill break; 35933Sbill } 36033Sbill p->p_stat = SRUN; 36133Sbill if (p->p_flag & SLOAD) 36233Sbill setrq(p); 36333Sbill splx(s); 3644826Swnj if (p->p_pri < curpri) { 36533Sbill runrun++; 3662443Swnj aston(); 3672443Swnj } 3683545Swnj if ((p->p_flag&SLOAD) == 0) { 3694826Swnj if (runout != 0) { 3703545Swnj runout = 0; 3713545Swnj wakeup((caddr_t)&runout); 3723545Swnj } 3733545Swnj wantin++; 37433Sbill } 37533Sbill } 37633Sbill 37733Sbill /* 37833Sbill * Set user priority. 37933Sbill * The rescheduling flag (runrun) 38033Sbill * is set if the priority is better 38133Sbill * than the currently running process. 38233Sbill */ 38333Sbill setpri(pp) 3844826Swnj register struct proc *pp; 38533Sbill { 3864826Swnj register int p; 38733Sbill 3883875Swnj p = (pp->p_cpu & 0377)/4; 3891543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 3903530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3913530Swnj p += 2*4; /* effectively, nice(4) */ 3924826Swnj if (p > 127) 39333Sbill p = 127; 3944826Swnj if (p < curpri) { 39533Sbill runrun++; 3962453Swnj aston(); 3972453Swnj } 39833Sbill pp->p_usrpri = p; 3994826Swnj return (p); 40033Sbill } 401