1*2453Swnj /* kern_synch.c 4.6 02/16/81 */ 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" 132443Swnj #include "../h/mtpr.h" 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 swtch(); 59181Sbill if(ISSIG(rp)) 6033Sbill goto psig; 6133Sbill } else { 62207Sbill rp->p_stat = SSLEEP; 63131Sbill (void) spl0(); 6433Sbill swtch(); 6533Sbill } 66187Sbill out: 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 /* 129181Sbill * Remove a process from its wait queue 130181Sbill */ 131181Sbill unsleep(p) 132181Sbill register struct proc *p; 133181Sbill { 134181Sbill register struct proc **hp; 135181Sbill register s; 136181Sbill 137181Sbill s = spl6(); 138181Sbill if (p->p_wchan) { 139181Sbill hp = &slpque[HASH(p->p_wchan)]; 140181Sbill while (*hp != p) 141181Sbill hp = &(*hp)->p_link; 142181Sbill *hp = p->p_link; 143181Sbill p->p_wchan = 0; 144181Sbill } 145181Sbill splx(s); 146181Sbill } 147181Sbill 148181Sbill /* 14933Sbill * Wake up all processes sleeping on chan. 15033Sbill */ 15133Sbill wakeup(chan) 15233Sbill register caddr_t chan; 15333Sbill { 154187Sbill register struct proc *p, **q, **h; 15533Sbill int s; 15633Sbill 15733Sbill s = spl6(); 158187Sbill h = &slpque[HASH(chan)]; 15933Sbill restart: 160187Sbill for (q = h; p = *q; ) { 161181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 16233Sbill panic("wakeup"); 163207Sbill if (p->p_wchan==chan) { 16433Sbill p->p_wchan = 0; 165187Sbill *q = p->p_link; 16633Sbill p->p_slptime = 0; 167181Sbill if (p->p_stat == SSLEEP) { 168181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 169181Sbill p->p_stat = SRUN; 170181Sbill if (p->p_flag & SLOAD) { 17133Sbill #ifndef FASTVAX 172181Sbill p->p_link = runq; 173181Sbill runq = p->p_link; 17433Sbill #else 175181Sbill setrq(p); 17633Sbill #endif 177181Sbill } 1782443Swnj if(p->p_pri < curpri) { 179181Sbill runrun++; 1802443Swnj aston(); 1812443Swnj } 182181Sbill if(runout != 0 && (p->p_flag&SLOAD) == 0) { 183181Sbill runout = 0; 184181Sbill wakeup((caddr_t)&runout); 185181Sbill } 186181Sbill /* END INLINE EXPANSION */ 187187Sbill goto restart; 18833Sbill } 189187Sbill } else 190187Sbill q = &p->p_link; 19133Sbill } 19233Sbill splx(s); 19333Sbill } 19433Sbill 19533Sbill #ifdef FASTVAX 19633Sbill /* 19733Sbill * Initialize the (doubly-linked) run queues 19833Sbill * to be empty. 19933Sbill */ 20033Sbill rqinit() 20133Sbill { 20233Sbill register int i; 20333Sbill 20433Sbill for (i = 0; i < NQS; i++) 20533Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 20633Sbill } 20733Sbill #endif 20833Sbill 20933Sbill /* 21033Sbill * Set the process running; 21133Sbill * arrange for it to be swapped in if necessary. 21233Sbill */ 21333Sbill setrun(p) 21433Sbill register struct proc *p; 21533Sbill { 21633Sbill register s; 21733Sbill 21833Sbill s = spl6(); 21933Sbill switch (p->p_stat) { 22033Sbill 22133Sbill case 0: 22233Sbill case SWAIT: 22333Sbill case SRUN: 22433Sbill case SZOMB: 22533Sbill default: 22633Sbill panic("setrun"); 22733Sbill 228207Sbill case SSTOP: 22933Sbill case SSLEEP: 230181Sbill unsleep(p); /* e.g. when sending signals */ 23133Sbill break; 23233Sbill 23333Sbill case SIDL: 23433Sbill break; 23533Sbill } 23633Sbill p->p_stat = SRUN; 23733Sbill if (p->p_flag & SLOAD) 23833Sbill setrq(p); 23933Sbill splx(s); 2402443Swnj if(p->p_pri < curpri) { 24133Sbill runrun++; 2422443Swnj aston(); 2432443Swnj } 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; 2621543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 26333Sbill if(p > 127) 26433Sbill p = 127; 265*2453Swnj if(p < curpri) { 26633Sbill runrun++; 267*2453Swnj aston(); 268*2453Swnj } 26933Sbill pp->p_usrpri = p; 27033Sbill return(p); 27133Sbill } 27233Sbill 27333Sbill /* 27433Sbill * Create a new process-- the internal version of 27533Sbill * sys fork. 27633Sbill * It returns 1 in the new process, 0 in the old. 27733Sbill */ 27833Sbill newproc(isvfork) 27933Sbill { 28033Sbill register struct proc *p; 28133Sbill register struct proc *rpp, *rip; 28233Sbill register int n; 28333Sbill 28433Sbill p = NULL; 28533Sbill /* 28633Sbill * First, just locate a slot for a process 28733Sbill * and copy the useful info from this process into it. 28833Sbill * The panic "cannot happen" because fork has already 28933Sbill * checked for the existence of a slot. 29033Sbill */ 29133Sbill retry: 29233Sbill mpid++; 29333Sbill if(mpid >= 30000) { 29433Sbill mpid = 0; 29533Sbill goto retry; 29633Sbill } 29733Sbill for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { 29833Sbill if(rpp->p_stat == NULL && p==NULL) 29933Sbill p = rpp; 30033Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 30133Sbill goto retry; 30233Sbill } 30333Sbill if ((rpp = p)==NULL) 30433Sbill panic("no procs"); 30533Sbill 30633Sbill /* 30733Sbill * make proc entry for new proc 30833Sbill */ 30933Sbill 31033Sbill rip = u.u_procp; 31133Sbill rpp->p_stat = SIDL; 31233Sbill rpp->p_clktim = 0; 313913Sbill rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG)); 31433Sbill if (isvfork) { 31533Sbill rpp->p_flag |= SVFORK; 31633Sbill rpp->p_ndx = rip->p_ndx; 31733Sbill } else 31833Sbill rpp->p_ndx = rpp - proc; 31933Sbill rpp->p_uid = rip->p_uid; 32033Sbill rpp->p_pgrp = rip->p_pgrp; 32133Sbill rpp->p_nice = rip->p_nice; 32233Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 32333Sbill rpp->p_pid = mpid; 32433Sbill rpp->p_ppid = rip->p_pid; 325181Sbill rpp->p_pptr = rip; 32633Sbill rpp->p_time = 0; 32733Sbill rpp->p_cpu = 0; 328181Sbill rpp->p_siga0 = rip->p_siga0; 329181Sbill rpp->p_siga1 = rip->p_siga1; 330181Sbill /* take along any pending signals, like stops? */ 33133Sbill if (isvfork) { 33233Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 33333Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 33433Sbill forkstat.cntvfork++; 33533Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 33633Sbill } else { 33733Sbill rpp->p_tsize = rip->p_tsize; 33833Sbill rpp->p_dsize = rip->p_dsize; 33933Sbill rpp->p_ssize = rip->p_ssize; 34033Sbill rpp->p_szpt = rip->p_szpt; 34133Sbill forkstat.cntfork++; 34233Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 34333Sbill } 34433Sbill rpp->p_rssize = 0; 34533Sbill rpp->p_wchan = 0; 34633Sbill rpp->p_slptime = 0; 3471400Sbill rpp->p_pctcpu = 0; 3481400Sbill rpp->p_cpticks = 0; 34933Sbill n = PIDHASH(rpp->p_pid); 35033Sbill p->p_idhash = pidhash[n]; 35133Sbill pidhash[n] = rpp - proc; 35233Sbill 35333Sbill /* 35433Sbill * make duplicate entries 35533Sbill * where needed 35633Sbill */ 35733Sbill 35833Sbill multprog++; 35933Sbill 36033Sbill for(n=0; n<NOFILE; n++) 36133Sbill if(u.u_ofile[n] != NULL) { 3622329Swnj #ifdef UCBIPC 3632329Swnj if (u.u_pofile[n] & ISPORT) 3642329Swnj u.u_oport[n]->pt_count++; 3652329Swnj else { 3662329Swnj #endif 3672329Swnj u.u_ofile[n]->f_count++; 3682329Swnj if(!isvfork && u.u_vrpages[n]) 3692329Swnj u.u_ofile[n]->f_inode->i_vfdcnt++; 3702329Swnj #ifdef UCBIPC 3712329Swnj } 3722329Swnj #endif UCBIPC 37333Sbill } 37433Sbill 37533Sbill u.u_cdir->i_count++; 37633Sbill if (u.u_rdir) 37733Sbill u.u_rdir->i_count++; 37833Sbill /* 37933Sbill * Partially simulate the environment 38033Sbill * of the new process so that when it is actually 38133Sbill * created (by copying) it will look right. 38233Sbill */ 38333Sbill 38433Sbill rip->p_flag |= SKEEP; /* prevent parent from being swapped */ 38533Sbill 38633Sbill if (procdup(rpp, isvfork)) 38733Sbill return (1); 38833Sbill 3891788Sbill (void) spl6(); 39033Sbill rpp->p_stat = SRUN; 39133Sbill setrq(rpp); 3921793Sbill (void) spl0(); 39388Sbill /* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */ 39433Sbill /* rpp->p_flag |= SSWAP; */ 39533Sbill rip->p_flag &= ~SKEEP; 39633Sbill if (isvfork) { 39733Sbill u.u_procp->p_xlink = rpp; 39833Sbill u.u_procp->p_flag |= SNOVM; 39933Sbill while (rpp->p_flag & SVFORK) 40033Sbill sleep((caddr_t)rpp, PZERO - 1); 40133Sbill if ((rpp->p_flag & SLOAD) == 0) 40233Sbill panic("newproc vfork"); 40333Sbill uaccess(rpp, Vfmap, &vfutl); 40433Sbill u.u_procp->p_xlink = 0; 40533Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 40633Sbill for (n = 0; n < NOFILE; n++) 40733Sbill if (vfutl.u_vrpages[n]) { 40833Sbill if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0) 40933Sbill if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0) 41033Sbill panic("newproc i_vfdcnt"); 41133Sbill vfutl.u_vrpages[n] = 0; 41233Sbill } 41333Sbill u.u_procp->p_flag &= ~SNOVM; 41433Sbill rpp->p_ndx = rpp - proc; 41533Sbill rpp->p_flag |= SVFDONE; 41633Sbill wakeup((caddr_t)rpp); 41733Sbill } 41833Sbill return (0); 41933Sbill } 420