1*102Sbill /* kern_synch.c 3.5 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; 5133Sbill VOID spl0(); 5233Sbill goto psig; 5333Sbill } 5433Sbill 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 { 6333Sbill 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; 97*102Sbill 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; 104100Sbill if ((sec = pp->p_clktim-seconds) < 0) 105100Sbill sec = 0; 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)); 120100Sbill pp->p_clktim += sec; 121100Sbill splx(n); 122100Sbill return(rval); 123100Sbill } 124100Sbill 125100Sbill /* 12633Sbill * Wake up all processes sleeping on chan. 12733Sbill */ 12833Sbill wakeup(chan) 12933Sbill register caddr_t chan; 13033Sbill { 13133Sbill register struct proc *p, *q; 13233Sbill register i; 13333Sbill int s; 13433Sbill 13533Sbill s = spl6(); 13633Sbill i = HASH(chan); 13733Sbill restart: 13833Sbill p = slpque[i]; 13933Sbill q = NULL; 14033Sbill while(p != NULL) { 14133Sbill if (p->p_rlink || p->p_stat != SSLEEP) 14233Sbill panic("wakeup"); 14333Sbill if (p->p_wchan==chan && p->p_stat!=SZOMB) { 14433Sbill if (q == NULL) 14533Sbill slpque[i] = p->p_link; 14633Sbill else 14733Sbill q->p_link = p->p_link; 14833Sbill p->p_wchan = 0; 14933Sbill p->p_slptime = 0; 15033Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 15133Sbill p->p_stat = SRUN; 15233Sbill if (p->p_flag & SLOAD) { 15333Sbill #ifndef FASTVAX 15433Sbill p->p_link = runq; 15533Sbill runq = p->p_link; 15633Sbill #else 15733Sbill setrq(p); 15833Sbill #endif 15933Sbill } 16033Sbill if(p->p_pri < curpri) 16133Sbill runrun++; 16233Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 16333Sbill runout = 0; 16433Sbill wakeup((caddr_t)&runout); 16533Sbill } 16633Sbill /* END INLINE EXPANSION */ 16733Sbill goto restart; 16833Sbill } 16933Sbill q = p; 17033Sbill p = p->p_link; 17133Sbill } 17233Sbill splx(s); 17333Sbill } 17433Sbill 17533Sbill #ifdef FASTVAX 17633Sbill /* 17733Sbill * Initialize the (doubly-linked) run queues 17833Sbill * to be empty. 17933Sbill */ 18033Sbill rqinit() 18133Sbill { 18233Sbill register int i; 18333Sbill 18433Sbill for (i = 0; i < NQS; i++) 18533Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 18633Sbill } 18733Sbill #endif 18833Sbill 18933Sbill /* 19033Sbill * Set the process running; 19133Sbill * arrange for it to be swapped in if necessary. 19233Sbill */ 19333Sbill setrun(p) 19433Sbill register struct proc *p; 19533Sbill { 19633Sbill register caddr_t w; 19733Sbill register s; 19833Sbill 19933Sbill s = spl6(); 20033Sbill switch (p->p_stat) { 20133Sbill 20233Sbill case 0: 20333Sbill case SWAIT: 20433Sbill case SRUN: 20533Sbill case SZOMB: 20633Sbill default: 20733Sbill panic("setrun"); 20833Sbill 20933Sbill case SSLEEP: 21033Sbill if (w = p->p_wchan) { 21133Sbill wakeup(w); 21233Sbill splx(s); 21333Sbill return; 21433Sbill } 21533Sbill break; 21633Sbill 21733Sbill case SIDL: 21833Sbill case SSTOP: 21933Sbill break; 22033Sbill } 22133Sbill p->p_stat = SRUN; 22233Sbill if (p->p_flag & SLOAD) 22333Sbill setrq(p); 22433Sbill splx(s); 22533Sbill if(p->p_pri < curpri) 22633Sbill runrun++; 22733Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 22833Sbill runout = 0; 22933Sbill wakeup((caddr_t)&runout); 23033Sbill } 23133Sbill } 23233Sbill 23333Sbill /* 23433Sbill * Set user priority. 23533Sbill * The rescheduling flag (runrun) 23633Sbill * is set if the priority is better 23733Sbill * than the currently running process. 23833Sbill */ 23933Sbill setpri(pp) 24033Sbill register struct proc *pp; 24133Sbill { 24233Sbill register p; 24333Sbill 24433Sbill p = (pp->p_cpu & 0377)/16; 24533Sbill p += PUSER + pp->p_nice - NZERO; 24633Sbill if(p > 127) 24733Sbill p = 127; 24833Sbill if(p < curpri) 24933Sbill runrun++; 25033Sbill pp->p_usrpri = p; 25133Sbill return(p); 25233Sbill } 25333Sbill 25433Sbill /* 25533Sbill * Create a new process-- the internal version of 25633Sbill * sys fork. 25733Sbill * It returns 1 in the new process, 0 in the old. 25833Sbill */ 25933Sbill newproc(isvfork) 26033Sbill { 26133Sbill register struct proc *p; 26233Sbill register struct proc *rpp, *rip; 26333Sbill register int n; 26433Sbill 26533Sbill p = NULL; 26633Sbill /* 26733Sbill * First, just locate a slot for a process 26833Sbill * and copy the useful info from this process into it. 26933Sbill * The panic "cannot happen" because fork has already 27033Sbill * checked for the existence of a slot. 27133Sbill */ 27233Sbill retry: 27333Sbill mpid++; 27433Sbill if(mpid >= 30000) { 27533Sbill mpid = 0; 27633Sbill goto retry; 27733Sbill } 27833Sbill for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 27933Sbill if(rpp->p_stat == NULL && p==NULL) 28033Sbill p = rpp; 28133Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 28233Sbill goto retry; 28333Sbill } 28433Sbill if ((rpp = p)==NULL) 28533Sbill panic("no procs"); 28633Sbill 28733Sbill /* 28833Sbill * make proc entry for new proc 28933Sbill */ 29033Sbill 29133Sbill rip = u.u_procp; 29233Sbill rpp->p_stat = SIDL; 29333Sbill rpp->p_clktim = 0; 29433Sbill rpp->p_flag = SLOAD | (rip->p_flag & SPAGI); 29533Sbill if (isvfork) { 29633Sbill rpp->p_flag |= SVFORK; 29733Sbill rpp->p_ndx = rip->p_ndx; 29833Sbill } else 29933Sbill rpp->p_ndx = rpp - proc; 30033Sbill rpp->p_uid = rip->p_uid; 30133Sbill rpp->p_pgrp = rip->p_pgrp; 30233Sbill rpp->p_nice = rip->p_nice; 30333Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 30433Sbill rpp->p_pid = mpid; 30533Sbill rpp->p_ppid = rip->p_pid; 30633Sbill rpp->p_time = 0; 30733Sbill rpp->p_cpu = 0; 30833Sbill if (isvfork) { 30933Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 31033Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 31133Sbill forkstat.cntvfork++; 31233Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 31333Sbill } else { 31433Sbill rpp->p_tsize = rip->p_tsize; 31533Sbill rpp->p_dsize = rip->p_dsize; 31633Sbill rpp->p_ssize = rip->p_ssize; 31733Sbill rpp->p_szpt = rip->p_szpt; 31833Sbill forkstat.cntfork++; 31933Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 32033Sbill } 32133Sbill rpp->p_rssize = 0; 32233Sbill rpp->p_wchan = 0; 32333Sbill rpp->p_slptime = 0; 32433Sbill rpp->p_aveflt = rip->p_aveflt; 32533Sbill rate.v_pgin += rip->p_aveflt; 32633Sbill rpp->p_faults = 0; 32733Sbill n = PIDHASH(rpp->p_pid); 32833Sbill p->p_idhash = pidhash[n]; 32933Sbill pidhash[n] = rpp - proc; 33033Sbill 33133Sbill /* 33233Sbill * make duplicate entries 33333Sbill * where needed 33433Sbill */ 33533Sbill 33633Sbill multprog++; 33733Sbill 33833Sbill for(n=0; n<NOFILE; n++) 33933Sbill if(u.u_ofile[n] != NULL) { 34033Sbill u.u_ofile[n]->f_count++; 34133Sbill if(!isvfork && u.u_vrpages[n]) 34233Sbill u.u_ofile[n]->f_inode->i_vfdcnt++; 34333Sbill } 34433Sbill 34533Sbill u.u_cdir->i_count++; 34633Sbill if (u.u_rdir) 34733Sbill u.u_rdir->i_count++; 34833Sbill /* 34933Sbill * Partially simulate the environment 35033Sbill * of the new process so that when it is actually 35133Sbill * created (by copying) it will look right. 35233Sbill */ 35333Sbill 35433Sbill rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 35533Sbill 35633Sbill if (procdup(rpp, isvfork)) 35733Sbill return (1); 35833Sbill 35933Sbill spl6(); 36033Sbill rpp->p_stat = SRUN; 36133Sbill setrq(rpp); 36233Sbill spl0(); 36388Sbill /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 36433Sbill /* rpp->p_flag |= SSWAP; */ 36533Sbill rip->p_flag &= ~SKEEP; 36633Sbill if (isvfork) { 36733Sbill u.u_procp->p_xlink = rpp; 36833Sbill u.u_procp->p_flag |= SNOVM; 36933Sbill while (rpp->p_flag & SVFORK) 37033Sbill sleep((caddr_t)rpp, PZERO - 1); 37133Sbill if ((rpp->p_flag & SLOAD) == 0) 37233Sbill panic("newproc vfork"); 37333Sbill uaccess(rpp, Vfmap, &vfutl); 37433Sbill u.u_procp->p_xlink = 0; 37533Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 37633Sbill for (n = 0; n < NOFILE; n++) 37733Sbill if (vfutl.u_vrpages[n]) { 37833Sbill if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 37933Sbill if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 38033Sbill panic("newproc i_vfdcnt"); 38133Sbill vfutl.u_vrpages[n] = 0; 38233Sbill } 38333Sbill u.u_procp->p_flag &= ~SNOVM; 38433Sbill rpp->p_ndx = rpp - proc; 38533Sbill rpp->p_flag |= SVFDONE; 38633Sbill wakeup((caddr_t)rpp); 38733Sbill } 38833Sbill return (0); 38933Sbill } 390