1*16532Skarels /* kern_synch.c 6.2 84/05/22 */ 233Sbill 39756Ssam #include "../machine/pte.h" 49756Ssam 533Sbill #include "../h/param.h" 633Sbill #include "../h/systm.h" 733Sbill #include "../h/dir.h" 833Sbill #include "../h/user.h" 933Sbill #include "../h/proc.h" 1033Sbill #include "../h/file.h" 1133Sbill #include "../h/inode.h" 1233Sbill #include "../h/vm.h" 138102Sroot #include "../h/kernel.h" 148102Sroot #include "../h/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 308113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */ 318102Sroot #undef ave 328102Sroot #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 338102Sroot int nrscale = 2; 348102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 358102Sroot 368102Sroot /* 378102Sroot * Recompute process priorities, once a second 388102Sroot */ 398102Sroot schedcpu() 408102Sroot { 418102Sroot register struct proc *p; 428102Sroot register int s, a; 438102Sroot 448102Sroot wakeup((caddr_t)&lbolt); 45*16532Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 468102Sroot if (p->p_time != 127) 478102Sroot p->p_time++; 488102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 498102Sroot if (p->p_slptime != 127) 508102Sroot p->p_slptime++; 518102Sroot if (p->p_flag&SLOAD) 528102Sroot p->p_pctcpu = ccpu * p->p_pctcpu + 538102Sroot (1.0 - ccpu) * (p->p_cpticks/(float)hz); 548102Sroot p->p_cpticks = 0; 558102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 568102Sroot p->p_nice - NZERO; 578102Sroot if (a < 0) 588102Sroot a = 0; 598102Sroot if (a > 255) 608102Sroot a = 255; 618102Sroot p->p_cpu = a; 628102Sroot (void) setpri(p); 638102Sroot s = spl6(); /* prevent state changes */ 648102Sroot if (p->p_pri >= PUSER) { 658102Sroot if ((p != u.u_procp || noproc) && 668102Sroot p->p_stat == SRUN && 678102Sroot (p->p_flag & SLOAD) && 688102Sroot p->p_pri != p->p_usrpri) { 698102Sroot remrq(p); 708102Sroot p->p_pri = p->p_usrpri; 718102Sroot setrq(p); 728102Sroot } else 738102Sroot p->p_pri = p->p_usrpri; 748102Sroot } 758102Sroot splx(s); 768102Sroot } 778102Sroot vmmeter(); 788102Sroot if (runin!=0) { 798102Sroot runin = 0; 808102Sroot wakeup((caddr_t)&runin); 818102Sroot } 828102Sroot if (bclnlist != NULL) 838102Sroot wakeup((caddr_t)&proc[2]); 848624Sroot timeout(schedcpu, (caddr_t)0, hz); 858102Sroot } 868102Sroot 8733Sbill #define SQSIZE 0100 /* Must be power of 2 */ 8833Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 8933Sbill struct proc *slpque[SQSIZE]; 9033Sbill 9133Sbill /* 9233Sbill * Give up the processor till a wakeup occurs 9333Sbill * on chan, at which time the process 9433Sbill * enters the scheduling queue at priority pri. 9533Sbill * The most important effect of pri is that when 9633Sbill * pri<=PZERO a signal cannot disturb the sleep; 9733Sbill * if pri>PZERO signals will be processed. 9833Sbill * Callers of this routine must be prepared for 9933Sbill * premature return, and check that the reason for 10033Sbill * sleeping has gone away. 10133Sbill */ 10233Sbill sleep(chan, pri) 1038033Sroot caddr_t chan; 1048033Sroot int pri; 10533Sbill { 106187Sbill register struct proc *rp, **hp; 107207Sbill register s; 10833Sbill 10933Sbill rp = u.u_procp; 11033Sbill s = spl6(); 11133Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 11233Sbill panic("sleep"); 11333Sbill rp->p_wchan = chan; 11433Sbill rp->p_slptime = 0; 11533Sbill rp->p_pri = pri; 116187Sbill hp = &slpque[HASH(chan)]; 117187Sbill rp->p_link = *hp; 118187Sbill *hp = rp; 1194826Swnj if (pri > PZERO) { 1204826Swnj if (ISSIG(rp)) { 121187Sbill if (rp->p_wchan) 122187Sbill unsleep(rp); 12333Sbill rp->p_stat = SRUN; 124131Sbill (void) spl0(); 12533Sbill goto psig; 12633Sbill } 127187Sbill if (rp->p_wchan == 0) 128187Sbill goto out; 129187Sbill rp->p_stat = SSLEEP; 130131Sbill (void) spl0(); 1318033Sroot u.u_ru.ru_nvcsw++; 13233Sbill swtch(); 1334826Swnj if (ISSIG(rp)) 13433Sbill goto psig; 13533Sbill } else { 136207Sbill rp->p_stat = SSLEEP; 137131Sbill (void) spl0(); 1388033Sroot u.u_ru.ru_nvcsw++; 13933Sbill swtch(); 14033Sbill } 141187Sbill out: 14233Sbill splx(s); 14333Sbill return; 14433Sbill 14533Sbill /* 14633Sbill * If priority was low (>PZERO) and 1474826Swnj * there has been a signal, execute non-local goto through 1488113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 1494826Swnj * (or finishing a tsleep, see below) 15033Sbill */ 15133Sbill psig: 1528113Sroot longjmp(&u.u_qsave); 15333Sbill /*NOTREACHED*/ 15433Sbill } 15533Sbill 15633Sbill /* 157181Sbill * Remove a process from its wait queue 158181Sbill */ 159181Sbill unsleep(p) 1604826Swnj register struct proc *p; 161181Sbill { 162181Sbill register struct proc **hp; 163181Sbill register s; 164181Sbill 165181Sbill s = spl6(); 166181Sbill if (p->p_wchan) { 167181Sbill hp = &slpque[HASH(p->p_wchan)]; 168181Sbill while (*hp != p) 169181Sbill hp = &(*hp)->p_link; 170181Sbill *hp = p->p_link; 171181Sbill p->p_wchan = 0; 172181Sbill } 173181Sbill splx(s); 174181Sbill } 175181Sbill 176181Sbill /* 17733Sbill * Wake up all processes sleeping on chan. 17833Sbill */ 17933Sbill wakeup(chan) 1804826Swnj register caddr_t chan; 18133Sbill { 182187Sbill register struct proc *p, **q, **h; 18333Sbill int s; 18433Sbill 18533Sbill s = spl6(); 186187Sbill h = &slpque[HASH(chan)]; 18733Sbill restart: 188187Sbill for (q = h; p = *q; ) { 189181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 19033Sbill panic("wakeup"); 191207Sbill if (p->p_wchan==chan) { 19233Sbill p->p_wchan = 0; 193187Sbill *q = p->p_link; 19433Sbill p->p_slptime = 0; 195181Sbill if (p->p_stat == SSLEEP) { 196181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 197181Sbill p->p_stat = SRUN; 1982702Swnj if (p->p_flag & SLOAD) 199181Sbill setrq(p); 2004826Swnj if (p->p_pri < curpri) { 201181Sbill runrun++; 2022443Swnj aston(); 2032443Swnj } 2043545Swnj if ((p->p_flag&SLOAD) == 0) { 2053545Swnj if (runout != 0) { 2063545Swnj runout = 0; 2073545Swnj wakeup((caddr_t)&runout); 2083545Swnj } 2093545Swnj wantin++; 210181Sbill } 211181Sbill /* END INLINE EXPANSION */ 212187Sbill goto restart; 21333Sbill } 214187Sbill } else 215187Sbill q = &p->p_link; 21633Sbill } 21733Sbill splx(s); 21833Sbill } 21933Sbill 22033Sbill /* 22133Sbill * Initialize the (doubly-linked) run queues 22233Sbill * to be empty. 22333Sbill */ 22433Sbill rqinit() 22533Sbill { 22633Sbill register int i; 22733Sbill 22833Sbill for (i = 0; i < NQS; i++) 22933Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 23033Sbill } 23133Sbill 23233Sbill /* 23333Sbill * Set the process running; 23433Sbill * arrange for it to be swapped in if necessary. 23533Sbill */ 23633Sbill setrun(p) 2374826Swnj register struct proc *p; 23833Sbill { 2394826Swnj register int s; 24033Sbill 24133Sbill s = spl6(); 24233Sbill switch (p->p_stat) { 24333Sbill 24433Sbill case 0: 24533Sbill case SWAIT: 24633Sbill case SRUN: 24733Sbill case SZOMB: 24833Sbill default: 24933Sbill panic("setrun"); 25033Sbill 251207Sbill case SSTOP: 25233Sbill case SSLEEP: 253181Sbill unsleep(p); /* e.g. when sending signals */ 25433Sbill break; 25533Sbill 25633Sbill case SIDL: 25733Sbill break; 25833Sbill } 25933Sbill p->p_stat = SRUN; 26033Sbill if (p->p_flag & SLOAD) 26133Sbill setrq(p); 26233Sbill splx(s); 2634826Swnj if (p->p_pri < curpri) { 26433Sbill runrun++; 2652443Swnj aston(); 2662443Swnj } 2673545Swnj if ((p->p_flag&SLOAD) == 0) { 2684826Swnj if (runout != 0) { 2693545Swnj runout = 0; 2703545Swnj wakeup((caddr_t)&runout); 2713545Swnj } 2723545Swnj wantin++; 27333Sbill } 27433Sbill } 27533Sbill 27633Sbill /* 27733Sbill * Set user priority. 27833Sbill * The rescheduling flag (runrun) 27933Sbill * is set if the priority is better 28033Sbill * than the currently running process. 28133Sbill */ 28233Sbill setpri(pp) 2834826Swnj register struct proc *pp; 28433Sbill { 2854826Swnj register int p; 28633Sbill 2873875Swnj p = (pp->p_cpu & 0377)/4; 2881543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 2893530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 2903530Swnj p += 2*4; /* effectively, nice(4) */ 2914826Swnj if (p > 127) 29233Sbill p = 127; 2934826Swnj if (p < curpri) { 29433Sbill runrun++; 2952453Swnj aston(); 2962453Swnj } 29733Sbill pp->p_usrpri = p; 2984826Swnj return (p); 29933Sbill } 300