1 /* kern_synch.c 4.22 82/10/10 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/proc.h" 8 #include "../h/file.h" 9 #include "../h/inode.h" 10 #include "../h/vm.h" 11 #include "../h/pte.h" 12 #ifdef MUSH 13 #include "../h/quota.h" 14 #include "../h/share.h" 15 #endif 16 #include "../h/kernel.h" 17 #include "../h/buf.h" 18 #include "../vax/mtpr.h" /* XXX */ 19 20 /* 21 * Force switch among equal priority processes every 100ms. 22 */ 23 roundrobin() 24 { 25 26 runrun++; 27 aston(); 28 timeout(roundrobin, 0, hz / 10); 29 } 30 31 /* constants to digital decay and forget 90% of usage in 5*loadav time */ 32 #undef ave 33 #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 34 int nrscale = 2; 35 double avenrun[]; 36 double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 37 38 /* 39 * Recompute process priorities, once a second 40 */ 41 schedcpu() 42 { 43 register struct proc *p; 44 register int s, a; 45 46 wakeup((caddr_t)&lbolt); 47 for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) { 48 #ifdef MUSH 49 if (p->p_quota->q_uid) 50 p->p_quota->q_cost += 51 shconsts.sc_click * p->p_rssize; 52 #endif 53 if (p->p_time != 127) 54 p->p_time++; 55 if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 56 if (p->p_slptime != 127) 57 p->p_slptime++; 58 if (p->p_flag&SLOAD) 59 p->p_pctcpu = ccpu * p->p_pctcpu + 60 (1.0 - ccpu) * (p->p_cpticks/(float)hz); 61 p->p_cpticks = 0; 62 #ifdef MUSH 63 a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 64 p->p_nice - NZERO + p->p_quota->q_nice; 65 #else 66 a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 67 p->p_nice - NZERO; 68 #endif 69 if (a < 0) 70 a = 0; 71 if (a > 255) 72 a = 255; 73 p->p_cpu = a; 74 (void) setpri(p); 75 s = spl6(); /* prevent state changes */ 76 if (p->p_pri >= PUSER) { 77 if ((p != u.u_procp || noproc) && 78 p->p_stat == SRUN && 79 (p->p_flag & SLOAD) && 80 p->p_pri != p->p_usrpri) { 81 remrq(p); 82 p->p_pri = p->p_usrpri; 83 setrq(p); 84 } else 85 p->p_pri = p->p_usrpri; 86 } 87 splx(s); 88 } 89 vmmeter(); 90 if (runin!=0) { 91 runin = 0; 92 wakeup((caddr_t)&runin); 93 } 94 if (bclnlist != NULL) 95 wakeup((caddr_t)&proc[2]); 96 timeout(schedcpu, 0, hz); 97 } 98 99 #define SQSIZE 0100 /* Must be power of 2 */ 100 #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 101 struct proc *slpque[SQSIZE]; 102 103 /* 104 * Give up the processor till a wakeup occurs 105 * on chan, at which time the process 106 * enters the scheduling queue at priority pri. 107 * The most important effect of pri is that when 108 * pri<=PZERO a signal cannot disturb the sleep; 109 * if pri>PZERO signals will be processed. 110 * Callers of this routine must be prepared for 111 * premature return, and check that the reason for 112 * sleeping has gone away. 113 */ 114 sleep(chan, pri) 115 caddr_t chan; 116 int pri; 117 { 118 register struct proc *rp, **hp; 119 register s; 120 121 rp = u.u_procp; 122 s = spl6(); 123 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 124 panic("sleep"); 125 rp->p_wchan = chan; 126 rp->p_slptime = 0; 127 rp->p_pri = pri; 128 hp = &slpque[HASH(chan)]; 129 rp->p_link = *hp; 130 *hp = rp; 131 if (pri > PZERO) { 132 if (ISSIG(rp)) { 133 if (rp->p_wchan) 134 unsleep(rp); 135 rp->p_stat = SRUN; 136 (void) spl0(); 137 goto psig; 138 } 139 if (rp->p_wchan == 0) 140 goto out; 141 rp->p_stat = SSLEEP; 142 (void) spl0(); 143 u.u_ru.ru_nvcsw++; 144 swtch(); 145 if (ISSIG(rp)) 146 goto psig; 147 } else { 148 rp->p_stat = SSLEEP; 149 (void) spl0(); 150 u.u_ru.ru_nvcsw++; 151 swtch(); 152 } 153 out: 154 splx(s); 155 return; 156 157 /* 158 * If priority was low (>PZERO) and 159 * there has been a signal, execute non-local goto through 160 * u.u_qsave, aborting the system call in progress (see trap.c) 161 * (or finishing a tsleep, see below) 162 */ 163 psig: 164 longjmp(&u.u_qsave); 165 /*NOTREACHED*/ 166 } 167 168 /* 169 * Remove a process from its wait queue 170 */ 171 unsleep(p) 172 register struct proc *p; 173 { 174 register struct proc **hp; 175 register s; 176 177 s = spl6(); 178 if (p->p_wchan) { 179 hp = &slpque[HASH(p->p_wchan)]; 180 while (*hp != p) 181 hp = &(*hp)->p_link; 182 *hp = p->p_link; 183 p->p_wchan = 0; 184 } 185 splx(s); 186 } 187 188 /* 189 * Wake up all processes sleeping on chan. 190 */ 191 wakeup(chan) 192 register caddr_t chan; 193 { 194 register struct proc *p, **q, **h; 195 int s; 196 197 s = spl6(); 198 h = &slpque[HASH(chan)]; 199 restart: 200 for (q = h; p = *q; ) { 201 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 202 panic("wakeup"); 203 if (p->p_wchan==chan) { 204 p->p_wchan = 0; 205 *q = p->p_link; 206 p->p_slptime = 0; 207 if (p->p_stat == SSLEEP) { 208 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 209 p->p_stat = SRUN; 210 if (p->p_flag & SLOAD) 211 setrq(p); 212 if (p->p_pri < curpri) { 213 runrun++; 214 aston(); 215 } 216 if ((p->p_flag&SLOAD) == 0) { 217 if (runout != 0) { 218 runout = 0; 219 wakeup((caddr_t)&runout); 220 } 221 wantin++; 222 } 223 /* END INLINE EXPANSION */ 224 goto restart; 225 } 226 } else 227 q = &p->p_link; 228 } 229 splx(s); 230 } 231 232 /* 233 * Initialize the (doubly-linked) run queues 234 * to be empty. 235 */ 236 rqinit() 237 { 238 register int i; 239 240 for (i = 0; i < NQS; i++) 241 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 242 } 243 244 /* 245 * Set the process running; 246 * arrange for it to be swapped in if necessary. 247 */ 248 setrun(p) 249 register struct proc *p; 250 { 251 register int s; 252 253 s = spl6(); 254 switch (p->p_stat) { 255 256 case 0: 257 case SWAIT: 258 case SRUN: 259 case SZOMB: 260 default: 261 panic("setrun"); 262 263 case SSTOP: 264 case SSLEEP: 265 unsleep(p); /* e.g. when sending signals */ 266 break; 267 268 case SIDL: 269 break; 270 } 271 p->p_stat = SRUN; 272 if (p->p_flag & SLOAD) 273 setrq(p); 274 splx(s); 275 if (p->p_pri < curpri) { 276 runrun++; 277 aston(); 278 } 279 if ((p->p_flag&SLOAD) == 0) { 280 if (runout != 0) { 281 runout = 0; 282 wakeup((caddr_t)&runout); 283 } 284 wantin++; 285 } 286 } 287 288 /* 289 * Set user priority. 290 * The rescheduling flag (runrun) 291 * is set if the priority is better 292 * than the currently running process. 293 */ 294 setpri(pp) 295 register struct proc *pp; 296 { 297 register int p; 298 299 p = (pp->p_cpu & 0377)/4; 300 p += PUSER + 2*(pp->p_nice - NZERO); 301 if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 302 p += 2*4; /* effectively, nice(4) */ 303 if (p > 127) 304 p = 127; 305 if (p < curpri) { 306 runrun++; 307 aston(); 308 } 309 pp->p_usrpri = p; 310 return (p); 311 } 312