123376Smckusick /* 229096Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323376Smckusick * All rights reserved. The Berkeley software License Agreement 423376Smckusick * specifies the terms and conditions for redistribution. 523376Smckusick * 6*29946Skarels * @(#)kern_synch.c 7.2 (Berkeley) 11/03/86 723376Smckusick */ 833Sbill 99756Ssam #include "../machine/pte.h" 10*29946Skarels #include "../machine/psl.h" 11*29946Skarels #include "../machine/mtpr.h" 129756Ssam 1317093Sbloom #include "param.h" 1417093Sbloom #include "systm.h" 1517093Sbloom #include "dir.h" 1617093Sbloom #include "user.h" 1717093Sbloom #include "proc.h" 1817093Sbloom #include "file.h" 1917093Sbloom #include "inode.h" 2017093Sbloom #include "vm.h" 2117093Sbloom #include "kernel.h" 2217093Sbloom #include "buf.h" 239756Ssam 248102Sroot /* 258102Sroot * Force switch among equal priority processes every 100ms. 268102Sroot */ 278102Sroot roundrobin() 288102Sroot { 298102Sroot 308102Sroot runrun++; 318102Sroot aston(); 328624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 338102Sroot } 348102Sroot 3517541Skarels /* fraction for digital decay to forget 90% of usage in 5*loadav sec */ 3617541Skarels #define filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1)) 3717541Skarels 388102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 398102Sroot 408102Sroot /* 418102Sroot * Recompute process priorities, once a second 428102Sroot */ 438102Sroot schedcpu() 448102Sroot { 4516795Skarels register double ccpu1 = (1.0 - ccpu) / (double)hz; 468102Sroot register struct proc *p; 478102Sroot register int s, a; 4817541Skarels float scale = filter(avenrun[0]); 498102Sroot 508102Sroot wakeup((caddr_t)&lbolt); 5116532Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 528102Sroot if (p->p_time != 127) 538102Sroot p->p_time++; 548102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 558102Sroot if (p->p_slptime != 127) 568102Sroot p->p_slptime++; 5717541Skarels /* 5817541Skarels * If the process has slept the entire second, 5917541Skarels * stop recalculating its priority until it wakes up. 6017541Skarels */ 6117541Skarels if (p->p_slptime > 1) { 6217541Skarels p->p_pctcpu *= ccpu; 6317541Skarels continue; 6417541Skarels } 6517541Skarels /* 6617541Skarels * p_pctcpu is only for ps. 6717541Skarels */ 6817541Skarels p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks; 698102Sroot p->p_cpticks = 0; 7017541Skarels a = (int) (scale * (p->p_cpu & 0377)) + p->p_nice; 718102Sroot if (a < 0) 728102Sroot a = 0; 738102Sroot if (a > 255) 748102Sroot a = 255; 758102Sroot p->p_cpu = a; 768102Sroot (void) setpri(p); 7717541Skarels s = splhigh(); /* prevent state changes */ 788102Sroot if (p->p_pri >= PUSER) { 7916795Skarels #define PPQ (128 / NQS) 808102Sroot if ((p != u.u_procp || noproc) && 818102Sroot p->p_stat == SRUN && 828102Sroot (p->p_flag & SLOAD) && 8316795Skarels (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) { 848102Sroot remrq(p); 858102Sroot p->p_pri = p->p_usrpri; 868102Sroot setrq(p); 878102Sroot } else 888102Sroot p->p_pri = p->p_usrpri; 898102Sroot } 908102Sroot splx(s); 918102Sroot } 928102Sroot vmmeter(); 938102Sroot if (runin!=0) { 948102Sroot runin = 0; 958102Sroot wakeup((caddr_t)&runin); 968102Sroot } 978102Sroot if (bclnlist != NULL) 988102Sroot wakeup((caddr_t)&proc[2]); 998624Sroot timeout(schedcpu, (caddr_t)0, hz); 1008102Sroot } 1018102Sroot 10217541Skarels /* 10317541Skarels * Recalculate the priority of a process after it has slept for a while. 10417541Skarels */ 10517541Skarels updatepri(p) 10617541Skarels register struct proc *p; 10717541Skarels { 10817541Skarels register int a = p->p_cpu & 0377; 10917541Skarels float scale = filter(avenrun[0]); 11017541Skarels 11117541Skarels p->p_slptime--; /* the first time was done in schedcpu */ 11217541Skarels while (a && --p->p_slptime) 11317541Skarels a = (int) (scale * a) /* + p->p_nice */; 11417541Skarels if (a < 0) 11517541Skarels a = 0; 11617541Skarels if (a > 255) 11717541Skarels a = 255; 11817541Skarels p->p_cpu = a; 11917541Skarels (void) setpri(p); 12017541Skarels } 12117541Skarels 12233Sbill #define SQSIZE 0100 /* Must be power of 2 */ 12333Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 12421099Smckusick struct slpque { 12521099Smckusick struct proc *sq_head; 12621099Smckusick struct proc **sq_tailp; 12721099Smckusick } slpque[SQSIZE]; 12833Sbill 12933Sbill /* 13033Sbill * Give up the processor till a wakeup occurs 13133Sbill * on chan, at which time the process 13233Sbill * enters the scheduling queue at priority pri. 13333Sbill * The most important effect of pri is that when 13433Sbill * pri<=PZERO a signal cannot disturb the sleep; 13533Sbill * if pri>PZERO signals will be processed. 13633Sbill * Callers of this routine must be prepared for 13733Sbill * premature return, and check that the reason for 13833Sbill * sleeping has gone away. 13933Sbill */ 14033Sbill sleep(chan, pri) 1418033Sroot caddr_t chan; 1428033Sroot int pri; 14333Sbill { 14421099Smckusick register struct proc *rp; 14521099Smckusick register struct slpque *qp; 146207Sbill register s; 14733Sbill 14833Sbill rp = u.u_procp; 14917541Skarels s = splhigh(); 15018363Skarels if (panicstr) { 15118363Skarels /* 15218363Skarels * After a panic, just give interrupts a chance, 15318363Skarels * then just return; don't run any other procs 15418363Skarels * or panic below, in case this is the idle process 15518363Skarels * and already asleep. 15618363Skarels * The splnet should be spl0 if the network was being used 15718363Skarels * by the filesystem, but for now avoid network interrupts 15818363Skarels * that might cause another panic. 15918363Skarels */ 16018363Skarels (void) splnet(); 16118363Skarels splx(s); 16218363Skarels return; 16318363Skarels } 16418363Skarels if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 16533Sbill panic("sleep"); 16633Sbill rp->p_wchan = chan; 16733Sbill rp->p_slptime = 0; 16833Sbill rp->p_pri = pri; 16921099Smckusick qp = &slpque[HASH(chan)]; 17021099Smckusick if (qp->sq_head == 0) 17121099Smckusick qp->sq_head = rp; 17221099Smckusick else 17321099Smckusick *qp->sq_tailp = rp; 17421099Smckusick *(qp->sq_tailp = &rp->p_link) = 0; 1754826Swnj if (pri > PZERO) { 17621763Skarels /* 17721763Skarels * If we stop in issig(), wakeup may already have happened 17821763Skarels * when we return (rp->p_wchan will then be 0). 17921763Skarels */ 1804826Swnj if (ISSIG(rp)) { 181187Sbill if (rp->p_wchan) 182187Sbill unsleep(rp); 18333Sbill rp->p_stat = SRUN; 184131Sbill (void) spl0(); 18533Sbill goto psig; 18633Sbill } 187187Sbill if (rp->p_wchan == 0) 188187Sbill goto out; 189187Sbill rp->p_stat = SSLEEP; 190131Sbill (void) spl0(); 1918033Sroot u.u_ru.ru_nvcsw++; 19233Sbill swtch(); 1934826Swnj if (ISSIG(rp)) 19433Sbill goto psig; 19533Sbill } else { 196207Sbill rp->p_stat = SSLEEP; 197131Sbill (void) spl0(); 1988033Sroot u.u_ru.ru_nvcsw++; 19933Sbill swtch(); 20033Sbill } 20116795Skarels curpri = rp->p_usrpri; 202187Sbill out: 20333Sbill splx(s); 20433Sbill return; 20533Sbill 20633Sbill /* 20733Sbill * If priority was low (>PZERO) and 2084826Swnj * there has been a signal, execute non-local goto through 2098113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 21033Sbill */ 21133Sbill psig: 2128113Sroot longjmp(&u.u_qsave); 21333Sbill /*NOTREACHED*/ 21433Sbill } 21533Sbill 21633Sbill /* 217181Sbill * Remove a process from its wait queue 218181Sbill */ 219181Sbill unsleep(p) 2204826Swnj register struct proc *p; 221181Sbill { 22221099Smckusick register struct slpque *qp; 223181Sbill register struct proc **hp; 22421099Smckusick int s; 225181Sbill 22617541Skarels s = splhigh(); 227181Sbill if (p->p_wchan) { 22821099Smckusick hp = &(qp = &slpque[HASH(p->p_wchan)])->sq_head; 229181Sbill while (*hp != p) 230181Sbill hp = &(*hp)->p_link; 231181Sbill *hp = p->p_link; 23221099Smckusick if (qp->sq_tailp == &p->p_link) 23321099Smckusick qp->sq_tailp = hp; 234181Sbill p->p_wchan = 0; 235181Sbill } 236181Sbill splx(s); 237181Sbill } 238181Sbill 239181Sbill /* 24033Sbill * Wake up all processes sleeping on chan. 24133Sbill */ 24233Sbill wakeup(chan) 2434826Swnj register caddr_t chan; 24433Sbill { 24521099Smckusick register struct slpque *qp; 24621099Smckusick register struct proc *p, **q; 24733Sbill int s; 24833Sbill 24917541Skarels s = splhigh(); 25021099Smckusick qp = &slpque[HASH(chan)]; 25133Sbill restart: 25221099Smckusick for (q = &qp->sq_head; p = *q; ) { 253181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 25433Sbill panic("wakeup"); 255207Sbill if (p->p_wchan==chan) { 25633Sbill p->p_wchan = 0; 257187Sbill *q = p->p_link; 25821099Smckusick if (qp->sq_tailp == &p->p_link) 25921099Smckusick qp->sq_tailp = q; 260181Sbill if (p->p_stat == SSLEEP) { 261181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 26221763Skarels if (p->p_slptime > 1) 26321763Skarels updatepri(p); 26422722Skarels p->p_slptime = 0; 265181Sbill p->p_stat = SRUN; 2662702Swnj if (p->p_flag & SLOAD) 267181Sbill setrq(p); 26816795Skarels /* 26916795Skarels * Since curpri is a usrpri, 27016795Skarels * p->p_pri is always better than curpri. 27116795Skarels */ 27216795Skarels runrun++; 27316795Skarels aston(); 2743545Swnj if ((p->p_flag&SLOAD) == 0) { 2753545Swnj if (runout != 0) { 2763545Swnj runout = 0; 2773545Swnj wakeup((caddr_t)&runout); 2783545Swnj } 2793545Swnj wantin++; 280181Sbill } 281181Sbill /* END INLINE EXPANSION */ 282187Sbill goto restart; 28333Sbill } 28422722Skarels p->p_slptime = 0; 285187Sbill } else 286187Sbill q = &p->p_link; 28733Sbill } 28833Sbill splx(s); 28933Sbill } 29033Sbill 29133Sbill /* 29233Sbill * Initialize the (doubly-linked) run queues 29333Sbill * to be empty. 29433Sbill */ 29533Sbill rqinit() 29633Sbill { 29733Sbill register int i; 29833Sbill 29933Sbill for (i = 0; i < NQS; i++) 30033Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 30133Sbill } 30233Sbill 30333Sbill /* 30433Sbill * Set the process running; 30533Sbill * arrange for it to be swapped in if necessary. 30633Sbill */ 30733Sbill setrun(p) 3084826Swnj register struct proc *p; 30933Sbill { 3104826Swnj register int s; 31133Sbill 31217541Skarels s = splhigh(); 31333Sbill switch (p->p_stat) { 31433Sbill 31533Sbill case 0: 31633Sbill case SWAIT: 31733Sbill case SRUN: 31833Sbill case SZOMB: 31933Sbill default: 32033Sbill panic("setrun"); 32133Sbill 322207Sbill case SSTOP: 32333Sbill case SSLEEP: 324181Sbill unsleep(p); /* e.g. when sending signals */ 32533Sbill break; 32633Sbill 32733Sbill case SIDL: 32833Sbill break; 32933Sbill } 33017541Skarels if (p->p_slptime > 1) 33117541Skarels updatepri(p); 33233Sbill p->p_stat = SRUN; 33333Sbill if (p->p_flag & SLOAD) 33433Sbill setrq(p); 33533Sbill splx(s); 3364826Swnj if (p->p_pri < curpri) { 33733Sbill runrun++; 3382443Swnj aston(); 3392443Swnj } 3403545Swnj if ((p->p_flag&SLOAD) == 0) { 3414826Swnj if (runout != 0) { 3423545Swnj runout = 0; 3433545Swnj wakeup((caddr_t)&runout); 3443545Swnj } 3453545Swnj wantin++; 34633Sbill } 34733Sbill } 34833Sbill 34933Sbill /* 35033Sbill * Set user priority. 35133Sbill * The rescheduling flag (runrun) 35233Sbill * is set if the priority is better 35333Sbill * than the currently running process. 35433Sbill */ 35533Sbill setpri(pp) 3564826Swnj register struct proc *pp; 35733Sbill { 3584826Swnj register int p; 35933Sbill 3603875Swnj p = (pp->p_cpu & 0377)/4; 36117541Skarels p += PUSER + 2 * pp->p_nice; 3623530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3633530Swnj p += 2*4; /* effectively, nice(4) */ 3644826Swnj if (p > 127) 36533Sbill p = 127; 3664826Swnj if (p < curpri) { 36733Sbill runrun++; 3682453Swnj aston(); 3692453Swnj } 37033Sbill pp->p_usrpri = p; 3714826Swnj return (p); 37233Sbill } 373