1*181Sbill /* kern_synch.c 3.8 10/14/12 */ 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" 12*181Sbill #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 { 3333Sbill register struct proc *rp; 3433Sbill register s, h; 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_stat = SSLEEP; 4133Sbill rp->p_wchan = chan; 4233Sbill rp->p_slptime = 0; 4333Sbill rp->p_pri = pri; 4433Sbill h = HASH(chan); 4533Sbill rp->p_link = slpque[h]; 4633Sbill slpque[h] = rp; 4733Sbill if(pri > PZERO) { 48*181Sbill if(ISSIG(rp)) { 4933Sbill rp->p_wchan = 0; 5033Sbill rp->p_stat = SRUN; 5133Sbill slpque[h] = rp->p_link; 52131Sbill (void) spl0(); 5333Sbill goto psig; 5433Sbill } 55131Sbill (void) spl0(); 5633Sbill if(runin != 0) { 5733Sbill runin = 0; 5833Sbill wakeup((caddr_t)&runin); 5933Sbill } 6033Sbill swtch(); 61*181Sbill if(ISSIG(rp)) 6233Sbill goto psig; 6333Sbill } else { 64131Sbill (void) spl0(); 6533Sbill swtch(); 6633Sbill } 6733Sbill splx(s); 6833Sbill return; 6933Sbill 7033Sbill /* 7133Sbill * If priority was low (>PZERO) and 7233Sbill * there has been a signal, 7333Sbill * execute non-local goto to 7433Sbill * the qsav location. 7533Sbill * (see trap1/trap.c) 7633Sbill */ 7733Sbill psig: 7833Sbill longjmp(u.u_qsav); 7933Sbill /*NOTREACHED*/ 8033Sbill } 8133Sbill 8233Sbill /* 83100Sbill * Sleep on chan at pri. 84100Sbill * Return in no more than the indicated number of seconds. 85100Sbill * (If seconds==0, no timeout implied) 86100Sbill * Return TS_OK if chan was awakened normally 87100Sbill * TS_TIME if timeout occurred 88100Sbill * TS_SIG if asynchronous signal occurred 89100Sbill */ 90100Sbill tsleep(chan, pri, seconds) 91100Sbill caddr_t chan; 92100Sbill { 93100Sbill label_t lqsav; 94100Sbill register struct proc *pp; 95100Sbill register sec, n, rval; 96100Sbill 97100Sbill pp = u.u_procp; 98102Sbill n = spl7(); 99100Sbill sec = 0; 100100Sbill rval = 0; 101100Sbill if (pp->p_clktim && pp->p_clktim<seconds) 102100Sbill seconds = 0; 103100Sbill if (seconds) { 104100Sbill pp->p_flag |= STIMO; 105103Sbill sec = pp->p_clktim-seconds; 106100Sbill pp->p_clktim = seconds; 107100Sbill } 108100Sbill bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 109100Sbill if (setjmp(u.u_qsav)) 110100Sbill rval = TS_SIG; 111100Sbill else { 112100Sbill sleep(chan, pri); 113100Sbill if ((pp->p_flag&STIMO)==0 && seconds) 114100Sbill rval = TS_TIME; 115100Sbill else 116100Sbill rval = TS_OK; 117100Sbill } 118100Sbill pp->p_flag &= ~STIMO; 119100Sbill bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 120103Sbill if (sec > 0) 121103Sbill pp->p_clktim += sec; 122103Sbill else 123103Sbill pp->p_clktim = 0; 124100Sbill splx(n); 125100Sbill return(rval); 126100Sbill } 127100Sbill 128100Sbill /* 129*181Sbill * Remove a process from its wait queue 130*181Sbill */ 131*181Sbill unsleep(p) 132*181Sbill register struct proc *p; 133*181Sbill { 134*181Sbill register struct proc **hp; 135*181Sbill register s; 136*181Sbill 137*181Sbill s = spl6(); 138*181Sbill if (p->p_wchan) { 139*181Sbill hp = &slpque[HASH(p->p_wchan)]; 140*181Sbill while (*hp != p) 141*181Sbill hp = &(*hp)->p_link; 142*181Sbill *hp = p->p_link; 143*181Sbill p->p_wchan = 0; 144*181Sbill } 145*181Sbill splx(s); 146*181Sbill } 147*181Sbill 148*181Sbill /* 14933Sbill * Wake up all processes sleeping on chan. 15033Sbill */ 15133Sbill wakeup(chan) 15233Sbill register caddr_t chan; 15333Sbill { 15433Sbill register struct proc *p, *q; 15533Sbill register i; 15633Sbill int s; 15733Sbill 15833Sbill s = spl6(); 15933Sbill i = HASH(chan); 16033Sbill restart: 16133Sbill p = slpque[i]; 16233Sbill q = NULL; 16333Sbill while(p != NULL) { 164*181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 16533Sbill panic("wakeup"); 16633Sbill if (p->p_wchan==chan && p->p_stat!=SZOMB) { 16733Sbill if (q == NULL) 16833Sbill slpque[i] = p->p_link; 16933Sbill else 17033Sbill q->p_link = p->p_link; 17133Sbill p->p_wchan = 0; 17233Sbill p->p_slptime = 0; 173*181Sbill if (p->p_stat == SSLEEP) { 174*181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 175*181Sbill p->p_stat = SRUN; 176*181Sbill if (p->p_flag & SLOAD) { 17733Sbill #ifndef FASTVAX 178*181Sbill p->p_link = runq; 179*181Sbill runq = p->p_link; 18033Sbill #else 181*181Sbill setrq(p); 18233Sbill #endif 183*181Sbill } 184*181Sbill if(p->p_pri < curpri) 185*181Sbill runrun++; 186*181Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 187*181Sbill runout = 0; 188*181Sbill wakeup((caddr_t)&runout); 189*181Sbill } 190*181Sbill /* END INLINE EXPANSION */ 19133Sbill } 19233Sbill goto restart; 19333Sbill } 19433Sbill q = p; 19533Sbill p = p->p_link; 19633Sbill } 19733Sbill splx(s); 19833Sbill } 19933Sbill 20033Sbill #ifdef FASTVAX 20133Sbill /* 20233Sbill * Initialize the (doubly-linked) run queues 20333Sbill * to be empty. 20433Sbill */ 20533Sbill rqinit() 20633Sbill { 20733Sbill register int i; 20833Sbill 20933Sbill for (i = 0; i < NQS; i++) 21033Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 21133Sbill } 21233Sbill #endif 21333Sbill 21433Sbill /* 21533Sbill * Set the process running; 21633Sbill * arrange for it to be swapped in if necessary. 21733Sbill */ 21833Sbill setrun(p) 21933Sbill register struct proc *p; 22033Sbill { 22133Sbill register caddr_t w; 22233Sbill register s; 22333Sbill 22433Sbill s = spl6(); 22533Sbill switch (p->p_stat) { 22633Sbill 22733Sbill case 0: 22833Sbill case SWAIT: 22933Sbill case SRUN: 23033Sbill case SZOMB: 23133Sbill default: 23233Sbill panic("setrun"); 23333Sbill 23433Sbill case SSLEEP: 235*181Sbill unsleep(p); /* e.g. when sending signals */ 23633Sbill break; 23733Sbill 23833Sbill case SIDL: 23933Sbill case SSTOP: 24033Sbill break; 24133Sbill } 24233Sbill p->p_stat = SRUN; 24333Sbill if (p->p_flag & SLOAD) 24433Sbill setrq(p); 24533Sbill splx(s); 24633Sbill if(p->p_pri < curpri) 24733Sbill runrun++; 24833Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 24933Sbill runout = 0; 25033Sbill wakeup((caddr_t)&runout); 25133Sbill } 25233Sbill } 25333Sbill 25433Sbill /* 25533Sbill * Set user priority. 25633Sbill * The rescheduling flag (runrun) 25733Sbill * is set if the priority is better 25833Sbill * than the currently running process. 25933Sbill */ 26033Sbill setpri(pp) 26133Sbill register struct proc *pp; 26233Sbill { 26333Sbill register p; 26433Sbill 26533Sbill p = (pp->p_cpu & 0377)/16; 26633Sbill p += PUSER + pp->p_nice - NZERO; 26733Sbill if(p > 127) 26833Sbill p = 127; 26933Sbill if(p < curpri) 27033Sbill runrun++; 27133Sbill pp->p_usrpri = p; 27233Sbill return(p); 27333Sbill } 27433Sbill 27533Sbill /* 27633Sbill * Create a new process-- the internal version of 27733Sbill * sys fork. 27833Sbill * It returns 1 in the new process, 0 in the old. 27933Sbill */ 28033Sbill newproc(isvfork) 28133Sbill { 28233Sbill register struct proc *p; 28333Sbill register struct proc *rpp, *rip; 28433Sbill register int n; 28533Sbill 28633Sbill p = NULL; 28733Sbill /* 28833Sbill * First, just locate a slot for a process 28933Sbill * and copy the useful info from this process into it. 29033Sbill * The panic "cannot happen" because fork has already 29133Sbill * checked for the existence of a slot. 29233Sbill */ 29333Sbill retry: 29433Sbill mpid++; 29533Sbill if(mpid >= 30000) { 29633Sbill mpid = 0; 29733Sbill goto retry; 29833Sbill } 29933Sbill for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 30033Sbill if(rpp->p_stat == NULL && p==NULL) 30133Sbill p = rpp; 30233Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 30333Sbill goto retry; 30433Sbill } 30533Sbill if ((rpp = p)==NULL) 30633Sbill panic("no procs"); 30733Sbill 30833Sbill /* 30933Sbill * make proc entry for new proc 31033Sbill */ 31133Sbill 31233Sbill rip = u.u_procp; 31333Sbill rpp->p_stat = SIDL; 31433Sbill rpp->p_clktim = 0; 31533Sbill rpp->p_flag = SLOAD | (rip->p_flag & SPAGI); 31633Sbill if (isvfork) { 31733Sbill rpp->p_flag |= SVFORK; 31833Sbill rpp->p_ndx = rip->p_ndx; 31933Sbill } else 32033Sbill rpp->p_ndx = rpp - proc; 32133Sbill rpp->p_uid = rip->p_uid; 32233Sbill rpp->p_pgrp = rip->p_pgrp; 32333Sbill rpp->p_nice = rip->p_nice; 32433Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 32533Sbill rpp->p_pid = mpid; 32633Sbill rpp->p_ppid = rip->p_pid; 327*181Sbill rpp->p_pptr = rip; 32833Sbill rpp->p_time = 0; 32933Sbill rpp->p_cpu = 0; 330*181Sbill rpp->p_siga0 = rip->p_siga0; 331*181Sbill rpp->p_siga1 = rip->p_siga1; 332*181Sbill /* take along any pending signals, like stops? */ 33333Sbill if (isvfork) { 33433Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 33533Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 33633Sbill forkstat.cntvfork++; 33733Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 33833Sbill } else { 33933Sbill rpp->p_tsize = rip->p_tsize; 34033Sbill rpp->p_dsize = rip->p_dsize; 34133Sbill rpp->p_ssize = rip->p_ssize; 34233Sbill rpp->p_szpt = rip->p_szpt; 34333Sbill forkstat.cntfork++; 34433Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 34533Sbill } 34633Sbill rpp->p_rssize = 0; 34733Sbill rpp->p_wchan = 0; 34833Sbill rpp->p_slptime = 0; 34933Sbill rpp->p_aveflt = rip->p_aveflt; 35033Sbill rate.v_pgin += rip->p_aveflt; 35133Sbill rpp->p_faults = 0; 35233Sbill n = PIDHASH(rpp->p_pid); 35333Sbill p->p_idhash = pidhash[n]; 35433Sbill pidhash[n] = rpp - proc; 35533Sbill 35633Sbill /* 35733Sbill * make duplicate entries 35833Sbill * where needed 35933Sbill */ 36033Sbill 36133Sbill multprog++; 36233Sbill 36333Sbill for(n=0; n<NOFILE; n++) 36433Sbill if(u.u_ofile[n] != NULL) { 36533Sbill u.u_ofile[n]->f_count++; 36633Sbill if(!isvfork && u.u_vrpages[n]) 36733Sbill u.u_ofile[n]->f_inode->i_vfdcnt++; 36833Sbill } 36933Sbill 37033Sbill u.u_cdir->i_count++; 37133Sbill if (u.u_rdir) 37233Sbill u.u_rdir->i_count++; 37333Sbill /* 37433Sbill * Partially simulate the environment 37533Sbill * of the new process so that when it is actually 37633Sbill * created (by copying) it will look right. 37733Sbill */ 37833Sbill 37933Sbill rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 38033Sbill 38133Sbill if (procdup(rpp, isvfork)) 38233Sbill return (1); 38333Sbill 38433Sbill spl6(); 38533Sbill rpp->p_stat = SRUN; 38633Sbill setrq(rpp); 38733Sbill spl0(); 38888Sbill /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 38933Sbill /* rpp->p_flag |= SSWAP; */ 39033Sbill rip->p_flag &= ~SKEEP; 39133Sbill if (isvfork) { 39233Sbill u.u_procp->p_xlink = rpp; 39333Sbill u.u_procp->p_flag |= SNOVM; 39433Sbill while (rpp->p_flag & SVFORK) 39533Sbill sleep((caddr_t)rpp, PZERO - 1); 39633Sbill if ((rpp->p_flag & SLOAD) == 0) 39733Sbill panic("newproc vfork"); 39833Sbill uaccess(rpp, Vfmap, &vfutl); 39933Sbill u.u_procp->p_xlink = 0; 40033Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 40133Sbill for (n = 0; n < NOFILE; n++) 40233Sbill if (vfutl.u_vrpages[n]) { 40333Sbill if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 40433Sbill if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 40533Sbill panic("newproc i_vfdcnt"); 40633Sbill vfutl.u_vrpages[n] = 0; 40733Sbill } 40833Sbill u.u_procp->p_flag &= ~SNOVM; 40933Sbill rpp->p_ndx = rpp - proc; 41033Sbill rpp->p_flag |= SVFDONE; 41133Sbill wakeup((caddr_t)rpp); 41233Sbill } 41333Sbill return (0); 41433Sbill } 415