1*7698Ssam /* kern_synch.c 4.18 82/08/10 */ 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" 147485Skre #include "../h/quota.h" 1533Sbill 1633Sbill #define SQSIZE 0100 /* Must be power of 2 */ 1733Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 1833Sbill struct proc *slpque[SQSIZE]; 1933Sbill 2033Sbill /* 2133Sbill * Give up the processor till a wakeup occurs 2233Sbill * on chan, at which time the process 2333Sbill * enters the scheduling queue at priority pri. 2433Sbill * The most important effect of pri is that when 2533Sbill * pri<=PZERO a signal cannot disturb the sleep; 2633Sbill * if pri>PZERO signals will be processed. 2733Sbill * Callers of this routine must be prepared for 2833Sbill * premature return, and check that the reason for 2933Sbill * sleeping has gone away. 3033Sbill */ 3133Sbill sleep(chan, pri) 3233Sbill caddr_t chan; 3333Sbill { 34187Sbill register struct proc *rp, **hp; 35207Sbill register s; 3633Sbill 3733Sbill rp = u.u_procp; 3833Sbill s = spl6(); 3933Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 4033Sbill panic("sleep"); 4133Sbill rp->p_wchan = chan; 4233Sbill rp->p_slptime = 0; 4333Sbill rp->p_pri = pri; 44187Sbill hp = &slpque[HASH(chan)]; 45187Sbill rp->p_link = *hp; 46187Sbill *hp = rp; 474826Swnj if (pri > PZERO) { 484826Swnj if (ISSIG(rp)) { 49187Sbill if (rp->p_wchan) 50187Sbill unsleep(rp); 5133Sbill rp->p_stat = SRUN; 52131Sbill (void) spl0(); 5333Sbill goto psig; 5433Sbill } 55187Sbill if (rp->p_wchan == 0) 56187Sbill goto out; 57187Sbill rp->p_stat = SSLEEP; 58131Sbill (void) spl0(); 5933Sbill swtch(); 604826Swnj if (ISSIG(rp)) 6133Sbill goto psig; 6233Sbill } else { 63207Sbill rp->p_stat = SSLEEP; 64131Sbill (void) spl0(); 6533Sbill swtch(); 6633Sbill } 67187Sbill out: 6833Sbill splx(s); 6933Sbill return; 7033Sbill 7133Sbill /* 7233Sbill * If priority was low (>PZERO) and 734826Swnj * there has been a signal, execute non-local goto through 744826Swnj * u.u_qsav, aborting the system call in progress (see trap.c) 754826Swnj * (or finishing a tsleep, see below) 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 894826Swnj * 904826Swnj * SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN 914826Swnj * INCREMENT IN MILLISECONDS! 92100Sbill */ 93100Sbill tsleep(chan, pri, seconds) 944826Swnj caddr_t chan; 954826Swnj int pri, seconds; 96100Sbill { 97100Sbill label_t lqsav; 98100Sbill register struct proc *pp; 997485Skre register sec, n, rval, sov; 100100Sbill 101100Sbill pp = u.u_procp; 102102Sbill n = spl7(); 103100Sbill sec = 0; 104100Sbill rval = 0; 1057485Skre sov = 0; 106100Sbill if (pp->p_clktim && pp->p_clktim<seconds) 1077485Skre if (pri > PZERO) 1087485Skre seconds = 0; 1097485Skre else 1107485Skre sov++; 111100Sbill if (seconds) { 112100Sbill pp->p_flag |= STIMO; 113103Sbill sec = pp->p_clktim-seconds; 114100Sbill pp->p_clktim = seconds; 115100Sbill } 116100Sbill bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 117100Sbill if (setjmp(u.u_qsav)) 118100Sbill rval = TS_SIG; 119100Sbill else { 120100Sbill sleep(chan, pri); 121100Sbill if ((pp->p_flag&STIMO)==0 && seconds) 122100Sbill rval = TS_TIME; 123100Sbill else 124100Sbill rval = TS_OK; 125100Sbill } 126100Sbill pp->p_flag &= ~STIMO; 127100Sbill bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 128103Sbill if (sec > 0) 129103Sbill pp->p_clktim += sec; 1307485Skre else if (sov) { 1317485Skre if ((pp->p_clktim += sec) <= 0) { 1327485Skre pp->p_clktim = 0; 1337485Skre psignal(pp, SIGALRM); 1347485Skre } 1357485Skre } else 136103Sbill pp->p_clktim = 0; 137100Sbill splx(n); 1384826Swnj return (rval); 139100Sbill } 140100Sbill 141100Sbill /* 142181Sbill * Remove a process from its wait queue 143181Sbill */ 144181Sbill unsleep(p) 1454826Swnj register struct proc *p; 146181Sbill { 147181Sbill register struct proc **hp; 148181Sbill register s; 149181Sbill 150181Sbill s = spl6(); 151181Sbill if (p->p_wchan) { 152181Sbill hp = &slpque[HASH(p->p_wchan)]; 153181Sbill while (*hp != p) 154181Sbill hp = &(*hp)->p_link; 155181Sbill *hp = p->p_link; 156181Sbill p->p_wchan = 0; 157181Sbill } 158181Sbill splx(s); 159181Sbill } 160181Sbill 161181Sbill /* 16233Sbill * Wake up all processes sleeping on chan. 16333Sbill */ 16433Sbill wakeup(chan) 1654826Swnj register caddr_t chan; 16633Sbill { 167187Sbill register struct proc *p, **q, **h; 16833Sbill int s; 16933Sbill 17033Sbill s = spl6(); 171187Sbill h = &slpque[HASH(chan)]; 17233Sbill restart: 173187Sbill for (q = h; p = *q; ) { 174181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 17533Sbill panic("wakeup"); 176207Sbill if (p->p_wchan==chan) { 17733Sbill p->p_wchan = 0; 178187Sbill *q = p->p_link; 17933Sbill p->p_slptime = 0; 180181Sbill if (p->p_stat == SSLEEP) { 181181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 182181Sbill p->p_stat = SRUN; 1832702Swnj if (p->p_flag & SLOAD) 184181Sbill setrq(p); 1854826Swnj if (p->p_pri < curpri) { 186181Sbill runrun++; 1872443Swnj aston(); 1882443Swnj } 1893545Swnj if ((p->p_flag&SLOAD) == 0) { 1903545Swnj if (runout != 0) { 1913545Swnj runout = 0; 1923545Swnj wakeup((caddr_t)&runout); 1933545Swnj } 1943545Swnj wantin++; 195181Sbill } 196181Sbill /* END INLINE EXPANSION */ 197187Sbill goto restart; 19833Sbill } 199187Sbill } else 200187Sbill q = &p->p_link; 20133Sbill } 20233Sbill splx(s); 20333Sbill } 20433Sbill 20533Sbill /* 20633Sbill * Initialize the (doubly-linked) run queues 20733Sbill * to be empty. 20833Sbill */ 20933Sbill rqinit() 21033Sbill { 21133Sbill register int i; 21233Sbill 21333Sbill for (i = 0; i < NQS; i++) 21433Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 21533Sbill } 21633Sbill 21733Sbill /* 21833Sbill * Set the process running; 21933Sbill * arrange for it to be swapped in if necessary. 22033Sbill */ 22133Sbill setrun(p) 2224826Swnj register struct proc *p; 22333Sbill { 2244826Swnj register int s; 22533Sbill 22633Sbill s = spl6(); 22733Sbill switch (p->p_stat) { 22833Sbill 22933Sbill case 0: 23033Sbill case SWAIT: 23133Sbill case SRUN: 23233Sbill case SZOMB: 23333Sbill default: 23433Sbill panic("setrun"); 23533Sbill 236207Sbill case SSTOP: 23733Sbill case SSLEEP: 238181Sbill unsleep(p); /* e.g. when sending signals */ 23933Sbill break; 24033Sbill 24133Sbill case SIDL: 24233Sbill break; 24333Sbill } 24433Sbill p->p_stat = SRUN; 24533Sbill if (p->p_flag & SLOAD) 24633Sbill setrq(p); 24733Sbill splx(s); 2484826Swnj if (p->p_pri < curpri) { 24933Sbill runrun++; 2502443Swnj aston(); 2512443Swnj } 2523545Swnj if ((p->p_flag&SLOAD) == 0) { 2534826Swnj if (runout != 0) { 2543545Swnj runout = 0; 2553545Swnj wakeup((caddr_t)&runout); 2563545Swnj } 2573545Swnj wantin++; 25833Sbill } 25933Sbill } 26033Sbill 26133Sbill /* 26233Sbill * Set user priority. 26333Sbill * The rescheduling flag (runrun) 26433Sbill * is set if the priority is better 26533Sbill * than the currently running process. 26633Sbill */ 26733Sbill setpri(pp) 2684826Swnj register struct proc *pp; 26933Sbill { 2704826Swnj register int p; 27133Sbill 2723875Swnj p = (pp->p_cpu & 0377)/4; 2731543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 2743530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 2753530Swnj p += 2*4; /* effectively, nice(4) */ 2764826Swnj if (p > 127) 27733Sbill p = 127; 2784826Swnj if (p < curpri) { 27933Sbill runrun++; 2802453Swnj aston(); 2812453Swnj } 28233Sbill pp->p_usrpri = p; 2834826Swnj return (p); 28433Sbill } 28533Sbill 28633Sbill /* 28733Sbill * Create a new process-- the internal version of 28833Sbill * sys fork. 28933Sbill * It returns 1 in the new process, 0 in the old. 29033Sbill */ 29133Sbill newproc(isvfork) 2924826Swnj int isvfork; 29333Sbill { 29433Sbill register struct proc *p; 29533Sbill register struct proc *rpp, *rip; 29633Sbill register int n; 297*7698Ssam register struct file *fp; 29833Sbill 29933Sbill p = NULL; 30033Sbill /* 30133Sbill * First, just locate a slot for a process 30233Sbill * and copy the useful info from this process into it. 30333Sbill * The panic "cannot happen" because fork has already 30433Sbill * checked for the existence of a slot. 30533Sbill */ 30633Sbill retry: 30733Sbill mpid++; 3084826Swnj if (mpid >= 30000) { 30933Sbill mpid = 0; 31033Sbill goto retry; 31133Sbill } 3124826Swnj for (rpp = proc; rpp < procNPROC; rpp++) { 3134826Swnj if (rpp->p_stat == NULL && p==NULL) 31433Sbill p = rpp; 31533Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 31633Sbill goto retry; 31733Sbill } 3184826Swnj if ((rpp = p) == NULL) 31933Sbill panic("no procs"); 32033Sbill 32133Sbill /* 3224826Swnj * Make a proc table entry for the new process. 32333Sbill */ 32433Sbill rip = u.u_procp; 3257485Skre #ifdef QUOTA 3267485Skre (rpp->p_quota = rip->p_quota)->q_cnt++; 3277485Skre #endif 32833Sbill rpp->p_stat = SIDL; 32933Sbill rpp->p_clktim = 0; 3305619Swnj rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 33133Sbill if (isvfork) { 33233Sbill rpp->p_flag |= SVFORK; 33333Sbill rpp->p_ndx = rip->p_ndx; 33433Sbill } else 33533Sbill rpp->p_ndx = rpp - proc; 33633Sbill rpp->p_uid = rip->p_uid; 33733Sbill rpp->p_pgrp = rip->p_pgrp; 33833Sbill rpp->p_nice = rip->p_nice; 33933Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 34033Sbill rpp->p_pid = mpid; 34133Sbill rpp->p_ppid = rip->p_pid; 342181Sbill rpp->p_pptr = rip; 3437485Skre rpp->p_osptr = rip->p_cptr; 3447485Skre if (rip->p_cptr) 3457485Skre rip->p_cptr->p_ysptr = rpp; 3467485Skre rpp->p_ysptr = NULL; 3477485Skre rpp->p_cptr = NULL; 3487485Skre rip->p_cptr = rpp; 34933Sbill rpp->p_time = 0; 35033Sbill rpp->p_cpu = 0; 351181Sbill rpp->p_siga0 = rip->p_siga0; 352181Sbill rpp->p_siga1 = rip->p_siga1; 353181Sbill /* take along any pending signals, like stops? */ 35433Sbill if (isvfork) { 35533Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 35633Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 35733Sbill forkstat.cntvfork++; 35833Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 35933Sbill } else { 36033Sbill rpp->p_tsize = rip->p_tsize; 36133Sbill rpp->p_dsize = rip->p_dsize; 36233Sbill rpp->p_ssize = rip->p_ssize; 36333Sbill rpp->p_szpt = rip->p_szpt; 36433Sbill forkstat.cntfork++; 36533Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 36633Sbill } 36733Sbill rpp->p_rssize = 0; 3683514Sroot rpp->p_maxrss = rip->p_maxrss; 36933Sbill rpp->p_wchan = 0; 37033Sbill rpp->p_slptime = 0; 3711400Sbill rpp->p_pctcpu = 0; 3721400Sbill rpp->p_cpticks = 0; 37333Sbill n = PIDHASH(rpp->p_pid); 37433Sbill p->p_idhash = pidhash[n]; 37533Sbill pidhash[n] = rpp - proc; 3764826Swnj multprog++; 37733Sbill 37833Sbill /* 3794826Swnj * Increase reference counts on shared objects. 38033Sbill */ 381*7698Ssam for (n = 0; n < NOFILE; n++) { 382*7698Ssam fp = u.u_ofile[n]; 383*7698Ssam if (fp == NULL) 384*7698Ssam continue; 385*7698Ssam fp->f_count++; 386*7698Ssam if (u.u_pofile[n]&RDLOCK) 387*7698Ssam fp->f_inode->i_rdlockc++; 388*7698Ssam if (u.u_pofile[n]&WRLOCK) 389*7698Ssam fp->f_inode->i_wrlockc++; 390*7698Ssam } 39133Sbill u.u_cdir->i_count++; 39233Sbill if (u.u_rdir) 39333Sbill u.u_rdir->i_count++; 3944826Swnj 39533Sbill /* 39633Sbill * Partially simulate the environment 39733Sbill * of the new process so that when it is actually 39833Sbill * created (by copying) it will look right. 3994826Swnj * This begins the section where we must prevent the parent 4004826Swnj * from being swapped. 40133Sbill */ 4024826Swnj rip->p_flag |= SKEEP; 40333Sbill if (procdup(rpp, isvfork)) 40433Sbill return (1); 40533Sbill 4064826Swnj /* 4074826Swnj * Make child runnable and add to run queue. 4084826Swnj */ 4091788Sbill (void) spl6(); 41033Sbill rpp->p_stat = SRUN; 41133Sbill setrq(rpp); 4121793Sbill (void) spl0(); 4134826Swnj 4144826Swnj /* 4154826Swnj * Cause child to take a non-local goto as soon as it runs. 4164826Swnj * On older systems this was done with SSWAP bit in proc 4174826Swnj * table; on VAX we use u.u_pcb.pcb_sswap so don't need 4184826Swnj * to do rpp->p_flag |= SSWAP. Actually do nothing here. 4194826Swnj */ 42033Sbill /* rpp->p_flag |= SSWAP; */ 4214826Swnj 4224826Swnj /* 4234826Swnj * Now can be swapped. 4244826Swnj */ 42533Sbill rip->p_flag &= ~SKEEP; 4264826Swnj 4274826Swnj /* 4284826Swnj * If vfork make chain from parent process to child 4294826Swnj * (where virtal memory is temporarily). Wait for 4304826Swnj * child to finish, steal virtual memory back, 4314826Swnj * and wakeup child to let it die. 4324826Swnj */ 43333Sbill if (isvfork) { 43433Sbill u.u_procp->p_xlink = rpp; 43533Sbill u.u_procp->p_flag |= SNOVM; 43633Sbill while (rpp->p_flag & SVFORK) 43733Sbill sleep((caddr_t)rpp, PZERO - 1); 43833Sbill if ((rpp->p_flag & SLOAD) == 0) 43933Sbill panic("newproc vfork"); 44033Sbill uaccess(rpp, Vfmap, &vfutl); 44133Sbill u.u_procp->p_xlink = 0; 44233Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 44333Sbill u.u_procp->p_flag &= ~SNOVM; 44433Sbill rpp->p_ndx = rpp - proc; 44533Sbill rpp->p_flag |= SVFDONE; 44633Sbill wakeup((caddr_t)rpp); 44733Sbill } 4484826Swnj 4494826Swnj /* 4504826Swnj * 0 return means parent. 4514826Swnj */ 45233Sbill return (0); 45333Sbill } 454