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