1*131Sbill /* kern_synch.c 3.7 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" 1233Sbill 1333Sbill 1433Sbill #define SQSIZE 0100 /* Must be power of 2 */ 1533Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 1633Sbill struct proc *slpque[SQSIZE]; 1733Sbill 1833Sbill /* 1933Sbill * Give up the processor till a wakeup occurs 2033Sbill * on chan, at which time the process 2133Sbill * enters the scheduling queue at priority pri. 2233Sbill * The most important effect of pri is that when 2333Sbill * pri<=PZERO a signal cannot disturb the sleep; 2433Sbill * if pri>PZERO signals will be processed. 2533Sbill * Callers of this routine must be prepared for 2633Sbill * premature return, and check that the reason for 2733Sbill * sleeping has gone away. 2833Sbill */ 2933Sbill sleep(chan, pri) 3033Sbill caddr_t chan; 3133Sbill { 3233Sbill register struct proc *rp; 3333Sbill register s, h; 3433Sbill 3533Sbill rp = u.u_procp; 3633Sbill s = spl6(); 3733Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 3833Sbill panic("sleep"); 3933Sbill rp->p_stat = SSLEEP; 4033Sbill rp->p_wchan = chan; 4133Sbill rp->p_slptime = 0; 4233Sbill rp->p_pri = pri; 4333Sbill h = HASH(chan); 4433Sbill rp->p_link = slpque[h]; 4533Sbill slpque[h] = rp; 4633Sbill if(pri > PZERO) { 4733Sbill if(rp->p_sig && issig()) { 4833Sbill rp->p_wchan = 0; 4933Sbill rp->p_stat = SRUN; 5033Sbill slpque[h] = rp->p_link; 51*131Sbill (void) spl0(); 5233Sbill goto psig; 5333Sbill } 54*131Sbill (void) spl0(); 5533Sbill if(runin != 0) { 5633Sbill runin = 0; 5733Sbill wakeup((caddr_t)&runin); 5833Sbill } 5933Sbill swtch(); 6033Sbill if(rp->p_sig && issig()) 6133Sbill goto psig; 6233Sbill } else { 63*131Sbill (void) spl0(); 6433Sbill swtch(); 6533Sbill } 6633Sbill splx(s); 6733Sbill return; 6833Sbill 6933Sbill /* 7033Sbill * If priority was low (>PZERO) and 7133Sbill * there has been a signal, 7233Sbill * execute non-local goto to 7333Sbill * the qsav location. 7433Sbill * (see trap1/trap.c) 7533Sbill */ 7633Sbill psig: 7733Sbill longjmp(u.u_qsav); 7833Sbill /*NOTREACHED*/ 7933Sbill } 8033Sbill 8133Sbill /* 82100Sbill * Sleep on chan at pri. 83100Sbill * Return in no more than the indicated number of seconds. 84100Sbill * (If seconds==0, no timeout implied) 85100Sbill * Return TS_OK if chan was awakened normally 86100Sbill * TS_TIME if timeout occurred 87100Sbill * TS_SIG if asynchronous signal occurred 88100Sbill */ 89100Sbill tsleep(chan, pri, seconds) 90100Sbill caddr_t chan; 91100Sbill { 92100Sbill label_t lqsav; 93100Sbill register struct proc *pp; 94100Sbill register sec, n, rval; 95100Sbill 96100Sbill pp = u.u_procp; 97102Sbill n = spl7(); 98100Sbill sec = 0; 99100Sbill rval = 0; 100100Sbill if (pp->p_clktim && pp->p_clktim<seconds) 101100Sbill seconds = 0; 102100Sbill if (seconds) { 103100Sbill pp->p_flag |= STIMO; 104103Sbill sec = pp->p_clktim-seconds; 105100Sbill pp->p_clktim = seconds; 106100Sbill } 107100Sbill bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 108100Sbill if (setjmp(u.u_qsav)) 109100Sbill rval = TS_SIG; 110100Sbill else { 111100Sbill sleep(chan, pri); 112100Sbill if ((pp->p_flag&STIMO)==0 && seconds) 113100Sbill rval = TS_TIME; 114100Sbill else 115100Sbill rval = TS_OK; 116100Sbill } 117100Sbill pp->p_flag &= ~STIMO; 118100Sbill bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 119103Sbill if (sec > 0) 120103Sbill pp->p_clktim += sec; 121103Sbill else 122103Sbill pp->p_clktim = 0; 123100Sbill splx(n); 124100Sbill return(rval); 125100Sbill } 126100Sbill 127100Sbill /* 12833Sbill * Wake up all processes sleeping on chan. 12933Sbill */ 13033Sbill wakeup(chan) 13133Sbill register caddr_t chan; 13233Sbill { 13333Sbill register struct proc *p, *q; 13433Sbill register i; 13533Sbill int s; 13633Sbill 13733Sbill s = spl6(); 13833Sbill i = HASH(chan); 13933Sbill restart: 14033Sbill p = slpque[i]; 14133Sbill q = NULL; 14233Sbill while(p != NULL) { 14333Sbill if (p->p_rlink || p->p_stat != SSLEEP) 14433Sbill panic("wakeup"); 14533Sbill if (p->p_wchan==chan && p->p_stat!=SZOMB) { 14633Sbill if (q == NULL) 14733Sbill slpque[i] = p->p_link; 14833Sbill else 14933Sbill q->p_link = p->p_link; 15033Sbill p->p_wchan = 0; 15133Sbill p->p_slptime = 0; 15233Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 15333Sbill p->p_stat = SRUN; 15433Sbill if (p->p_flag & SLOAD) { 15533Sbill #ifndef FASTVAX 15633Sbill p->p_link = runq; 15733Sbill runq = p->p_link; 15833Sbill #else 15933Sbill setrq(p); 16033Sbill #endif 16133Sbill } 16233Sbill if(p->p_pri < curpri) 16333Sbill runrun++; 16433Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 16533Sbill runout = 0; 16633Sbill wakeup((caddr_t)&runout); 16733Sbill } 16833Sbill /* END INLINE EXPANSION */ 16933Sbill goto restart; 17033Sbill } 17133Sbill q = p; 17233Sbill p = p->p_link; 17333Sbill } 17433Sbill splx(s); 17533Sbill } 17633Sbill 17733Sbill #ifdef FASTVAX 17833Sbill /* 17933Sbill * Initialize the (doubly-linked) run queues 18033Sbill * to be empty. 18133Sbill */ 18233Sbill rqinit() 18333Sbill { 18433Sbill register int i; 18533Sbill 18633Sbill for (i = 0; i < NQS; i++) 18733Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 18833Sbill } 18933Sbill #endif 19033Sbill 19133Sbill /* 19233Sbill * Set the process running; 19333Sbill * arrange for it to be swapped in if necessary. 19433Sbill */ 19533Sbill setrun(p) 19633Sbill register struct proc *p; 19733Sbill { 19833Sbill register caddr_t w; 19933Sbill register s; 20033Sbill 20133Sbill s = spl6(); 20233Sbill switch (p->p_stat) { 20333Sbill 20433Sbill case 0: 20533Sbill case SWAIT: 20633Sbill case SRUN: 20733Sbill case SZOMB: 20833Sbill default: 20933Sbill panic("setrun"); 21033Sbill 21133Sbill case SSLEEP: 21233Sbill if (w = p->p_wchan) { 21333Sbill wakeup(w); 21433Sbill splx(s); 21533Sbill return; 21633Sbill } 21733Sbill break; 21833Sbill 21933Sbill case SIDL: 22033Sbill case SSTOP: 22133Sbill break; 22233Sbill } 22333Sbill p->p_stat = SRUN; 22433Sbill if (p->p_flag & SLOAD) 22533Sbill setrq(p); 22633Sbill splx(s); 22733Sbill if(p->p_pri < curpri) 22833Sbill runrun++; 22933Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 23033Sbill runout = 0; 23133Sbill wakeup((caddr_t)&runout); 23233Sbill } 23333Sbill } 23433Sbill 23533Sbill /* 23633Sbill * Set user priority. 23733Sbill * The rescheduling flag (runrun) 23833Sbill * is set if the priority is better 23933Sbill * than the currently running process. 24033Sbill */ 24133Sbill setpri(pp) 24233Sbill register struct proc *pp; 24333Sbill { 24433Sbill register p; 24533Sbill 24633Sbill p = (pp->p_cpu & 0377)/16; 24733Sbill p += PUSER + pp->p_nice - NZERO; 24833Sbill if(p > 127) 24933Sbill p = 127; 25033Sbill if(p < curpri) 25133Sbill runrun++; 25233Sbill pp->p_usrpri = p; 25333Sbill return(p); 25433Sbill } 25533Sbill 25633Sbill /* 25733Sbill * Create a new process-- the internal version of 25833Sbill * sys fork. 25933Sbill * It returns 1 in the new process, 0 in the old. 26033Sbill */ 26133Sbill newproc(isvfork) 26233Sbill { 26333Sbill register struct proc *p; 26433Sbill register struct proc *rpp, *rip; 26533Sbill register int n; 26633Sbill 26733Sbill p = NULL; 26833Sbill /* 26933Sbill * First, just locate a slot for a process 27033Sbill * and copy the useful info from this process into it. 27133Sbill * The panic "cannot happen" because fork has already 27233Sbill * checked for the existence of a slot. 27333Sbill */ 27433Sbill retry: 27533Sbill mpid++; 27633Sbill if(mpid >= 30000) { 27733Sbill mpid = 0; 27833Sbill goto retry; 27933Sbill } 28033Sbill for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 28133Sbill if(rpp->p_stat == NULL && p==NULL) 28233Sbill p = rpp; 28333Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 28433Sbill goto retry; 28533Sbill } 28633Sbill if ((rpp = p)==NULL) 28733Sbill panic("no procs"); 28833Sbill 28933Sbill /* 29033Sbill * make proc entry for new proc 29133Sbill */ 29233Sbill 29333Sbill rip = u.u_procp; 29433Sbill rpp->p_stat = SIDL; 29533Sbill rpp->p_clktim = 0; 29633Sbill rpp->p_flag = SLOAD | (rip->p_flag & SPAGI); 29733Sbill if (isvfork) { 29833Sbill rpp->p_flag |= SVFORK; 29933Sbill rpp->p_ndx = rip->p_ndx; 30033Sbill } else 30133Sbill rpp->p_ndx = rpp - proc; 30233Sbill rpp->p_uid = rip->p_uid; 30333Sbill rpp->p_pgrp = rip->p_pgrp; 30433Sbill rpp->p_nice = rip->p_nice; 30533Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 30633Sbill rpp->p_pid = mpid; 30733Sbill rpp->p_ppid = rip->p_pid; 30833Sbill rpp->p_time = 0; 30933Sbill rpp->p_cpu = 0; 31033Sbill if (isvfork) { 31133Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 31233Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 31333Sbill forkstat.cntvfork++; 31433Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 31533Sbill } else { 31633Sbill rpp->p_tsize = rip->p_tsize; 31733Sbill rpp->p_dsize = rip->p_dsize; 31833Sbill rpp->p_ssize = rip->p_ssize; 31933Sbill rpp->p_szpt = rip->p_szpt; 32033Sbill forkstat.cntfork++; 32133Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 32233Sbill } 32333Sbill rpp->p_rssize = 0; 32433Sbill rpp->p_wchan = 0; 32533Sbill rpp->p_slptime = 0; 32633Sbill rpp->p_aveflt = rip->p_aveflt; 32733Sbill rate.v_pgin += rip->p_aveflt; 32833Sbill rpp->p_faults = 0; 32933Sbill n = PIDHASH(rpp->p_pid); 33033Sbill p->p_idhash = pidhash[n]; 33133Sbill pidhash[n] = rpp - proc; 33233Sbill 33333Sbill /* 33433Sbill * make duplicate entries 33533Sbill * where needed 33633Sbill */ 33733Sbill 33833Sbill multprog++; 33933Sbill 34033Sbill for(n=0; n<NOFILE; n++) 34133Sbill if(u.u_ofile[n] != NULL) { 34233Sbill u.u_ofile[n]->f_count++; 34333Sbill if(!isvfork && u.u_vrpages[n]) 34433Sbill u.u_ofile[n]->f_inode->i_vfdcnt++; 34533Sbill } 34633Sbill 34733Sbill u.u_cdir->i_count++; 34833Sbill if (u.u_rdir) 34933Sbill u.u_rdir->i_count++; 35033Sbill /* 35133Sbill * Partially simulate the environment 35233Sbill * of the new process so that when it is actually 35333Sbill * created (by copying) it will look right. 35433Sbill */ 35533Sbill 35633Sbill rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 35733Sbill 35833Sbill if (procdup(rpp, isvfork)) 35933Sbill return (1); 36033Sbill 36133Sbill spl6(); 36233Sbill rpp->p_stat = SRUN; 36333Sbill setrq(rpp); 36433Sbill spl0(); 36588Sbill /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 36633Sbill /* rpp->p_flag |= SSWAP; */ 36733Sbill rip->p_flag &= ~SKEEP; 36833Sbill if (isvfork) { 36933Sbill u.u_procp->p_xlink = rpp; 37033Sbill u.u_procp->p_flag |= SNOVM; 37133Sbill while (rpp->p_flag & SVFORK) 37233Sbill sleep((caddr_t)rpp, PZERO - 1); 37333Sbill if ((rpp->p_flag & SLOAD) == 0) 37433Sbill panic("newproc vfork"); 37533Sbill uaccess(rpp, Vfmap, &vfutl); 37633Sbill u.u_procp->p_xlink = 0; 37733Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 37833Sbill for (n = 0; n < NOFILE; n++) 37933Sbill if (vfutl.u_vrpages[n]) { 38033Sbill if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 38133Sbill if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 38233Sbill panic("newproc i_vfdcnt"); 38333Sbill vfutl.u_vrpages[n] = 0; 38433Sbill } 38533Sbill u.u_procp->p_flag &= ~SNOVM; 38633Sbill rpp->p_ndx = rpp - proc; 38733Sbill rpp->p_flag |= SVFDONE; 38833Sbill wakeup((caddr_t)rpp); 38933Sbill } 39033Sbill return (0); 39133Sbill } 392