123376Smckusick /* 2*29096Smckusick * 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*29096Smckusick * @(#)kern_synch.c 7.1 (Berkeley) 06/05/86 723376Smckusick */ 833Sbill 99756Ssam #include "../machine/pte.h" 109756Ssam 1117093Sbloom #include "param.h" 1217093Sbloom #include "systm.h" 1317093Sbloom #include "dir.h" 1417093Sbloom #include "user.h" 1517093Sbloom #include "proc.h" 1617093Sbloom #include "file.h" 1717093Sbloom #include "inode.h" 1817093Sbloom #include "vm.h" 1917093Sbloom #include "kernel.h" 2017093Sbloom #include "buf.h" 219756Ssam 229756Ssam #ifdef vax 238445Sroot #include "../vax/mtpr.h" /* XXX */ 249756Ssam #endif 258102Sroot /* 268102Sroot * Force switch among equal priority processes every 100ms. 278102Sroot */ 288102Sroot roundrobin() 298102Sroot { 308102Sroot 318102Sroot runrun++; 328102Sroot aston(); 338624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 348102Sroot } 358102Sroot 3617541Skarels /* fraction for digital decay to forget 90% of usage in 5*loadav sec */ 3717541Skarels #define filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1)) 3817541Skarels 398102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 408102Sroot 418102Sroot /* 428102Sroot * Recompute process priorities, once a second 438102Sroot */ 448102Sroot schedcpu() 458102Sroot { 4616795Skarels register double ccpu1 = (1.0 - ccpu) / (double)hz; 478102Sroot register struct proc *p; 488102Sroot register int s, a; 4917541Skarels float scale = filter(avenrun[0]); 508102Sroot 518102Sroot wakeup((caddr_t)&lbolt); 5216532Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 538102Sroot if (p->p_time != 127) 548102Sroot p->p_time++; 558102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 568102Sroot if (p->p_slptime != 127) 578102Sroot p->p_slptime++; 5817541Skarels /* 5917541Skarels * If the process has slept the entire second, 6017541Skarels * stop recalculating its priority until it wakes up. 6117541Skarels */ 6217541Skarels if (p->p_slptime > 1) { 6317541Skarels p->p_pctcpu *= ccpu; 6417541Skarels continue; 6517541Skarels } 6617541Skarels /* 6717541Skarels * p_pctcpu is only for ps. 6817541Skarels */ 6917541Skarels p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks; 708102Sroot p->p_cpticks = 0; 7117541Skarels a = (int) (scale * (p->p_cpu & 0377)) + p->p_nice; 728102Sroot if (a < 0) 738102Sroot a = 0; 748102Sroot if (a > 255) 758102Sroot a = 255; 768102Sroot p->p_cpu = a; 778102Sroot (void) setpri(p); 7817541Skarels s = splhigh(); /* prevent state changes */ 798102Sroot if (p->p_pri >= PUSER) { 8016795Skarels #define PPQ (128 / NQS) 818102Sroot if ((p != u.u_procp || noproc) && 828102Sroot p->p_stat == SRUN && 838102Sroot (p->p_flag & SLOAD) && 8416795Skarels (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) { 858102Sroot remrq(p); 868102Sroot p->p_pri = p->p_usrpri; 878102Sroot setrq(p); 888102Sroot } else 898102Sroot p->p_pri = p->p_usrpri; 908102Sroot } 918102Sroot splx(s); 928102Sroot } 938102Sroot vmmeter(); 948102Sroot if (runin!=0) { 958102Sroot runin = 0; 968102Sroot wakeup((caddr_t)&runin); 978102Sroot } 988102Sroot if (bclnlist != NULL) 998102Sroot wakeup((caddr_t)&proc[2]); 1008624Sroot timeout(schedcpu, (caddr_t)0, hz); 1018102Sroot } 1028102Sroot 10317541Skarels /* 10417541Skarels * Recalculate the priority of a process after it has slept for a while. 10517541Skarels */ 10617541Skarels updatepri(p) 10717541Skarels register struct proc *p; 10817541Skarels { 10917541Skarels register int a = p->p_cpu & 0377; 11017541Skarels float scale = filter(avenrun[0]); 11117541Skarels 11217541Skarels p->p_slptime--; /* the first time was done in schedcpu */ 11317541Skarels while (a && --p->p_slptime) 11417541Skarels a = (int) (scale * a) /* + p->p_nice */; 11517541Skarels if (a < 0) 11617541Skarels a = 0; 11717541Skarels if (a > 255) 11817541Skarels a = 255; 11917541Skarels p->p_cpu = a; 12017541Skarels (void) setpri(p); 12117541Skarels } 12217541Skarels 12333Sbill #define SQSIZE 0100 /* Must be power of 2 */ 12433Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 12521099Smckusick struct slpque { 12621099Smckusick struct proc *sq_head; 12721099Smckusick struct proc **sq_tailp; 12821099Smckusick } slpque[SQSIZE]; 12933Sbill 13033Sbill /* 13133Sbill * Give up the processor till a wakeup occurs 13233Sbill * on chan, at which time the process 13333Sbill * enters the scheduling queue at priority pri. 13433Sbill * The most important effect of pri is that when 13533Sbill * pri<=PZERO a signal cannot disturb the sleep; 13633Sbill * if pri>PZERO signals will be processed. 13733Sbill * Callers of this routine must be prepared for 13833Sbill * premature return, and check that the reason for 13933Sbill * sleeping has gone away. 14033Sbill */ 14133Sbill sleep(chan, pri) 1428033Sroot caddr_t chan; 1438033Sroot int pri; 14433Sbill { 14521099Smckusick register struct proc *rp; 14621099Smckusick register struct slpque *qp; 147207Sbill register s; 14833Sbill 14933Sbill rp = u.u_procp; 15017541Skarels s = splhigh(); 15118363Skarels if (panicstr) { 15218363Skarels /* 15318363Skarels * After a panic, just give interrupts a chance, 15418363Skarels * then just return; don't run any other procs 15518363Skarels * or panic below, in case this is the idle process 15618363Skarels * and already asleep. 15718363Skarels * The splnet should be spl0 if the network was being used 15818363Skarels * by the filesystem, but for now avoid network interrupts 15918363Skarels * that might cause another panic. 16018363Skarels */ 16118363Skarels (void) splnet(); 16218363Skarels splx(s); 16318363Skarels return; 16418363Skarels } 16518363Skarels if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 16633Sbill panic("sleep"); 16733Sbill rp->p_wchan = chan; 16833Sbill rp->p_slptime = 0; 16933Sbill rp->p_pri = pri; 17021099Smckusick qp = &slpque[HASH(chan)]; 17121099Smckusick if (qp->sq_head == 0) 17221099Smckusick qp->sq_head = rp; 17321099Smckusick else 17421099Smckusick *qp->sq_tailp = rp; 17521099Smckusick *(qp->sq_tailp = &rp->p_link) = 0; 1764826Swnj if (pri > PZERO) { 17721763Skarels /* 17821763Skarels * If we stop in issig(), wakeup may already have happened 17921763Skarels * when we return (rp->p_wchan will then be 0). 18021763Skarels */ 1814826Swnj if (ISSIG(rp)) { 182187Sbill if (rp->p_wchan) 183187Sbill unsleep(rp); 18433Sbill rp->p_stat = SRUN; 185131Sbill (void) spl0(); 18633Sbill goto psig; 18733Sbill } 188187Sbill if (rp->p_wchan == 0) 189187Sbill goto out; 190187Sbill rp->p_stat = SSLEEP; 191131Sbill (void) spl0(); 1928033Sroot u.u_ru.ru_nvcsw++; 19333Sbill swtch(); 1944826Swnj if (ISSIG(rp)) 19533Sbill goto psig; 19633Sbill } else { 197207Sbill rp->p_stat = SSLEEP; 198131Sbill (void) spl0(); 1998033Sroot u.u_ru.ru_nvcsw++; 20033Sbill swtch(); 20133Sbill } 20216795Skarels curpri = rp->p_usrpri; 203187Sbill out: 20433Sbill splx(s); 20533Sbill return; 20633Sbill 20733Sbill /* 20833Sbill * If priority was low (>PZERO) and 2094826Swnj * there has been a signal, execute non-local goto through 2108113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 21133Sbill */ 21233Sbill psig: 2138113Sroot longjmp(&u.u_qsave); 21433Sbill /*NOTREACHED*/ 21533Sbill } 21633Sbill 21733Sbill /* 218181Sbill * Remove a process from its wait queue 219181Sbill */ 220181Sbill unsleep(p) 2214826Swnj register struct proc *p; 222181Sbill { 22321099Smckusick register struct slpque *qp; 224181Sbill register struct proc **hp; 22521099Smckusick int s; 226181Sbill 22717541Skarels s = splhigh(); 228181Sbill if (p->p_wchan) { 22921099Smckusick hp = &(qp = &slpque[HASH(p->p_wchan)])->sq_head; 230181Sbill while (*hp != p) 231181Sbill hp = &(*hp)->p_link; 232181Sbill *hp = p->p_link; 23321099Smckusick if (qp->sq_tailp == &p->p_link) 23421099Smckusick qp->sq_tailp = hp; 235181Sbill p->p_wchan = 0; 236181Sbill } 237181Sbill splx(s); 238181Sbill } 239181Sbill 240181Sbill /* 24133Sbill * Wake up all processes sleeping on chan. 24233Sbill */ 24333Sbill wakeup(chan) 2444826Swnj register caddr_t chan; 24533Sbill { 24621099Smckusick register struct slpque *qp; 24721099Smckusick register struct proc *p, **q; 24833Sbill int s; 24933Sbill 25017541Skarels s = splhigh(); 25121099Smckusick qp = &slpque[HASH(chan)]; 25233Sbill restart: 25321099Smckusick for (q = &qp->sq_head; p = *q; ) { 254181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 25533Sbill panic("wakeup"); 256207Sbill if (p->p_wchan==chan) { 25733Sbill p->p_wchan = 0; 258187Sbill *q = p->p_link; 25921099Smckusick if (qp->sq_tailp == &p->p_link) 26021099Smckusick qp->sq_tailp = q; 261181Sbill if (p->p_stat == SSLEEP) { 262181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 26321763Skarels if (p->p_slptime > 1) 26421763Skarels updatepri(p); 26522722Skarels p->p_slptime = 0; 266181Sbill p->p_stat = SRUN; 2672702Swnj if (p->p_flag & SLOAD) 268181Sbill setrq(p); 26916795Skarels /* 27016795Skarels * Since curpri is a usrpri, 27116795Skarels * p->p_pri is always better than curpri. 27216795Skarels */ 27316795Skarels runrun++; 27416795Skarels aston(); 2753545Swnj if ((p->p_flag&SLOAD) == 0) { 2763545Swnj if (runout != 0) { 2773545Swnj runout = 0; 2783545Swnj wakeup((caddr_t)&runout); 2793545Swnj } 2803545Swnj wantin++; 281181Sbill } 282181Sbill /* END INLINE EXPANSION */ 283187Sbill goto restart; 28433Sbill } 28522722Skarels p->p_slptime = 0; 286187Sbill } else 287187Sbill q = &p->p_link; 28833Sbill } 28933Sbill splx(s); 29033Sbill } 29133Sbill 29233Sbill /* 29333Sbill * Initialize the (doubly-linked) run queues 29433Sbill * to be empty. 29533Sbill */ 29633Sbill rqinit() 29733Sbill { 29833Sbill register int i; 29933Sbill 30033Sbill for (i = 0; i < NQS; i++) 30133Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 30233Sbill } 30333Sbill 30433Sbill /* 30533Sbill * Set the process running; 30633Sbill * arrange for it to be swapped in if necessary. 30733Sbill */ 30833Sbill setrun(p) 3094826Swnj register struct proc *p; 31033Sbill { 3114826Swnj register int s; 31233Sbill 31317541Skarels s = splhigh(); 31433Sbill switch (p->p_stat) { 31533Sbill 31633Sbill case 0: 31733Sbill case SWAIT: 31833Sbill case SRUN: 31933Sbill case SZOMB: 32033Sbill default: 32133Sbill panic("setrun"); 32233Sbill 323207Sbill case SSTOP: 32433Sbill case SSLEEP: 325181Sbill unsleep(p); /* e.g. when sending signals */ 32633Sbill break; 32733Sbill 32833Sbill case SIDL: 32933Sbill break; 33033Sbill } 33117541Skarels if (p->p_slptime > 1) 33217541Skarels updatepri(p); 33333Sbill p->p_stat = SRUN; 33433Sbill if (p->p_flag & SLOAD) 33533Sbill setrq(p); 33633Sbill splx(s); 3374826Swnj if (p->p_pri < curpri) { 33833Sbill runrun++; 3392443Swnj aston(); 3402443Swnj } 3413545Swnj if ((p->p_flag&SLOAD) == 0) { 3424826Swnj if (runout != 0) { 3433545Swnj runout = 0; 3443545Swnj wakeup((caddr_t)&runout); 3453545Swnj } 3463545Swnj wantin++; 34733Sbill } 34833Sbill } 34933Sbill 35033Sbill /* 35133Sbill * Set user priority. 35233Sbill * The rescheduling flag (runrun) 35333Sbill * is set if the priority is better 35433Sbill * than the currently running process. 35533Sbill */ 35633Sbill setpri(pp) 3574826Swnj register struct proc *pp; 35833Sbill { 3594826Swnj register int p; 36033Sbill 3613875Swnj p = (pp->p_cpu & 0377)/4; 36217541Skarels p += PUSER + 2 * pp->p_nice; 3633530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3643530Swnj p += 2*4; /* effectively, nice(4) */ 3654826Swnj if (p > 127) 36633Sbill p = 127; 3674826Swnj if (p < curpri) { 36833Sbill runrun++; 3692453Swnj aston(); 3702453Swnj } 37133Sbill pp->p_usrpri = p; 3724826Swnj return (p); 37333Sbill } 374