1*5619Swnj /* kern_synch.c 4.16 82/01/24 */ 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; 464826Swnj if (pri > PZERO) { 474826Swnj 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(); 594826Swnj 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 724826Swnj * there has been a signal, execute non-local goto through 734826Swnj * u.u_qsav, aborting the system call in progress (see trap.c) 744826Swnj * (or finishing a tsleep, see below) 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 884826Swnj * 894826Swnj * SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN 904826Swnj * INCREMENT IN MILLISECONDS! 91100Sbill */ 92100Sbill tsleep(chan, pri, seconds) 934826Swnj caddr_t chan; 944826Swnj int pri, seconds; 95100Sbill { 96100Sbill label_t lqsav; 97100Sbill register struct proc *pp; 98100Sbill register sec, n, rval; 99100Sbill 100100Sbill pp = u.u_procp; 101102Sbill n = spl7(); 102100Sbill sec = 0; 103100Sbill rval = 0; 104100Sbill if (pp->p_clktim && pp->p_clktim<seconds) 105100Sbill seconds = 0; 106100Sbill if (seconds) { 107100Sbill pp->p_flag |= STIMO; 108103Sbill sec = pp->p_clktim-seconds; 109100Sbill pp->p_clktim = seconds; 110100Sbill } 111100Sbill bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 112100Sbill if (setjmp(u.u_qsav)) 113100Sbill rval = TS_SIG; 114100Sbill else { 115100Sbill sleep(chan, pri); 116100Sbill if ((pp->p_flag&STIMO)==0 && seconds) 117100Sbill rval = TS_TIME; 118100Sbill else 119100Sbill rval = TS_OK; 120100Sbill } 121100Sbill pp->p_flag &= ~STIMO; 122100Sbill bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 123103Sbill if (sec > 0) 124103Sbill pp->p_clktim += sec; 125103Sbill else 126103Sbill pp->p_clktim = 0; 127100Sbill splx(n); 1284826Swnj return (rval); 129100Sbill } 130100Sbill 131100Sbill /* 132181Sbill * Remove a process from its wait queue 133181Sbill */ 134181Sbill unsleep(p) 1354826Swnj register struct proc *p; 136181Sbill { 137181Sbill register struct proc **hp; 138181Sbill register s; 139181Sbill 140181Sbill s = spl6(); 141181Sbill if (p->p_wchan) { 142181Sbill hp = &slpque[HASH(p->p_wchan)]; 143181Sbill while (*hp != p) 144181Sbill hp = &(*hp)->p_link; 145181Sbill *hp = p->p_link; 146181Sbill p->p_wchan = 0; 147181Sbill } 148181Sbill splx(s); 149181Sbill } 150181Sbill 151181Sbill /* 15233Sbill * Wake up all processes sleeping on chan. 15333Sbill */ 15433Sbill wakeup(chan) 1554826Swnj register caddr_t chan; 15633Sbill { 157187Sbill register struct proc *p, **q, **h; 15833Sbill int s; 15933Sbill 16033Sbill s = spl6(); 161187Sbill h = &slpque[HASH(chan)]; 16233Sbill restart: 163187Sbill for (q = h; p = *q; ) { 164181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 16533Sbill panic("wakeup"); 166207Sbill if (p->p_wchan==chan) { 16733Sbill p->p_wchan = 0; 168187Sbill *q = p->p_link; 16933Sbill p->p_slptime = 0; 170181Sbill if (p->p_stat == SSLEEP) { 171181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 172181Sbill p->p_stat = SRUN; 1732702Swnj if (p->p_flag & SLOAD) 174181Sbill setrq(p); 1754826Swnj if (p->p_pri < curpri) { 176181Sbill runrun++; 1772443Swnj aston(); 1782443Swnj } 1793545Swnj if ((p->p_flag&SLOAD) == 0) { 1803545Swnj if (runout != 0) { 1813545Swnj runout = 0; 1823545Swnj wakeup((caddr_t)&runout); 1833545Swnj } 1843545Swnj wantin++; 185181Sbill } 186181Sbill /* END INLINE EXPANSION */ 187187Sbill goto restart; 18833Sbill } 189187Sbill } else 190187Sbill q = &p->p_link; 19133Sbill } 19233Sbill splx(s); 19333Sbill } 19433Sbill 19533Sbill /* 19633Sbill * Initialize the (doubly-linked) run queues 19733Sbill * to be empty. 19833Sbill */ 19933Sbill rqinit() 20033Sbill { 20133Sbill register int i; 20233Sbill 20333Sbill for (i = 0; i < NQS; i++) 20433Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 20533Sbill } 20633Sbill 20733Sbill /* 20833Sbill * Set the process running; 20933Sbill * arrange for it to be swapped in if necessary. 21033Sbill */ 21133Sbill setrun(p) 2124826Swnj register struct proc *p; 21333Sbill { 2144826Swnj register int s; 21533Sbill 21633Sbill s = spl6(); 21733Sbill switch (p->p_stat) { 21833Sbill 21933Sbill case 0: 22033Sbill case SWAIT: 22133Sbill case SRUN: 22233Sbill case SZOMB: 22333Sbill default: 22433Sbill panic("setrun"); 22533Sbill 226207Sbill case SSTOP: 22733Sbill case SSLEEP: 228181Sbill unsleep(p); /* e.g. when sending signals */ 22933Sbill break; 23033Sbill 23133Sbill case SIDL: 23233Sbill break; 23333Sbill } 23433Sbill p->p_stat = SRUN; 23533Sbill if (p->p_flag & SLOAD) 23633Sbill setrq(p); 23733Sbill splx(s); 2384826Swnj if (p->p_pri < curpri) { 23933Sbill runrun++; 2402443Swnj aston(); 2412443Swnj } 2423545Swnj if ((p->p_flag&SLOAD) == 0) { 2434826Swnj if (runout != 0) { 2443545Swnj runout = 0; 2453545Swnj wakeup((caddr_t)&runout); 2463545Swnj } 2473545Swnj wantin++; 24833Sbill } 24933Sbill } 25033Sbill 25133Sbill /* 25233Sbill * Set user priority. 25333Sbill * The rescheduling flag (runrun) 25433Sbill * is set if the priority is better 25533Sbill * than the currently running process. 25633Sbill */ 25733Sbill setpri(pp) 2584826Swnj register struct proc *pp; 25933Sbill { 2604826Swnj register int p; 26133Sbill 2623875Swnj p = (pp->p_cpu & 0377)/4; 2631543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 2643530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 2653530Swnj p += 2*4; /* effectively, nice(4) */ 2664826Swnj if (p > 127) 26733Sbill p = 127; 2684826Swnj if (p < curpri) { 26933Sbill runrun++; 2702453Swnj aston(); 2712453Swnj } 27233Sbill pp->p_usrpri = p; 2734826Swnj return (p); 27433Sbill } 27533Sbill 27633Sbill /* 27733Sbill * Create a new process-- the internal version of 27833Sbill * sys fork. 27933Sbill * It returns 1 in the new process, 0 in the old. 28033Sbill */ 28133Sbill newproc(isvfork) 2824826Swnj int isvfork; 28333Sbill { 28433Sbill register struct proc *p; 28533Sbill register struct proc *rpp, *rip; 28633Sbill register int n; 28733Sbill 28833Sbill p = NULL; 28933Sbill /* 29033Sbill * First, just locate a slot for a process 29133Sbill * and copy the useful info from this process into it. 29233Sbill * The panic "cannot happen" because fork has already 29333Sbill * checked for the existence of a slot. 29433Sbill */ 29533Sbill retry: 29633Sbill mpid++; 2974826Swnj if (mpid >= 30000) { 29833Sbill mpid = 0; 29933Sbill goto retry; 30033Sbill } 3014826Swnj for (rpp = proc; rpp < procNPROC; rpp++) { 3024826Swnj if (rpp->p_stat == NULL && p==NULL) 30333Sbill p = rpp; 30433Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 30533Sbill goto retry; 30633Sbill } 3074826Swnj if ((rpp = p) == NULL) 30833Sbill panic("no procs"); 30933Sbill 31033Sbill /* 3114826Swnj * Make a proc table entry for the new process. 31233Sbill */ 31333Sbill rip = u.u_procp; 31433Sbill rpp->p_stat = SIDL; 31533Sbill rpp->p_clktim = 0; 316*5619Swnj rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 31733Sbill if (isvfork) { 31833Sbill rpp->p_flag |= SVFORK; 31933Sbill rpp->p_ndx = rip->p_ndx; 32033Sbill } else 32133Sbill rpp->p_ndx = rpp - proc; 32233Sbill rpp->p_uid = rip->p_uid; 32333Sbill rpp->p_pgrp = rip->p_pgrp; 32433Sbill rpp->p_nice = rip->p_nice; 32533Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 32633Sbill rpp->p_pid = mpid; 32733Sbill rpp->p_ppid = rip->p_pid; 328181Sbill rpp->p_pptr = rip; 32933Sbill rpp->p_time = 0; 33033Sbill rpp->p_cpu = 0; 331181Sbill rpp->p_siga0 = rip->p_siga0; 332181Sbill rpp->p_siga1 = rip->p_siga1; 333181Sbill /* take along any pending signals, like stops? */ 33433Sbill if (isvfork) { 33533Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 33633Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 33733Sbill forkstat.cntvfork++; 33833Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 33933Sbill } else { 34033Sbill rpp->p_tsize = rip->p_tsize; 34133Sbill rpp->p_dsize = rip->p_dsize; 34233Sbill rpp->p_ssize = rip->p_ssize; 34333Sbill rpp->p_szpt = rip->p_szpt; 34433Sbill forkstat.cntfork++; 34533Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 34633Sbill } 34733Sbill rpp->p_rssize = 0; 3483514Sroot rpp->p_maxrss = rip->p_maxrss; 34933Sbill rpp->p_wchan = 0; 35033Sbill rpp->p_slptime = 0; 3511400Sbill rpp->p_pctcpu = 0; 3521400Sbill rpp->p_cpticks = 0; 35333Sbill n = PIDHASH(rpp->p_pid); 35433Sbill p->p_idhash = pidhash[n]; 35533Sbill pidhash[n] = rpp - proc; 3564826Swnj multprog++; 35733Sbill 35833Sbill /* 3594826Swnj * Increase reference counts on shared objects. 36033Sbill */ 36133Sbill for(n=0; n<NOFILE; n++) 3624826Swnj if (u.u_ofile[n] != NULL) 3632938Swnj u.u_ofile[n]->f_count++; 36433Sbill u.u_cdir->i_count++; 36533Sbill if (u.u_rdir) 36633Sbill u.u_rdir->i_count++; 3674826Swnj 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. 3724826Swnj * This begins the section where we must prevent the parent 3734826Swnj * from being swapped. 37433Sbill */ 3754826Swnj rip->p_flag |= SKEEP; 37633Sbill if (procdup(rpp, isvfork)) 37733Sbill return (1); 37833Sbill 3794826Swnj /* 3804826Swnj * Make child runnable and add to run queue. 3814826Swnj */ 3821788Sbill (void) spl6(); 38333Sbill rpp->p_stat = SRUN; 38433Sbill setrq(rpp); 3851793Sbill (void) spl0(); 3864826Swnj 3874826Swnj /* 3884826Swnj * Cause child to take a non-local goto as soon as it runs. 3894826Swnj * On older systems this was done with SSWAP bit in proc 3904826Swnj * table; on VAX we use u.u_pcb.pcb_sswap so don't need 3914826Swnj * to do rpp->p_flag |= SSWAP. Actually do nothing here. 3924826Swnj */ 39333Sbill /* rpp->p_flag |= SSWAP; */ 3944826Swnj 3954826Swnj /* 3964826Swnj * Now can be swapped. 3974826Swnj */ 39833Sbill rip->p_flag &= ~SKEEP; 3994826Swnj 4004826Swnj /* 4014826Swnj * If vfork make chain from parent process to child 4024826Swnj * (where virtal memory is temporarily). Wait for 4034826Swnj * child to finish, steal virtual memory back, 4044826Swnj * and wakeup child to let it die. 4054826Swnj */ 40633Sbill if (isvfork) { 40733Sbill u.u_procp->p_xlink = rpp; 40833Sbill u.u_procp->p_flag |= SNOVM; 40933Sbill while (rpp->p_flag & SVFORK) 41033Sbill sleep((caddr_t)rpp, PZERO - 1); 41133Sbill if ((rpp->p_flag & SLOAD) == 0) 41233Sbill panic("newproc vfork"); 41333Sbill uaccess(rpp, Vfmap, &vfutl); 41433Sbill u.u_procp->p_xlink = 0; 41533Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 41633Sbill u.u_procp->p_flag &= ~SNOVM; 41733Sbill rpp->p_ndx = rpp - proc; 41833Sbill rpp->p_flag |= SVFDONE; 41933Sbill wakeup((caddr_t)rpp); 42033Sbill } 4214826Swnj 4224826Swnj /* 4234826Swnj * 0 return means parent. 4244826Swnj */ 42533Sbill return (0); 42633Sbill } 427