1*1400Sbill /* kern_synch.c 3.15 10/11/80 */ 233Sbill 333Sbill #include "../h/param.h" 433Sbill #include "../h/systm.h" 533Sbill #include "../h/dir.h" 633Sbill #include "../h/user.h" 733Sbill #include "../h/proc.h" 833Sbill #include "../h/file.h" 933Sbill #include "../h/inode.h" 1033Sbill #include "../h/vm.h" 1133Sbill #include "../h/pte.h" 12181Sbill #include "../h/inline.h" 1333Sbill 1433Sbill 1533Sbill #define SQSIZE 0100 /* Must be power of 2 */ 1633Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 1733Sbill struct proc *slpque[SQSIZE]; 1833Sbill 1933Sbill /* 2033Sbill * Give up the processor till a wakeup occurs 2133Sbill * on chan, at which time the process 2233Sbill * enters the scheduling queue at priority pri. 2333Sbill * The most important effect of pri is that when 2433Sbill * pri<=PZERO a signal cannot disturb the sleep; 2533Sbill * if pri>PZERO signals will be processed. 2633Sbill * Callers of this routine must be prepared for 2733Sbill * premature return, and check that the reason for 2833Sbill * sleeping has gone away. 2933Sbill */ 3033Sbill sleep(chan, pri) 3133Sbill caddr_t chan; 3233Sbill { 33187Sbill register struct proc *rp, **hp; 34207Sbill register s; 3533Sbill 3633Sbill rp = u.u_procp; 3733Sbill s = spl6(); 3833Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 3933Sbill panic("sleep"); 4033Sbill rp->p_wchan = chan; 4133Sbill rp->p_slptime = 0; 4233Sbill rp->p_pri = pri; 43187Sbill hp = &slpque[HASH(chan)]; 44187Sbill rp->p_link = *hp; 45187Sbill *hp = rp; 4633Sbill if(pri > PZERO) { 47181Sbill if(ISSIG(rp)) { 48187Sbill if (rp->p_wchan) 49187Sbill unsleep(rp); 5033Sbill rp->p_stat = SRUN; 51131Sbill (void) spl0(); 5233Sbill goto psig; 5333Sbill } 54187Sbill if (rp->p_wchan == 0) 55187Sbill goto out; 56187Sbill rp->p_stat = SSLEEP; 57131Sbill (void) spl0(); 5833Sbill if(runin != 0) { 5933Sbill runin = 0; 6033Sbill wakeup((caddr_t)&runin); 6133Sbill } 6233Sbill swtch(); 63181Sbill if(ISSIG(rp)) 6433Sbill goto psig; 6533Sbill } else { 66207Sbill rp->p_stat = SSLEEP; 67131Sbill (void) spl0(); 6833Sbill swtch(); 6933Sbill } 70187Sbill out: 7133Sbill splx(s); 7233Sbill return; 7333Sbill 7433Sbill /* 7533Sbill * If priority was low (>PZERO) and 7633Sbill * there has been a signal, 7733Sbill * execute non-local goto to 7833Sbill * the qsav location. 7933Sbill * (see trap1/trap.c) 8033Sbill */ 8133Sbill psig: 8233Sbill longjmp(u.u_qsav); 8333Sbill /*NOTREACHED*/ 8433Sbill } 8533Sbill 8633Sbill /* 87100Sbill * Sleep on chan at pri. 88100Sbill * Return in no more than the indicated number of seconds. 89100Sbill * (If seconds==0, no timeout implied) 90100Sbill * Return TS_OK if chan was awakened normally 91100Sbill * TS_TIME if timeout occurred 92100Sbill * TS_SIG if asynchronous signal occurred 93100Sbill */ 94100Sbill tsleep(chan, pri, seconds) 95100Sbill caddr_t chan; 96100Sbill { 97100Sbill label_t lqsav; 98100Sbill register struct proc *pp; 99100Sbill register sec, n, rval; 100100Sbill 101100Sbill pp = u.u_procp; 102102Sbill n = spl7(); 103100Sbill sec = 0; 104100Sbill rval = 0; 105100Sbill if (pp->p_clktim && pp->p_clktim<seconds) 106100Sbill seconds = 0; 107100Sbill if (seconds) { 108100Sbill pp->p_flag |= STIMO; 109103Sbill sec = pp->p_clktim-seconds; 110100Sbill pp->p_clktim = seconds; 111100Sbill } 112100Sbill bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 113100Sbill if (setjmp(u.u_qsav)) 114100Sbill rval = TS_SIG; 115100Sbill else { 116100Sbill sleep(chan, pri); 117100Sbill if ((pp->p_flag&STIMO)==0 && seconds) 118100Sbill rval = TS_TIME; 119100Sbill else 120100Sbill rval = TS_OK; 121100Sbill } 122100Sbill pp->p_flag &= ~STIMO; 123100Sbill bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 124103Sbill if (sec > 0) 125103Sbill pp->p_clktim += sec; 126103Sbill else 127103Sbill pp->p_clktim = 0; 128100Sbill splx(n); 129100Sbill return(rval); 130100Sbill } 131100Sbill 132100Sbill /* 133181Sbill * Remove a process from its wait queue 134181Sbill */ 135181Sbill unsleep(p) 136181Sbill register struct proc *p; 137181Sbill { 138181Sbill register struct proc **hp; 139181Sbill register s; 140181Sbill 141181Sbill s = spl6(); 142181Sbill if (p->p_wchan) { 143181Sbill hp = &slpque[HASH(p->p_wchan)]; 144181Sbill while (*hp != p) 145181Sbill hp = &(*hp)->p_link; 146181Sbill *hp = p->p_link; 147181Sbill p->p_wchan = 0; 148181Sbill } 149181Sbill splx(s); 150181Sbill } 151181Sbill 152181Sbill /* 15333Sbill * Wake up all processes sleeping on chan. 15433Sbill */ 15533Sbill wakeup(chan) 15633Sbill register caddr_t chan; 15733Sbill { 158187Sbill register struct proc *p, **q, **h; 15933Sbill int s; 16033Sbill 16133Sbill s = spl6(); 162187Sbill h = &slpque[HASH(chan)]; 16333Sbill restart: 164187Sbill for (q = h; p = *q; ) { 165181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 16633Sbill panic("wakeup"); 167207Sbill if (p->p_wchan==chan) { 16833Sbill p->p_wchan = 0; 169187Sbill *q = p->p_link; 17033Sbill p->p_slptime = 0; 171181Sbill if (p->p_stat == SSLEEP) { 172181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 173181Sbill p->p_stat = SRUN; 174181Sbill if (p->p_flag & SLOAD) { 17533Sbill #ifndef FASTVAX 176181Sbill p->p_link = runq; 177181Sbill runq = p->p_link; 17833Sbill #else 179181Sbill setrq(p); 18033Sbill #endif 181181Sbill } 182181Sbill if(p->p_pri < curpri) 183181Sbill runrun++; 184181Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 185181Sbill runout = 0; 186181Sbill wakeup((caddr_t)&runout); 187181Sbill } 188181Sbill /* END INLINE EXPANSION */ 189187Sbill goto restart; 19033Sbill } 191187Sbill } else 192187Sbill q = &p->p_link; 19333Sbill } 19433Sbill splx(s); 19533Sbill } 19633Sbill 19733Sbill #ifdef FASTVAX 19833Sbill /* 19933Sbill * Initialize the (doubly-linked) run queues 20033Sbill * to be empty. 20133Sbill */ 20233Sbill rqinit() 20333Sbill { 20433Sbill register int i; 20533Sbill 20633Sbill for (i = 0; i < NQS; i++) 20733Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 20833Sbill } 20933Sbill #endif 21033Sbill 21133Sbill /* 21233Sbill * Set the process running; 21333Sbill * arrange for it to be swapped in if necessary. 21433Sbill */ 21533Sbill setrun(p) 21633Sbill register struct proc *p; 21733Sbill { 21833Sbill register s; 21933Sbill 22033Sbill s = spl6(); 22133Sbill switch (p->p_stat) { 22233Sbill 22333Sbill case 0: 22433Sbill case SWAIT: 22533Sbill case SRUN: 22633Sbill case SZOMB: 22733Sbill default: 22833Sbill panic("setrun"); 22933Sbill 230207Sbill case SSTOP: 23133Sbill case SSLEEP: 232181Sbill unsleep(p); /* e.g. when sending signals */ 23333Sbill break; 23433Sbill 23533Sbill case SIDL: 23633Sbill break; 23733Sbill } 23833Sbill p->p_stat = SRUN; 23933Sbill if (p->p_flag & SLOAD) 24033Sbill setrq(p); 24133Sbill splx(s); 24233Sbill if(p->p_pri < curpri) 24333Sbill runrun++; 24433Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 24533Sbill runout = 0; 24633Sbill wakeup((caddr_t)&runout); 24733Sbill } 24833Sbill } 24933Sbill 25033Sbill /* 25133Sbill * Set user priority. 25233Sbill * The rescheduling flag (runrun) 25333Sbill * is set if the priority is better 25433Sbill * than the currently running process. 25533Sbill */ 25633Sbill setpri(pp) 25733Sbill register struct proc *pp; 25833Sbill { 25933Sbill register p; 26033Sbill 26133Sbill p = (pp->p_cpu & 0377)/16; 26233Sbill p += PUSER + pp->p_nice - NZERO; 26333Sbill if(p > 127) 26433Sbill p = 127; 26533Sbill if(p < curpri) 26633Sbill runrun++; 26733Sbill pp->p_usrpri = p; 26833Sbill return(p); 26933Sbill } 27033Sbill 27133Sbill /* 27233Sbill * Create a new process-- the internal version of 27333Sbill * sys fork. 27433Sbill * It returns 1 in the new process, 0 in the old. 27533Sbill */ 27633Sbill newproc(isvfork) 27733Sbill { 27833Sbill register struct proc *p; 27933Sbill register struct proc *rpp, *rip; 28033Sbill register int n; 28133Sbill 28233Sbill p = NULL; 28333Sbill /* 28433Sbill * First, just locate a slot for a process 28533Sbill * and copy the useful info from this process into it. 28633Sbill * The panic "cannot happen" because fork has already 28733Sbill * checked for the existence of a slot. 28833Sbill */ 28933Sbill retry: 29033Sbill mpid++; 29133Sbill if(mpid >= 30000) { 29233Sbill mpid = 0; 29333Sbill goto retry; 29433Sbill } 29533Sbill for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 29633Sbill if(rpp->p_stat == NULL && p==NULL) 29733Sbill p = rpp; 29833Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 29933Sbill goto retry; 30033Sbill } 30133Sbill if ((rpp = p)==NULL) 30233Sbill panic("no procs"); 30333Sbill 30433Sbill /* 30533Sbill * make proc entry for new proc 30633Sbill */ 30733Sbill 30833Sbill rip = u.u_procp; 30933Sbill rpp->p_stat = SIDL; 31033Sbill rpp->p_clktim = 0; 311913Sbill rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG)); 31233Sbill if (isvfork) { 31333Sbill rpp->p_flag |= SVFORK; 31433Sbill rpp->p_ndx = rip->p_ndx; 31533Sbill } else 31633Sbill rpp->p_ndx = rpp - proc; 31733Sbill rpp->p_uid = rip->p_uid; 31833Sbill rpp->p_pgrp = rip->p_pgrp; 31933Sbill rpp->p_nice = rip->p_nice; 32033Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 32133Sbill rpp->p_pid = mpid; 32233Sbill rpp->p_ppid = rip->p_pid; 323181Sbill rpp->p_pptr = rip; 32433Sbill rpp->p_time = 0; 32533Sbill rpp->p_cpu = 0; 326181Sbill rpp->p_siga0 = rip->p_siga0; 327181Sbill rpp->p_siga1 = rip->p_siga1; 328181Sbill /* take along any pending signals, like stops? */ 32933Sbill if (isvfork) { 33033Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 33133Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 33233Sbill forkstat.cntvfork++; 33333Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 33433Sbill } else { 33533Sbill rpp->p_tsize = rip->p_tsize; 33633Sbill rpp->p_dsize = rip->p_dsize; 33733Sbill rpp->p_ssize = rip->p_ssize; 33833Sbill rpp->p_szpt = rip->p_szpt; 33933Sbill forkstat.cntfork++; 34033Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 34133Sbill } 34233Sbill rpp->p_rssize = 0; 34333Sbill rpp->p_wchan = 0; 34433Sbill rpp->p_slptime = 0; 345*1400Sbill rpp->p_pctcpu = 0; 346*1400Sbill rpp->p_cpticks = 0; 34733Sbill n = PIDHASH(rpp->p_pid); 34833Sbill p->p_idhash = pidhash[n]; 34933Sbill pidhash[n] = rpp - proc; 35033Sbill 35133Sbill /* 35233Sbill * make duplicate entries 35333Sbill * where needed 35433Sbill */ 35533Sbill 35633Sbill multprog++; 35733Sbill 35833Sbill for(n=0; n<NOFILE; n++) 35933Sbill if(u.u_ofile[n] != NULL) { 36033Sbill u.u_ofile[n]->f_count++; 36133Sbill if(!isvfork && u.u_vrpages[n]) 36233Sbill u.u_ofile[n]->f_inode->i_vfdcnt++; 36333Sbill } 36433Sbill 36533Sbill u.u_cdir->i_count++; 36633Sbill if (u.u_rdir) 36733Sbill u.u_rdir->i_count++; 36833Sbill /* 36933Sbill * Partially simulate the environment 37033Sbill * of the new process so that when it is actually 37133Sbill * created (by copying) it will look right. 37233Sbill */ 37333Sbill 37433Sbill rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 37533Sbill 37633Sbill if (procdup(rpp, isvfork)) 37733Sbill return (1); 37833Sbill 37933Sbill spl6(); 38033Sbill rpp->p_stat = SRUN; 38133Sbill setrq(rpp); 38233Sbill spl0(); 38388Sbill /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 38433Sbill /* rpp->p_flag |= SSWAP; */ 38533Sbill rip->p_flag &= ~SKEEP; 38633Sbill if (isvfork) { 38733Sbill u.u_procp->p_xlink = rpp; 38833Sbill u.u_procp->p_flag |= SNOVM; 38933Sbill while (rpp->p_flag & SVFORK) 39033Sbill sleep((caddr_t)rpp, PZERO - 1); 39133Sbill if ((rpp->p_flag & SLOAD) == 0) 39233Sbill panic("newproc vfork"); 39333Sbill uaccess(rpp, Vfmap, &vfutl); 39433Sbill u.u_procp->p_xlink = 0; 39533Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 39633Sbill for (n = 0; n < NOFILE; n++) 39733Sbill if (vfutl.u_vrpages[n]) { 39833Sbill if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 39933Sbill if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 40033Sbill panic("newproc i_vfdcnt"); 40133Sbill vfutl.u_vrpages[n] = 0; 40233Sbill } 40333Sbill u.u_procp->p_flag &= ~SNOVM; 40433Sbill rpp->p_ndx = rpp - proc; 40533Sbill rpp->p_flag |= SVFDONE; 40633Sbill wakeup((caddr_t)rpp); 40733Sbill } 40833Sbill return (0); 40933Sbill } 410