1*17541Skarels /* kern_synch.c 6.5 84/12/20 */ 233Sbill 39756Ssam #include "../machine/pte.h" 49756Ssam 517093Sbloom #include "param.h" 617093Sbloom #include "systm.h" 717093Sbloom #include "dir.h" 817093Sbloom #include "user.h" 917093Sbloom #include "proc.h" 1017093Sbloom #include "file.h" 1117093Sbloom #include "inode.h" 1217093Sbloom #include "vm.h" 1317093Sbloom #include "kernel.h" 1417093Sbloom #include "buf.h" 159756Ssam 169756Ssam #ifdef vax 178445Sroot #include "../vax/mtpr.h" /* XXX */ 189756Ssam #endif 198102Sroot /* 208102Sroot * Force switch among equal priority processes every 100ms. 218102Sroot */ 228102Sroot roundrobin() 238102Sroot { 248102Sroot 258102Sroot runrun++; 268102Sroot aston(); 278624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 288102Sroot } 298102Sroot 30*17541Skarels /* fraction for digital decay to forget 90% of usage in 5*loadav sec */ 31*17541Skarels #define filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1)) 32*17541Skarels 338102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 348102Sroot 358102Sroot /* 368102Sroot * Recompute process priorities, once a second 378102Sroot */ 388102Sroot schedcpu() 398102Sroot { 4016795Skarels register double ccpu1 = (1.0 - ccpu) / (double)hz; 418102Sroot register struct proc *p; 428102Sroot register int s, a; 43*17541Skarels float scale = filter(avenrun[0]); 448102Sroot 458102Sroot wakeup((caddr_t)&lbolt); 4616532Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 478102Sroot if (p->p_time != 127) 488102Sroot p->p_time++; 498102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 508102Sroot if (p->p_slptime != 127) 518102Sroot p->p_slptime++; 52*17541Skarels /* 53*17541Skarels * If the process has slept the entire second, 54*17541Skarels * stop recalculating its priority until it wakes up. 55*17541Skarels */ 56*17541Skarels if (p->p_slptime > 1) { 57*17541Skarels p->p_pctcpu *= ccpu; 58*17541Skarels continue; 59*17541Skarels } 60*17541Skarels /* 61*17541Skarels * p_pctcpu is only for ps. 62*17541Skarels */ 63*17541Skarels p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks; 648102Sroot p->p_cpticks = 0; 65*17541Skarels a = (int) (scale * (p->p_cpu & 0377)) + p->p_nice; 668102Sroot if (a < 0) 678102Sroot a = 0; 688102Sroot if (a > 255) 698102Sroot a = 255; 708102Sroot p->p_cpu = a; 718102Sroot (void) setpri(p); 72*17541Skarels s = splhigh(); /* prevent state changes */ 738102Sroot if (p->p_pri >= PUSER) { 7416795Skarels #define PPQ (128 / NQS) 758102Sroot if ((p != u.u_procp || noproc) && 768102Sroot p->p_stat == SRUN && 778102Sroot (p->p_flag & SLOAD) && 7816795Skarels (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) { 798102Sroot remrq(p); 808102Sroot p->p_pri = p->p_usrpri; 818102Sroot setrq(p); 828102Sroot } else 838102Sroot p->p_pri = p->p_usrpri; 848102Sroot } 858102Sroot splx(s); 868102Sroot } 878102Sroot vmmeter(); 888102Sroot if (runin!=0) { 898102Sroot runin = 0; 908102Sroot wakeup((caddr_t)&runin); 918102Sroot } 928102Sroot if (bclnlist != NULL) 938102Sroot wakeup((caddr_t)&proc[2]); 948624Sroot timeout(schedcpu, (caddr_t)0, hz); 958102Sroot } 968102Sroot 97*17541Skarels /* 98*17541Skarels * Recalculate the priority of a process after it has slept for a while. 99*17541Skarels */ 100*17541Skarels updatepri(p) 101*17541Skarels register struct proc *p; 102*17541Skarels { 103*17541Skarels register int a = p->p_cpu & 0377; 104*17541Skarels float scale = filter(avenrun[0]); 105*17541Skarels 106*17541Skarels p->p_slptime--; /* the first time was done in schedcpu */ 107*17541Skarels while (a && --p->p_slptime) 108*17541Skarels a = (int) (scale * a) /* + p->p_nice */; 109*17541Skarels if (a < 0) 110*17541Skarels a = 0; 111*17541Skarels if (a > 255) 112*17541Skarels a = 255; 113*17541Skarels p->p_cpu = a; 114*17541Skarels (void) setpri(p); 115*17541Skarels } 116*17541Skarels 11733Sbill #define SQSIZE 0100 /* Must be power of 2 */ 11833Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 11933Sbill struct proc *slpque[SQSIZE]; 12033Sbill 12133Sbill /* 12233Sbill * Give up the processor till a wakeup occurs 12333Sbill * on chan, at which time the process 12433Sbill * enters the scheduling queue at priority pri. 12533Sbill * The most important effect of pri is that when 12633Sbill * pri<=PZERO a signal cannot disturb the sleep; 12733Sbill * if pri>PZERO signals will be processed. 12833Sbill * Callers of this routine must be prepared for 12933Sbill * premature return, and check that the reason for 13033Sbill * sleeping has gone away. 13133Sbill */ 13233Sbill sleep(chan, pri) 1338033Sroot caddr_t chan; 1348033Sroot int pri; 13533Sbill { 136187Sbill register struct proc *rp, **hp; 137207Sbill register s; 13833Sbill 13933Sbill rp = u.u_procp; 140*17541Skarels s = splhigh(); 141*17541Skarels if ((chan==0 || rp->p_stat != SRUN || rp->p_rlink) && 142*17541Skarels panicstr == (char *) NULL) 14333Sbill panic("sleep"); 14433Sbill rp->p_wchan = chan; 14533Sbill rp->p_slptime = 0; 14633Sbill rp->p_pri = pri; 147187Sbill hp = &slpque[HASH(chan)]; 148187Sbill rp->p_link = *hp; 149187Sbill *hp = rp; 1504826Swnj if (pri > PZERO) { 1514826Swnj if (ISSIG(rp)) { 152187Sbill if (rp->p_wchan) 153187Sbill unsleep(rp); 15433Sbill rp->p_stat = SRUN; 155131Sbill (void) spl0(); 15633Sbill goto psig; 15733Sbill } 158187Sbill if (rp->p_wchan == 0) 159187Sbill goto out; 160187Sbill rp->p_stat = SSLEEP; 161131Sbill (void) spl0(); 1628033Sroot u.u_ru.ru_nvcsw++; 16333Sbill swtch(); 1644826Swnj if (ISSIG(rp)) 16533Sbill goto psig; 16633Sbill } else { 167207Sbill rp->p_stat = SSLEEP; 168131Sbill (void) spl0(); 1698033Sroot u.u_ru.ru_nvcsw++; 17033Sbill swtch(); 17133Sbill } 17216795Skarels curpri = rp->p_usrpri; 173187Sbill out: 17433Sbill splx(s); 17533Sbill return; 17633Sbill 17733Sbill /* 17833Sbill * If priority was low (>PZERO) and 1794826Swnj * there has been a signal, execute non-local goto through 1808113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 18133Sbill */ 18233Sbill psig: 1838113Sroot longjmp(&u.u_qsave); 18433Sbill /*NOTREACHED*/ 18533Sbill } 18633Sbill 18733Sbill /* 188181Sbill * Remove a process from its wait queue 189181Sbill */ 190181Sbill unsleep(p) 1914826Swnj register struct proc *p; 192181Sbill { 193181Sbill register struct proc **hp; 194181Sbill register s; 195181Sbill 196*17541Skarels s = splhigh(); 197181Sbill if (p->p_wchan) { 198181Sbill hp = &slpque[HASH(p->p_wchan)]; 199181Sbill while (*hp != p) 200181Sbill hp = &(*hp)->p_link; 201181Sbill *hp = p->p_link; 202181Sbill p->p_wchan = 0; 203181Sbill } 204181Sbill splx(s); 205181Sbill } 206181Sbill 207181Sbill /* 20833Sbill * Wake up all processes sleeping on chan. 20933Sbill */ 21033Sbill wakeup(chan) 2114826Swnj register caddr_t chan; 21233Sbill { 213187Sbill register struct proc *p, **q, **h; 21433Sbill int s; 21533Sbill 216*17541Skarels s = splhigh(); 217187Sbill h = &slpque[HASH(chan)]; 21833Sbill restart: 219187Sbill for (q = h; p = *q; ) { 220181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 22133Sbill panic("wakeup"); 222207Sbill if (p->p_wchan==chan) { 22333Sbill p->p_wchan = 0; 224187Sbill *q = p->p_link; 225*17541Skarels if (p->p_slptime > 1) 226*17541Skarels updatepri(p); 22733Sbill p->p_slptime = 0; 228181Sbill if (p->p_stat == SSLEEP) { 229181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 230181Sbill p->p_stat = SRUN; 2312702Swnj if (p->p_flag & SLOAD) 232181Sbill setrq(p); 23316795Skarels /* 23416795Skarels * Since curpri is a usrpri, 23516795Skarels * p->p_pri is always better than curpri. 23616795Skarels */ 23716795Skarels runrun++; 23816795Skarels aston(); 2393545Swnj if ((p->p_flag&SLOAD) == 0) { 2403545Swnj if (runout != 0) { 2413545Swnj runout = 0; 2423545Swnj wakeup((caddr_t)&runout); 2433545Swnj } 2443545Swnj wantin++; 245181Sbill } 246181Sbill /* END INLINE EXPANSION */ 247187Sbill goto restart; 24833Sbill } 249187Sbill } else 250187Sbill q = &p->p_link; 25133Sbill } 25233Sbill splx(s); 25333Sbill } 25433Sbill 25533Sbill /* 25633Sbill * Initialize the (doubly-linked) run queues 25733Sbill * to be empty. 25833Sbill */ 25933Sbill rqinit() 26033Sbill { 26133Sbill register int i; 26233Sbill 26333Sbill for (i = 0; i < NQS; i++) 26433Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 26533Sbill } 26633Sbill 26733Sbill /* 26833Sbill * Set the process running; 26933Sbill * arrange for it to be swapped in if necessary. 27033Sbill */ 27133Sbill setrun(p) 2724826Swnj register struct proc *p; 27333Sbill { 2744826Swnj register int s; 27533Sbill 276*17541Skarels s = splhigh(); 27733Sbill switch (p->p_stat) { 27833Sbill 27933Sbill case 0: 28033Sbill case SWAIT: 28133Sbill case SRUN: 28233Sbill case SZOMB: 28333Sbill default: 28433Sbill panic("setrun"); 28533Sbill 286207Sbill case SSTOP: 28733Sbill case SSLEEP: 288181Sbill unsleep(p); /* e.g. when sending signals */ 28933Sbill break; 29033Sbill 29133Sbill case SIDL: 29233Sbill break; 29333Sbill } 294*17541Skarels if (p->p_slptime > 1) 295*17541Skarels updatepri(p); 29633Sbill p->p_stat = SRUN; 29733Sbill if (p->p_flag & SLOAD) 29833Sbill setrq(p); 29933Sbill splx(s); 3004826Swnj if (p->p_pri < curpri) { 30133Sbill runrun++; 3022443Swnj aston(); 3032443Swnj } 3043545Swnj if ((p->p_flag&SLOAD) == 0) { 3054826Swnj if (runout != 0) { 3063545Swnj runout = 0; 3073545Swnj wakeup((caddr_t)&runout); 3083545Swnj } 3093545Swnj wantin++; 31033Sbill } 31133Sbill } 31233Sbill 31333Sbill /* 31433Sbill * Set user priority. 31533Sbill * The rescheduling flag (runrun) 31633Sbill * is set if the priority is better 31733Sbill * than the currently running process. 31833Sbill */ 31933Sbill setpri(pp) 3204826Swnj register struct proc *pp; 32133Sbill { 3224826Swnj register int p; 32333Sbill 3243875Swnj p = (pp->p_cpu & 0377)/4; 325*17541Skarels p += PUSER + 2 * pp->p_nice; 3263530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3273530Swnj p += 2*4; /* effectively, nice(4) */ 3284826Swnj if (p > 127) 32933Sbill p = 127; 3304826Swnj if (p < curpri) { 33133Sbill runrun++; 3322453Swnj aston(); 3332453Swnj } 33433Sbill pp->p_usrpri = p; 3354826Swnj return (p); 33633Sbill } 337