1: /* 2: * SCCS id @(#)clock.c 2.1 (Berkeley) 9/1/83 3: */ 4: 5: #include "param.h" 6: #include <sys/systm.h> 7: #include <sys/callout.h> 8: #include <sys/seg.h> 9: #include <sys/dir.h> 10: #include <sys/user.h> 11: #include <sys/proc.h> 12: #include <sys/reg.h> 13: #ifdef UCB_METER 14: #include <sys/text.h> 15: #include <sys/vm.h> 16: #endif 17: #ifdef UCB_NET 18: /* 19: * shifted to keep "make depend" from finding these for now... 20: */ 21: # include <sys/protosw.h> 22: # include <sys/socket.h> 23: # include "../net/if.h" 24: # include "../net/in_systm.h" 25: #endif 26: 27: #ifdef UCB_FRCSWAP 28: extern int idleflg; /* If set, allow incore forks and expands */ 29: /* Set before idle(), cleared in clock.c */ 30: #endif 31: 32: #ifdef UCB_NET 33: /* 34: * Protoslow is like lbolt, but for slow protocol timeouts, counting 35: * up to (hz/PR_SLOWHZ), then causing a pfslowtimo(). 36: * Protofast is like lbolt, but for fast protocol timeouts, counting 37: * up to (hz/PR_FASTHZ), then causing a pffasttimo(). 38: */ 39: int protoslow; 40: int protofast; 41: int ifnetslow; 42: int netoff; 43: #endif 44: 45: #define SCHMAG 8/10 46: 47: /* 48: * clock is called straight from 49: * the real time clock interrupt. 50: * 51: * Functions: 52: * reprime clock 53: * copy *switches to display 54: * implement callouts 55: * maintain user/system times 56: * maintain date 57: * profile 58: * lightning bolt wakeup (every second) 59: * alarm clock signals 60: * jab the scheduler 61: */ 62: 63: /*ARGSUSED*/ 64: #ifdef MENLO_KOV 65: clock(dev, sp, r1, ov, nps, r0, pc, ps) 66: #else 67: clock(dev, sp, r1, nps, r0, pc, ps) 68: #endif 69: dev_t dev; 70: caddr_t pc; 71: { 72: register a; 73: mapinfo map; 74: extern caddr_t waitloc; 75: extern char *panicstr; 76: 77: /* 78: * restart clock 79: */ 80: if(lks) 81: *lks = 0115; 82: /* 83: * ensure normal mapping of kernel data 84: */ 85: savemap(map); 86: 87: #ifdef DISPLAY 88: /* 89: * display register 90: */ 91: display(); 92: #endif 93: 94: /* 95: * callouts 96: * never after panics 97: * if none, just continue 98: * else update first non-zero time 99: */ 100: if (panicstr == (char *) 0) { 101: register struct callout *p1, *p2; 102: 103: if(callout[0].c_func == NULL) 104: goto out; 105: p2 = &callout[0]; 106: while(p2->c_time<=0 && p2->c_func!=NULL) 107: p2++; 108: p2->c_time--; 109: 110: #ifdef UCB_NET 111: /* 112: * Time moves on for protocols. 113: */ 114: if(!netoff) { 115: --protoslow; --protofast; --ifnetslow; 116: if(protoslow<=0 || protofast<=0 || ifnetslow<=0) 117: schednetisr(NETISR_CLOCK); 118: } 119: #endif 120: 121: /* 122: * if ps is high, just return 123: */ 124: if (!BASEPRI(ps)) 125: goto out; 126: 127: /* 128: * callout 129: */ 130: if(callout[0].c_time <= 0) { 131: p1 = &callout[0]; 132: while(p1->c_func != 0 && p1->c_time <= 0) { 133: (*p1->c_func)(p1->c_arg); 134: p1++; 135: } 136: p2 = &callout[0]; 137: while(p2->c_func = p1->c_func) { 138: p2->c_time = p1->c_time; 139: p2->c_arg = p1->c_arg; 140: p1++; 141: p2++; 142: } 143: } 144: } 145: out: 146: 147: a = (dk_busy != 0); 148: if (USERMODE(ps)) { 149: u.u_utime++; 150: if(u.u_prof.pr_scale) 151: addupc(pc, &u.u_prof, 1); 152: if(u.u_procp->p_nice > NZERO) 153: a += 2; 154: } else { 155: a += 4; 156: if (pc == waitloc) 157: a += 2; 158: u.u_stime++; 159: } 160: sy_time[a] += 1; 161: dk_time[dk_busy & ((1 << ndisk) - 1)] += 1; 162: { 163: register struct proc *pp; 164: pp = u.u_procp; 165: if(++pp->p_cpu == 0) 166: pp->p_cpu--; 167: } 168: /* 169: * lightning bolt time-out 170: * and time of day 171: */ 172: if ((++lbolt >= hz) && (BASEPRI(ps))) { 173: register struct proc *pp; 174: 175: lbolt -= hz; 176: #ifdef UCB_FRCSWAP 177: idleflg = 0; 178: #endif 179: ++time; 180: (void) _spl1(); 181: #if defined(UCB_LOAD) || defined(UCB_METER) 182: meter(); 183: #endif 184: runrun++; 185: wakeup((caddr_t)&lbolt); 186: for(pp = &proc[0]; pp <= maxproc; pp++) 187: if (pp->p_stat && pp->p_stat<SZOMB) { 188: if(pp->p_time != 127) 189: pp->p_time++; 190: #ifdef UCB_METER 191: if (pp->p_stat == SSLEEP || pp->p_stat == SSTOP) 192: if (pp->p_slptime != 127) 193: pp->p_slptime++; 194: #endif UCB_METER 195: if (pp->p_clktim && --pp->p_clktim == 0) 196: #ifdef UCB_NET 197: /* 198: * If process has clock counting down, and it 199: * expires, set it running (if this is a 200: * tsleep()), or give it an SIGALRM (if the user 201: * process is using alarm signals. 202: */ 203: if (pp->p_flag & STIMO) { 204: a = spl6(); 205: switch (pp->p_stat) { 206: 207: case SSLEEP: 208: setrun(pp); 209: break; 210: 211: case SSTOP: 212: unsleep(pp); 213: break; 214: } 215: pp->p_flag &= ~STIMO; 216: splx(a); 217: } else 218: #endif 219: psignal(pp, SIGALRM); 220: a = (pp->p_cpu & 0377) * SCHMAG + pp->p_nice - NZERO; 221: if(a < 0) 222: a = 0; 223: if(a > 255) 224: a = 255; 225: pp->p_cpu = a; 226: if(pp->p_pri >= PUSER) 227: setpri(pp); 228: } 229: if(runin!=0) { 230: runin = 0; 231: wakeup((caddr_t)&runin); 232: } 233: } 234: restormap(map); 235: } 236: 237: /* 238: * timeout is called to arrange that 239: * fun(arg) is called in tim/hz seconds. 240: * An entry is sorted into the callout 241: * structure. The time in each structure 242: * entry is the number of hz's more 243: * than the previous entry. 244: * In this way, decrementing the 245: * first entry has the effect of 246: * updating all entries. 247: * 248: * The panic is there because there is nothing 249: * intelligent to be done if an entry won't fit. 250: */ 251: timeout(fun, arg, tim) 252: int (*fun)(); 253: caddr_t arg; 254: { 255: register struct callout *p1, *p2; 256: register int t; 257: int s; 258: 259: t = tim; 260: p1 = &callout[0]; 261: s = spl7(); 262: while(p1->c_func != 0 && p1->c_time <= t) { 263: t -= p1->c_time; 264: p1++; 265: } 266: p1->c_time -= t; 267: p2 = p1; 268: while(p2->c_func != 0) 269: p2++; 270: if (p2 >= callNCALL) 271: panic("Timeout table overflow"); 272: while(p2 >= p1) { 273: (p2+1)->c_time = p2->c_time; 274: (p2+1)->c_func = p2->c_func; 275: (p2+1)->c_arg = p2->c_arg; 276: p2--; 277: } 278: p1->c_time = t; 279: p1->c_func = fun; 280: p1->c_arg = arg; 281: splx(s); 282: return; 283: } 284: 285: #if defined(UCB_LOAD) || defined(UCB_METER) 286: /* 287: * Count up various things once a second 288: */ 289: short avenrun[3]; /* internal load average in psuedo-floating point */ 290: #define ave(smooth,new,time) (smooth) = (((time)-1) * (smooth) + (new))/ (time) 291: 292: #define ctok(cliks) (((cliks) >> 4) & 07777) /* clicks to KB */ 293: 294: meter() 295: { 296: #ifdef UCB_METER 297: register unsigned *cp, *rp; 298: register long *sp; 299: 300: ave(avefree, ctok(freemem), 5); 301: #endif 302: 303: if (time % 5 == 0) { 304: vmtotal(); 305: #ifdef UCB_METER 306: cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.vs_first; 307: while (cp <= &cnt.v_last) { 308: *rp = *cp; 309: *sp += *cp; 310: *cp = 0; 311: rp++, cp++, sp++; 312: } 313: #endif 314: } 315: } 316: 317: vmtotal() 318: { 319: extern char counted[]; 320: register struct proc *p; 321: register struct text *xq; 322: register nrun = 0; 323: #ifdef UCB_METER 324: int nt; 325: 326: total.t_vmtxt = 0; 327: total.t_avmtxt = 0; 328: total.t_rmtxt = 0; 329: total.t_armtxt = 0; 330: for (xq = text; xq < textNTEXT; xq++) { 331: counted[xq-text]=0; 332: if (xq->x_iptr) { 333: total.t_vmtxt += xq->x_size; 334: if (xq->x_ccount) 335: total.t_rmtxt += xq->x_size; 336: } 337: } 338: total.t_vm = 0; 339: total.t_avm = 0; 340: total.t_rm = 0; 341: total.t_arm = 0; 342: total.t_rq = 0; 343: total.t_dw = 0; 344: total.t_sl = 0; 345: total.t_sw = 0; 346: #endif 347: for (p = &proc[1]; p <= maxproc; p++) { 348: if (p->p_stat) { 349: #ifdef UCB_METER 350: #ifndef VIRUS_VFORK 351: total.t_vm += p->p_size; 352: if (p->p_flag & SLOAD) 353: total.t_rm += p->p_size; 354: #else 355: total.t_vm += p->p_dsize + p->p_ssize + USIZE; 356: if (p->p_flag & SLOAD) 357: total.t_rm += p->p_dsize + p->p_ssize + USIZE; 358: #endif 359: #endif 360: switch (p->p_stat) { 361: 362: case SSLEEP: 363: case SSTOP: 364: if (p->p_pri <= PZERO) 365: nrun++; 366: #ifdef UCB_METER 367: if (p->p_flag & SLOAD) { 368: if (p->p_pri <= PZERO) 369: total.t_dw++; 370: else if (p->p_slptime < MAXSLP) 371: total.t_sl++; 372: } else if (p->p_slptime < MAXSLP) 373: total.t_sw++; 374: if (p->p_slptime < MAXSLP) 375: goto active; 376: #endif 377: break; 378: 379: case SRUN: 380: case SIDL: 381: nrun++; 382: #ifdef UCB_METER 383: if (p->p_flag & SLOAD) 384: total.t_rq++; 385: else 386: total.t_sw++; 387: active: 388: #ifndef VIRUS_VFORK 389: total.t_avm += p->p_size; 390: if (p->p_flag & SLOAD) 391: total.t_arm += p->p_size; 392: #else 393: total.t_avm += p->p_dsize + p->p_ssize + USIZE; 394: if (p->p_flag & SLOAD) 395: total.t_arm += 396: p->p_dsize + p->p_ssize + USIZE; 397: #endif 398: if (p->p_textp) { 399: total.t_avmtxt += p->p_textp->x_size; 400: nt = p->p_textp-text; 401: if (counted[nt]==0) { 402: counted[nt]=1; 403: if (p->p_textp->x_ccount) 404: total.t_armtxt += 405: p->p_textp->x_size; 406: } 407: } 408: #endif 409: break; 410: } 411: } 412: } 413: #ifdef UCB_METER 414: total.t_vm += total.t_vmtxt; 415: total.t_avm += total.t_avmtxt; 416: total.t_rm += total.t_rmtxt; 417: total.t_arm += total.t_armtxt; 418: total.t_free = avefree; 419: #endif 420: loadav(avenrun, nrun); 421: } 422: 423: /* 424: * Compute Tenex style load average. This code is adapted from similar 425: * code by Bill Joy on the Vax system. The major change is that we 426: * avoid floating point since not all pdp-11's have it. This makes 427: * the code quite hard to read - it was derived with some algebra. 428: * 429: * "floating point" numbers here are stored in a 16 bit short, with 430: * 8 bits on each side of the decimal point. Some partial products 431: * will have 16 bits to the right. 432: */ 433: 434: /* 435: * The Vax algorithm is: 436: * 437: * /* 438: * * Constants for averages over 1, 5, and 15 minutes 439: * * when sampling at 5 second intervals. 440: * * / 441: * double cexp[3] = { 442: * 0.9200444146293232, /* exp(-1/12) * / 443: * 0.9834714538216174, /* exp(-1/60) * / 444: * 0.9944598480048967, /* exp(-1/180) * / 445: * }; 446: * 447: * /* 448: * * Compute a tenex style load average of a quantity on 449: * * 1, 5 and 15 minute intervals. 450: * * / 451: * loadav(avg, n) 452: * register double *avg; 453: * int n; 454: * { 455: * register int i; 456: * 457: * for (i = 0; i < 3; i++) 458: * avg[i] = cexp[i] * avg[i] + n * (1.0 - cexp[i]); 459: * } 460: */ 461: 462: long cexp[3] = { 463: 0353, /* 256*exp(-1/12) */ 464: 0373, /* 256*exp(-1/60) */ 465: 0376, /* 256*exp(-1/180) */ 466: }; 467: 468: loadav(avg, n) 469: register short *avg; 470: register n; 471: { 472: register int i; 473: 474: for (i = 0; i < 3; i++) 475: avg[i] = (cexp[i] * (avg[i]-(n<<8)) + (((long)n)<<16)) >> 8; 476: } 477: #endif