123376Smckusick /* 240711Skarels * Copyright (c) 1982, 1986, 1990 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*45742Smckusick * @(#)kern_synch.c 7.13 (Berkeley) 12/05/90 723376Smckusick */ 833Sbill 917093Sbloom #include "param.h" 1017093Sbloom #include "systm.h" 1117093Sbloom #include "user.h" 1217093Sbloom #include "proc.h" 1317093Sbloom #include "kernel.h" 1417093Sbloom #include "buf.h" 159756Ssam 16*45742Smckusick #include "machine/psl.h" 17*45742Smckusick #include "machine/mtpr.h" 18*45742Smckusick 198102Sroot /* 208102Sroot * Force switch among equal priority processes every 100ms. 218102Sroot */ 228102Sroot roundrobin() 238102Sroot { 248102Sroot 258102Sroot runrun++; 268102Sroot aston(); 278624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 288102Sroot } 298102Sroot 3032908Smckusick /* 3132908Smckusick * constants for digital decay and forget 3232908Smckusick * 90% of (p_cpu) usage in 5*loadav time 3332908Smckusick * 95% of (p_pctcpu) usage in 60 seconds (load insensitive) 3432908Smckusick * Note that, as ps(1) mentions, this can let percentages 3532908Smckusick * total over 100% (I've seen 137.9% for 3 processes). 3632908Smckusick * 3732908Smckusick * Note that hardclock updates p_cpu and p_cpticks independently. 3832908Smckusick * 3932908Smckusick * We wish to decay away 90% of p_cpu in (5 * loadavg) seconds. 4032908Smckusick * That is, the system wants to compute a value of decay such 4132908Smckusick * that the following for loop: 4232908Smckusick * for (i = 0; i < (5 * loadavg); i++) 4332908Smckusick * p_cpu *= decay; 4432908Smckusick * will compute 4532908Smckusick * p_cpu *= 0.1; 4632908Smckusick * for all values of loadavg: 4732908Smckusick * 4832908Smckusick * Mathematically this loop can be expressed by saying: 4932908Smckusick * decay ** (5 * loadavg) ~= .1 5032908Smckusick * 5132908Smckusick * The system computes decay as: 5232908Smckusick * decay = (2 * loadavg) / (2 * loadavg + 1) 5332908Smckusick * 5432908Smckusick * We wish to prove that the system's computation of decay 5532908Smckusick * will always fulfill the equation: 5632908Smckusick * decay ** (5 * loadavg) ~= .1 5732908Smckusick * 5832908Smckusick * If we compute b as: 5932908Smckusick * b = 2 * loadavg 6032908Smckusick * then 6132908Smckusick * decay = b / (b + 1) 6232908Smckusick * 6332908Smckusick * We now need to prove two things: 6432908Smckusick * 1) Given factor ** (5 * loadavg) ~= .1, prove factor == b/(b+1) 6532908Smckusick * 2) Given b/(b+1) ** power ~= .1, prove power == (5 * loadavg) 6632908Smckusick * 6732908Smckusick * Facts: 6832908Smckusick * For x close to zero, exp(x) =~ 1 + x, since 6932908Smckusick * exp(x) = 0! + x**1/1! + x**2/2! + ... . 7032908Smckusick * therefore exp(-1/b) =~ 1 - (1/b) = (b-1)/b. 7132908Smckusick * For x close to zero, ln(1+x) =~ x, since 7232908Smckusick * ln(1+x) = x - x**2/2 + x**3/3 - ... -1 < x < 1 7332908Smckusick * therefore ln(b/(b+1)) = ln(1 - 1/(b+1)) =~ -1/(b+1). 7432908Smckusick * ln(.1) =~ -2.30 7532908Smckusick * 7632908Smckusick * Proof of (1): 7732908Smckusick * Solve (factor)**(power) =~ .1 given power (5*loadav): 7832908Smckusick * solving for factor, 7932908Smckusick * ln(factor) =~ (-2.30/5*loadav), or 8032908Smckusick * factor =~ exp(-1/((5/2.30)*loadav) =~ exp(-1/(2*loadav)) = 8132908Smckusick * exp(-1/b) =~ (b-1)/b =~ b/(b+1). QED 8232908Smckusick * 8332908Smckusick * Proof of (2): 8432908Smckusick * Solve (factor)**(power) =~ .1 given factor == (b/(b+1)): 8532908Smckusick * solving for power, 8632908Smckusick * power*ln(b/(b+1)) =~ -2.30, or 8732908Smckusick * power =~ 2.3 * (b + 1) = 4.6*loadav + 2.3 =~ 5*loadav. QED 8832908Smckusick * 8932908Smckusick * Actual power values for the implemented algorithm are as follows: 9032908Smckusick * loadav: 1 2 3 4 9132908Smckusick * power: 5.68 10.32 14.94 19.55 9232908Smckusick */ 9317541Skarels 9438164Smckusick /* calculations for digital decay to forget 90% of usage in 5*loadav sec */ 9538164Smckusick #define get_b(loadav) (2 * (loadav)) 9638164Smckusick #define get_pcpu(b, cpu) (((b) * ((cpu) & 0377)) / ((b) + FSCALE)) 978102Sroot 9838164Smckusick /* decay 95% of `p_pctcpu' in 60 seconds; see CCPU_SHIFT before changing */ 9938164Smckusick fixpt_t ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */ 10038164Smckusick 1018102Sroot /* 10238164Smckusick * If `ccpu' is not equal to `exp(-1/20)' and you still want to use the 10338164Smckusick * faster/more-accurate formula, you'll have to estimate CCPU_SHIFT below 10438164Smckusick * and possibly adjust FSHIFT in "param.h" so that (FSHIFT >= CCPU_SHIFT). 10538164Smckusick * 10638164Smckusick * To estimate CCPU_SHIFT for exp(-1/20), the following formula was used: 10738164Smckusick * 1 - exp(-1/20) ~= 0.0487 ~= 0.0488 == 1 (fixed pt, *11* bits). 10838164Smckusick * 10938164Smckusick * If you dont want to bother with the faster/more-accurate formula, you 11038164Smckusick * can set CCPU_SHIFT to (FSHIFT + 1) which will use a slower/less-accurate 11138164Smckusick * (more general) method of calculating the %age of CPU used by a process. 11238164Smckusick */ 11338164Smckusick #define CCPU_SHIFT 11 11438164Smckusick 11538164Smckusick /* 1168102Sroot * Recompute process priorities, once a second 1178102Sroot */ 1188102Sroot schedcpu() 1198102Sroot { 12038164Smckusick register fixpt_t b = get_b(averunnable[0]); 1218102Sroot register struct proc *p; 1228102Sroot register int s, a; 1238102Sroot 1248102Sroot wakeup((caddr_t)&lbolt); 12516532Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 1268102Sroot if (p->p_time != 127) 1278102Sroot p->p_time++; 1288102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 1298102Sroot if (p->p_slptime != 127) 1308102Sroot p->p_slptime++; 13138164Smckusick p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT; 13217541Skarels /* 13317541Skarels * If the process has slept the entire second, 13417541Skarels * stop recalculating its priority until it wakes up. 13517541Skarels */ 13638164Smckusick if (p->p_slptime > 1) 13717541Skarels continue; 13817541Skarels /* 13917541Skarels * p_pctcpu is only for ps. 14017541Skarels */ 14138164Smckusick #if (FSHIFT >= CCPU_SHIFT) 14238164Smckusick p->p_pctcpu += (hz == 100)? 14338164Smckusick ((fixpt_t) p->p_cpticks) << (FSHIFT - CCPU_SHIFT): 14438164Smckusick 100 * (((fixpt_t) p->p_cpticks) 14538164Smckusick << (FSHIFT - CCPU_SHIFT)) / hz; 14638164Smckusick #else 14738164Smckusick p->p_pctcpu += ((FSCALE - ccpu) * 14838164Smckusick (p->p_cpticks * FSCALE / hz)) >> FSHIFT; 14938164Smckusick #endif 1508102Sroot p->p_cpticks = 0; 15138164Smckusick a = (int) get_pcpu(b, p->p_cpu) + p->p_nice; 1528102Sroot if (a < 0) 1538102Sroot a = 0; 1548102Sroot if (a > 255) 1558102Sroot a = 255; 1568102Sroot p->p_cpu = a; 1578102Sroot (void) setpri(p); 15817541Skarels s = splhigh(); /* prevent state changes */ 1598102Sroot if (p->p_pri >= PUSER) { 16016795Skarels #define PPQ (128 / NQS) 1618102Sroot if ((p != u.u_procp || noproc) && 1628102Sroot p->p_stat == SRUN && 1638102Sroot (p->p_flag & SLOAD) && 16416795Skarels (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) { 1658102Sroot remrq(p); 1668102Sroot p->p_pri = p->p_usrpri; 1678102Sroot setrq(p); 1688102Sroot } else 1698102Sroot p->p_pri = p->p_usrpri; 1708102Sroot } 1718102Sroot splx(s); 1728102Sroot } 1738102Sroot vmmeter(); 1748102Sroot if (runin!=0) { 1758102Sroot runin = 0; 1768102Sroot wakeup((caddr_t)&runin); 1778102Sroot } 1788102Sroot if (bclnlist != NULL) 1798102Sroot wakeup((caddr_t)&proc[2]); 1808624Sroot timeout(schedcpu, (caddr_t)0, hz); 1818102Sroot } 1828102Sroot 18317541Skarels /* 18417541Skarels * Recalculate the priority of a process after it has slept for a while. 18517541Skarels */ 18617541Skarels updatepri(p) 18717541Skarels register struct proc *p; 18817541Skarels { 18917541Skarels register int a = p->p_cpu & 0377; 19038164Smckusick register fixpt_t b = get_b(averunnable[0]); 19117541Skarels 19217541Skarels p->p_slptime--; /* the first time was done in schedcpu */ 19317541Skarels while (a && --p->p_slptime) 19438164Smckusick a = (int) get_pcpu(b, a) /* + p->p_nice */; 19530232Skarels p->p_slptime = 0; 19617541Skarels if (a < 0) 19717541Skarels a = 0; 19817541Skarels if (a > 255) 19917541Skarels a = 255; 20017541Skarels p->p_cpu = a; 20117541Skarels (void) setpri(p); 20217541Skarels } 20317541Skarels 20433Sbill #define SQSIZE 0100 /* Must be power of 2 */ 20533Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 20621099Smckusick struct slpque { 20721099Smckusick struct proc *sq_head; 20821099Smckusick struct proc **sq_tailp; 20921099Smckusick } slpque[SQSIZE]; 21033Sbill 21133Sbill /* 21245671Skarels * During autoconfiguration or after a panic, a sleep will simply 21345671Skarels * lower the priority briefly to allow interrupts, then return. 21445671Skarels * The priority to be used (safepri) is machine-dependent, thus this 21545671Skarels * value is initialized and maintained in the machine-dependent layers. 21645671Skarels * This priority will typically be 0, or the lowest priority 21745671Skarels * that is safe for use on the interrupt stack; it can be made 21845671Skarels * higher to block network software interrupts after panics. 21945671Skarels */ 22045671Skarels int safepri; 22145671Skarels 22245671Skarels /* 22340711Skarels * General sleep call. 22440711Skarels * Suspends current process until a wakeup is made on chan. 22540711Skarels * The process will then be made runnable with priority pri. 22640711Skarels * Sleeps at most timo/hz seconds (0 means no timeout). 22740711Skarels * If pri includes PCATCH flag, signals are checked 22840711Skarels * before and after sleeping, else signals are not checked. 22940711Skarels * Returns 0 if awakened, EWOULDBLOCK if the timeout expires. 23040711Skarels * If PCATCH is set and a signal needs to be delivered, 23140711Skarels * ERESTART is returned if the current system call should be restarted 23240711Skarels * if possible, and EINTR is returned if the system call should 23340711Skarels * be interrupted by the signal (return EINTR). 23433Sbill */ 23540711Skarels tsleep(chan, pri, wmesg, timo) 23640710Smarc caddr_t chan; 23740710Smarc int pri; 23840710Smarc char *wmesg; 23940710Smarc int timo; 24040710Smarc { 24140710Smarc register struct proc *rp; 24240710Smarc register struct slpque *qp; 24340710Smarc register s; 24440711Skarels int sig, catch = pri & PCATCH; 24540710Smarc extern int cold; 24640710Smarc int endtsleep(); 24740710Smarc 24840710Smarc rp = u.u_procp; 24940710Smarc s = splhigh(); 25040710Smarc if (cold || panicstr) { 25140710Smarc /* 25240710Smarc * After a panic, or during autoconfiguration, 25340710Smarc * just give interrupts a chance, then just return; 25440710Smarc * don't run any other procs or panic below, 25540710Smarc * in case this is the idle process and already asleep. 25640710Smarc */ 25745671Skarels splx(safepri); 25840710Smarc splx(s); 25940710Smarc return (0); 26040710Smarc } 26140710Smarc #ifdef DIAGNOSTIC 26240711Skarels if (chan == 0 || rp->p_stat != SRUN || rp->p_rlink) 26340711Skarels panic("tsleep"); 26440710Smarc #endif 26540710Smarc rp->p_wchan = chan; 26640710Smarc rp->p_wmesg = wmesg; 26740710Smarc rp->p_slptime = 0; 26840711Skarels rp->p_pri = pri & PRIMASK; 26940710Smarc qp = &slpque[HASH(chan)]; 27040710Smarc if (qp->sq_head == 0) 27140710Smarc qp->sq_head = rp; 27240710Smarc else 27340710Smarc *qp->sq_tailp = rp; 27440710Smarc *(qp->sq_tailp = &rp->p_link) = 0; 27545671Skarels if (timo) 27645671Skarels timeout(endtsleep, (caddr_t)rp, timo); 27740710Smarc /* 27845671Skarels * If we stop in CURSIG/issig(), a wakeup or a SIGCONT 27945671Skarels * (or both) could occur while we were stopped. 28045671Skarels * A SIGCONT would cause us to be marked as SSLEEP 28145671Skarels * without resuming us, thus we must be ready for sleep 28245671Skarels * when CURSIG is called. If the wakeup happens while we're 28345671Skarels * stopped, rp->p_wchan will be 0 upon return from CURSIG. 28440710Smarc */ 28540711Skarels if (catch) { 28645671Skarels rp->p_flag |= SSINTR; 28740711Skarels if (sig = CURSIG(rp)) { 28840711Skarels if (rp->p_wchan) 28940711Skarels unsleep(rp); 29040711Skarels rp->p_stat = SRUN; 29145671Skarels goto resume; 29240711Skarels } 29340711Skarels if (rp->p_wchan == 0) { 29445671Skarels catch = 0; 29545671Skarels goto resume; 29640711Skarels } 29740710Smarc } 29840710Smarc rp->p_stat = SSLEEP; 29940710Smarc (void) spl0(); 30040710Smarc u.u_ru.ru_nvcsw++; 30140710Smarc swtch(); 30245671Skarels resume: 30340710Smarc curpri = rp->p_usrpri; 30440710Smarc splx(s); 30540711Skarels rp->p_flag &= ~SSINTR; 30640710Smarc if (rp->p_flag & STIMO) { 30740710Smarc rp->p_flag &= ~STIMO; 30845671Skarels if (catch == 0 || sig == 0) 30945671Skarels return (EWOULDBLOCK); 31045671Skarels } else if (timo) 31140710Smarc untimeout(endtsleep, (caddr_t)rp); 31245671Skarels if (catch && (sig != 0 || (sig = CURSIG(rp)))) { 31340711Skarels if (u.u_sigintr & sigmask(sig)) 31440711Skarels return (EINTR); 31540711Skarels return (ERESTART); 31640711Skarels } 31740710Smarc return (0); 31840710Smarc } 31940710Smarc 32040710Smarc /* 32140710Smarc * Implement timeout for tsleep. 32240710Smarc * If process hasn't been awakened (wchan non-zero), 32340710Smarc * set timeout flag and undo the sleep. If proc 32440710Smarc * is stopped, just unsleep so it will remain stopped. 32540710Smarc */ 32640710Smarc endtsleep(p) 32740710Smarc register struct proc *p; 32840710Smarc { 32940710Smarc int s = splhigh(); 33040710Smarc 33140710Smarc if (p->p_wchan) { 33240710Smarc if (p->p_stat == SSLEEP) 33340710Smarc setrun(p); 33440710Smarc else 33540710Smarc unsleep(p); 33640710Smarc p->p_flag |= STIMO; 33740710Smarc } 33840710Smarc splx(s); 33940710Smarc } 34040710Smarc 34140711Skarels /* 34240711Skarels * Short-term, non-interruptable sleep. 34340711Skarels */ 34433Sbill sleep(chan, pri) 3458033Sroot caddr_t chan; 3468033Sroot int pri; 34733Sbill { 34821099Smckusick register struct proc *rp; 34921099Smckusick register struct slpque *qp; 350207Sbill register s; 35130532Skarels extern int cold; 35233Sbill 35340711Skarels #ifdef DIAGNOSTIC 35440711Skarels if (pri > PZERO) { 35540711Skarels printf("sleep called with pri %d > PZERO, wchan: %x\n", 35640711Skarels pri, chan); 35740711Skarels panic("old sleep"); 35840711Skarels } 35940711Skarels #endif 36033Sbill rp = u.u_procp; 36117541Skarels s = splhigh(); 36230532Skarels if (cold || panicstr) { 36318363Skarels /* 36430532Skarels * After a panic, or during autoconfiguration, 36530532Skarels * just give interrupts a chance, then just return; 36630532Skarels * don't run any other procs or panic below, 36730532Skarels * in case this is the idle process and already asleep. 36818363Skarels */ 36945671Skarels splx(safepri); 37018363Skarels splx(s); 37118363Skarels return; 37218363Skarels } 37340710Smarc #ifdef DIAGNOSTIC 37418363Skarels if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 37533Sbill panic("sleep"); 37640710Smarc #endif 37733Sbill rp->p_wchan = chan; 37840710Smarc rp->p_wmesg = NULL; 37933Sbill rp->p_slptime = 0; 38033Sbill rp->p_pri = pri; 38121099Smckusick qp = &slpque[HASH(chan)]; 38221099Smckusick if (qp->sq_head == 0) 38321099Smckusick qp->sq_head = rp; 38421099Smckusick else 38521099Smckusick *qp->sq_tailp = rp; 38621099Smckusick *(qp->sq_tailp = &rp->p_link) = 0; 38740711Skarels rp->p_stat = SSLEEP; 38840711Skarels (void) spl0(); 38940711Skarels u.u_ru.ru_nvcsw++; 39040711Skarels swtch(); 39116795Skarels curpri = rp->p_usrpri; 39233Sbill splx(s); 39333Sbill } 39433Sbill 39533Sbill /* 396181Sbill * Remove a process from its wait queue 397181Sbill */ 398181Sbill unsleep(p) 3994826Swnj register struct proc *p; 400181Sbill { 40121099Smckusick register struct slpque *qp; 402181Sbill register struct proc **hp; 40321099Smckusick int s; 404181Sbill 40517541Skarels s = splhigh(); 406181Sbill if (p->p_wchan) { 40721099Smckusick hp = &(qp = &slpque[HASH(p->p_wchan)])->sq_head; 408181Sbill while (*hp != p) 409181Sbill hp = &(*hp)->p_link; 410181Sbill *hp = p->p_link; 41121099Smckusick if (qp->sq_tailp == &p->p_link) 41221099Smckusick qp->sq_tailp = hp; 413181Sbill p->p_wchan = 0; 414181Sbill } 415181Sbill splx(s); 416181Sbill } 417181Sbill 418181Sbill /* 41933Sbill * Wake up all processes sleeping on chan. 42033Sbill */ 42133Sbill wakeup(chan) 4224826Swnj register caddr_t chan; 42333Sbill { 42421099Smckusick register struct slpque *qp; 42521099Smckusick register struct proc *p, **q; 42633Sbill int s; 42733Sbill 42817541Skarels s = splhigh(); 42921099Smckusick qp = &slpque[HASH(chan)]; 43033Sbill restart: 43121099Smckusick for (q = &qp->sq_head; p = *q; ) { 43240710Smarc #ifdef DIAGNOSTIC 433181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 43433Sbill panic("wakeup"); 43540710Smarc #endif 436207Sbill if (p->p_wchan==chan) { 43733Sbill p->p_wchan = 0; 438187Sbill *q = p->p_link; 43921099Smckusick if (qp->sq_tailp == &p->p_link) 44021099Smckusick qp->sq_tailp = q; 441181Sbill if (p->p_stat == SSLEEP) { 442181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 44321763Skarels if (p->p_slptime > 1) 44421763Skarels updatepri(p); 445181Sbill p->p_stat = SRUN; 4462702Swnj if (p->p_flag & SLOAD) 447181Sbill setrq(p); 44816795Skarels /* 44916795Skarels * Since curpri is a usrpri, 45016795Skarels * p->p_pri is always better than curpri. 45116795Skarels */ 45216795Skarels runrun++; 45316795Skarels aston(); 4543545Swnj if ((p->p_flag&SLOAD) == 0) { 4553545Swnj if (runout != 0) { 4563545Swnj runout = 0; 4573545Swnj wakeup((caddr_t)&runout); 4583545Swnj } 4593545Swnj wantin++; 460181Sbill } 461181Sbill /* END INLINE EXPANSION */ 462187Sbill goto restart; 46333Sbill } 464187Sbill } else 465187Sbill q = &p->p_link; 46633Sbill } 46733Sbill splx(s); 46833Sbill } 46933Sbill 47033Sbill /* 47133Sbill * Initialize the (doubly-linked) run queues 47233Sbill * to be empty. 47333Sbill */ 47433Sbill rqinit() 47533Sbill { 47633Sbill register int i; 47733Sbill 47833Sbill for (i = 0; i < NQS; i++) 47933Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 48033Sbill } 48133Sbill 48233Sbill /* 48333Sbill * Set the process running; 48433Sbill * arrange for it to be swapped in if necessary. 48533Sbill */ 48633Sbill setrun(p) 4874826Swnj register struct proc *p; 48833Sbill { 4894826Swnj register int s; 49033Sbill 49117541Skarels s = splhigh(); 49233Sbill switch (p->p_stat) { 49333Sbill 49433Sbill case 0: 49533Sbill case SWAIT: 49633Sbill case SRUN: 49733Sbill case SZOMB: 49833Sbill default: 49933Sbill panic("setrun"); 50033Sbill 501207Sbill case SSTOP: 50233Sbill case SSLEEP: 503181Sbill unsleep(p); /* e.g. when sending signals */ 50433Sbill break; 50533Sbill 50633Sbill case SIDL: 50733Sbill break; 50833Sbill } 50933Sbill p->p_stat = SRUN; 51033Sbill if (p->p_flag & SLOAD) 51133Sbill setrq(p); 51233Sbill splx(s); 51330232Skarels if (p->p_slptime > 1) 51430232Skarels updatepri(p); 5154826Swnj if (p->p_pri < curpri) { 51633Sbill runrun++; 5172443Swnj aston(); 5182443Swnj } 5193545Swnj if ((p->p_flag&SLOAD) == 0) { 5204826Swnj if (runout != 0) { 5213545Swnj runout = 0; 5223545Swnj wakeup((caddr_t)&runout); 5233545Swnj } 5243545Swnj wantin++; 52533Sbill } 52633Sbill } 52733Sbill 52833Sbill /* 52933Sbill * Set user priority. 53033Sbill * The rescheduling flag (runrun) 53133Sbill * is set if the priority is better 53233Sbill * than the currently running process. 53333Sbill */ 53433Sbill setpri(pp) 5354826Swnj register struct proc *pp; 53633Sbill { 5374826Swnj register int p; 53833Sbill 5393875Swnj p = (pp->p_cpu & 0377)/4; 54017541Skarels p += PUSER + 2 * pp->p_nice; 5414826Swnj if (p > 127) 54233Sbill p = 127; 5434826Swnj if (p < curpri) { 54433Sbill runrun++; 5452453Swnj aston(); 5462453Swnj } 54733Sbill pp->p_usrpri = p; 5484826Swnj return (p); 54933Sbill } 550