1*8033Sroot /* kern_synch.c 4.19 82/09/04 */ 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) 32*8033Sroot caddr_t chan; 33*8033Sroot int pri; 3433Sbill { 35187Sbill register struct proc *rp, **hp; 36207Sbill register s; 3733Sbill 3833Sbill rp = u.u_procp; 3933Sbill s = spl6(); 4033Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 4133Sbill panic("sleep"); 4233Sbill rp->p_wchan = chan; 4333Sbill rp->p_slptime = 0; 4433Sbill rp->p_pri = pri; 45187Sbill hp = &slpque[HASH(chan)]; 46187Sbill rp->p_link = *hp; 47187Sbill *hp = rp; 484826Swnj if (pri > PZERO) { 494826Swnj if (ISSIG(rp)) { 50187Sbill if (rp->p_wchan) 51187Sbill unsleep(rp); 5233Sbill rp->p_stat = SRUN; 53131Sbill (void) spl0(); 5433Sbill goto psig; 5533Sbill } 56187Sbill if (rp->p_wchan == 0) 57187Sbill goto out; 58187Sbill rp->p_stat = SSLEEP; 59131Sbill (void) spl0(); 60*8033Sroot u.u_ru.ru_nvcsw++; 6133Sbill swtch(); 624826Swnj if (ISSIG(rp)) 6333Sbill goto psig; 6433Sbill } else { 65207Sbill rp->p_stat = SSLEEP; 66131Sbill (void) spl0(); 67*8033Sroot u.u_ru.ru_nvcsw++; 6833Sbill swtch(); 6933Sbill } 70187Sbill out: 7133Sbill splx(s); 7233Sbill return; 7333Sbill 7433Sbill /* 7533Sbill * If priority was low (>PZERO) and 764826Swnj * there has been a signal, execute non-local goto through 774826Swnj * u.u_qsav, aborting the system call in progress (see trap.c) 784826Swnj * (or finishing a tsleep, see below) 7933Sbill */ 8033Sbill psig: 8133Sbill longjmp(u.u_qsav); 8233Sbill /*NOTREACHED*/ 8333Sbill } 8433Sbill 8533Sbill /* 86*8033Sroot * Sleep on chan at pri for at most a specified amount of time. 87*8033Sroot * Return (TS_OK,TS_TIME,TS_SIG) on (normal,timeout,signal) condition. 88100Sbill */ 89*8033Sroot tsleep(chan, pri, tvp) 904826Swnj caddr_t chan; 91*8033Sroot int pri; 92*8033Sroot struct timeval *tvp; 93100Sbill { 94*8033Sroot register struct proc *p = u.u_procp; 95*8033Sroot int s, rval; 96100Sbill 97*8033Sroot s = spl7(); 98*8033Sroot if (timercmp(tvp, &p->p_realtimer.itimer_value, >)) { 99*8033Sroot /* alarm will occur first! */ 100100Sbill sleep(chan, pri); 101*8033Sroot rval = TS_OK; /* almost NOTREACHED modulo fuzz */ 102*8033Sroot } else { 103*8033Sroot label_t lqsav; 104*8033Sroot 105*8033Sroot bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t)); 106*8033Sroot p->p_seltimer = *tvp; 107*8033Sroot if (setjmp(u.u_qsav)) 108*8033Sroot rval = TS_SIG; 109*8033Sroot else { 110*8033Sroot sleep(chan, pri); 111100Sbill rval = TS_OK; 112*8033Sroot } 113*8033Sroot timerclear(&p->p_seltimer); 114*8033Sroot bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t)); 115100Sbill } 116*8033Sroot splx(s); 1174826Swnj return (rval); 118100Sbill } 119100Sbill 120100Sbill /* 121181Sbill * Remove a process from its wait queue 122181Sbill */ 123181Sbill unsleep(p) 1244826Swnj register struct proc *p; 125181Sbill { 126181Sbill register struct proc **hp; 127181Sbill register s; 128181Sbill 129181Sbill s = spl6(); 130181Sbill if (p->p_wchan) { 131181Sbill hp = &slpque[HASH(p->p_wchan)]; 132181Sbill while (*hp != p) 133181Sbill hp = &(*hp)->p_link; 134181Sbill *hp = p->p_link; 135181Sbill p->p_wchan = 0; 136181Sbill } 137181Sbill splx(s); 138181Sbill } 139181Sbill 140181Sbill /* 14133Sbill * Wake up all processes sleeping on chan. 14233Sbill */ 14333Sbill wakeup(chan) 1444826Swnj register caddr_t chan; 14533Sbill { 146187Sbill register struct proc *p, **q, **h; 14733Sbill int s; 14833Sbill 14933Sbill s = spl6(); 150187Sbill h = &slpque[HASH(chan)]; 15133Sbill restart: 152187Sbill for (q = h; p = *q; ) { 153181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 15433Sbill panic("wakeup"); 155207Sbill if (p->p_wchan==chan) { 15633Sbill p->p_wchan = 0; 157187Sbill *q = p->p_link; 15833Sbill p->p_slptime = 0; 159181Sbill if (p->p_stat == SSLEEP) { 160181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 161181Sbill p->p_stat = SRUN; 1622702Swnj if (p->p_flag & SLOAD) 163181Sbill setrq(p); 1644826Swnj if (p->p_pri < curpri) { 165181Sbill runrun++; 1662443Swnj aston(); 1672443Swnj } 1683545Swnj if ((p->p_flag&SLOAD) == 0) { 1693545Swnj if (runout != 0) { 1703545Swnj runout = 0; 1713545Swnj wakeup((caddr_t)&runout); 1723545Swnj } 1733545Swnj wantin++; 174181Sbill } 175181Sbill /* END INLINE EXPANSION */ 176187Sbill goto restart; 17733Sbill } 178187Sbill } else 179187Sbill q = &p->p_link; 18033Sbill } 18133Sbill splx(s); 18233Sbill } 18333Sbill 18433Sbill /* 18533Sbill * Initialize the (doubly-linked) run queues 18633Sbill * to be empty. 18733Sbill */ 18833Sbill rqinit() 18933Sbill { 19033Sbill register int i; 19133Sbill 19233Sbill for (i = 0; i < NQS; i++) 19333Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 19433Sbill } 19533Sbill 19633Sbill /* 19733Sbill * Set the process running; 19833Sbill * arrange for it to be swapped in if necessary. 19933Sbill */ 20033Sbill setrun(p) 2014826Swnj register struct proc *p; 20233Sbill { 2034826Swnj register int s; 20433Sbill 20533Sbill s = spl6(); 20633Sbill switch (p->p_stat) { 20733Sbill 20833Sbill case 0: 20933Sbill case SWAIT: 21033Sbill case SRUN: 21133Sbill case SZOMB: 21233Sbill default: 21333Sbill panic("setrun"); 21433Sbill 215207Sbill case SSTOP: 21633Sbill case SSLEEP: 217181Sbill unsleep(p); /* e.g. when sending signals */ 21833Sbill break; 21933Sbill 22033Sbill case SIDL: 22133Sbill break; 22233Sbill } 22333Sbill p->p_stat = SRUN; 22433Sbill if (p->p_flag & SLOAD) 22533Sbill setrq(p); 22633Sbill splx(s); 2274826Swnj if (p->p_pri < curpri) { 22833Sbill runrun++; 2292443Swnj aston(); 2302443Swnj } 2313545Swnj if ((p->p_flag&SLOAD) == 0) { 2324826Swnj if (runout != 0) { 2333545Swnj runout = 0; 2343545Swnj wakeup((caddr_t)&runout); 2353545Swnj } 2363545Swnj wantin++; 23733Sbill } 23833Sbill } 23933Sbill 24033Sbill /* 24133Sbill * Set user priority. 24233Sbill * The rescheduling flag (runrun) 24333Sbill * is set if the priority is better 24433Sbill * than the currently running process. 24533Sbill */ 24633Sbill setpri(pp) 2474826Swnj register struct proc *pp; 24833Sbill { 2494826Swnj register int p; 25033Sbill 2513875Swnj p = (pp->p_cpu & 0377)/4; 2521543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 2533530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 2543530Swnj p += 2*4; /* effectively, nice(4) */ 2554826Swnj if (p > 127) 25633Sbill p = 127; 2574826Swnj if (p < curpri) { 25833Sbill runrun++; 2592453Swnj aston(); 2602453Swnj } 26133Sbill pp->p_usrpri = p; 2624826Swnj return (p); 26333Sbill } 26433Sbill 26533Sbill /* 26633Sbill * Create a new process-- the internal version of 26733Sbill * sys fork. 26833Sbill * It returns 1 in the new process, 0 in the old. 26933Sbill */ 27033Sbill newproc(isvfork) 2714826Swnj int isvfork; 27233Sbill { 27333Sbill register struct proc *p; 27433Sbill register struct proc *rpp, *rip; 27533Sbill register int n; 2767698Ssam register struct file *fp; 27733Sbill 27833Sbill p = NULL; 27933Sbill /* 28033Sbill * First, just locate a slot for a process 28133Sbill * and copy the useful info from this process into it. 28233Sbill * The panic "cannot happen" because fork has already 28333Sbill * checked for the existence of a slot. 28433Sbill */ 28533Sbill retry: 28633Sbill mpid++; 2874826Swnj if (mpid >= 30000) { 28833Sbill mpid = 0; 28933Sbill goto retry; 29033Sbill } 2914826Swnj for (rpp = proc; rpp < procNPROC; rpp++) { 2924826Swnj if (rpp->p_stat == NULL && p==NULL) 29333Sbill p = rpp; 29433Sbill if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 29533Sbill goto retry; 29633Sbill } 2974826Swnj if ((rpp = p) == NULL) 29833Sbill panic("no procs"); 29933Sbill 30033Sbill /* 3014826Swnj * Make a proc table entry for the new process. 30233Sbill */ 30333Sbill rip = u.u_procp; 3047485Skre #ifdef QUOTA 3057485Skre (rpp->p_quota = rip->p_quota)->q_cnt++; 3067485Skre #endif 30733Sbill rpp->p_stat = SIDL; 308*8033Sroot timerclear(&rpp->p_realtimer.itimer_value); 3095619Swnj rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 31033Sbill if (isvfork) { 31133Sbill rpp->p_flag |= SVFORK; 31233Sbill rpp->p_ndx = rip->p_ndx; 31333Sbill } else 31433Sbill rpp->p_ndx = rpp - proc; 31533Sbill rpp->p_uid = rip->p_uid; 31633Sbill rpp->p_pgrp = rip->p_pgrp; 31733Sbill rpp->p_nice = rip->p_nice; 31833Sbill rpp->p_textp = isvfork ? 0 : rip->p_textp; 31933Sbill rpp->p_pid = mpid; 32033Sbill rpp->p_ppid = rip->p_pid; 321181Sbill rpp->p_pptr = rip; 3227485Skre rpp->p_osptr = rip->p_cptr; 3237485Skre if (rip->p_cptr) 3247485Skre rip->p_cptr->p_ysptr = rpp; 3257485Skre rpp->p_ysptr = NULL; 3267485Skre rpp->p_cptr = NULL; 3277485Skre rip->p_cptr = rpp; 32833Sbill rpp->p_time = 0; 32933Sbill rpp->p_cpu = 0; 330181Sbill rpp->p_siga0 = rip->p_siga0; 331181Sbill rpp->p_siga1 = rip->p_siga1; 332181Sbill /* take along any pending signals, like stops? */ 33333Sbill if (isvfork) { 33433Sbill rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 33533Sbill rpp->p_szpt = clrnd(ctopt(UPAGES)); 33633Sbill forkstat.cntvfork++; 33733Sbill forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 33833Sbill } else { 33933Sbill rpp->p_tsize = rip->p_tsize; 34033Sbill rpp->p_dsize = rip->p_dsize; 34133Sbill rpp->p_ssize = rip->p_ssize; 34233Sbill rpp->p_szpt = rip->p_szpt; 34333Sbill forkstat.cntfork++; 34433Sbill forkstat.sizfork += rip->p_dsize + rip->p_ssize; 34533Sbill } 34633Sbill rpp->p_rssize = 0; 3473514Sroot rpp->p_maxrss = rip->p_maxrss; 34833Sbill rpp->p_wchan = 0; 34933Sbill rpp->p_slptime = 0; 3501400Sbill rpp->p_pctcpu = 0; 3511400Sbill rpp->p_cpticks = 0; 35233Sbill n = PIDHASH(rpp->p_pid); 35333Sbill p->p_idhash = pidhash[n]; 35433Sbill pidhash[n] = rpp - proc; 3554826Swnj multprog++; 35633Sbill 35733Sbill /* 3584826Swnj * Increase reference counts on shared objects. 35933Sbill */ 3607698Ssam for (n = 0; n < NOFILE; n++) { 3617698Ssam fp = u.u_ofile[n]; 3627698Ssam if (fp == NULL) 3637698Ssam continue; 3647698Ssam fp->f_count++; 3657698Ssam if (u.u_pofile[n]&RDLOCK) 3667698Ssam fp->f_inode->i_rdlockc++; 3677698Ssam if (u.u_pofile[n]&WRLOCK) 3687698Ssam fp->f_inode->i_wrlockc++; 3697698Ssam } 37033Sbill u.u_cdir->i_count++; 37133Sbill if (u.u_rdir) 37233Sbill u.u_rdir->i_count++; 3734826Swnj 37433Sbill /* 37533Sbill * Partially simulate the environment 37633Sbill * of the new process so that when it is actually 37733Sbill * created (by copying) it will look right. 3784826Swnj * This begins the section where we must prevent the parent 3794826Swnj * from being swapped. 38033Sbill */ 3814826Swnj rip->p_flag |= SKEEP; 38233Sbill if (procdup(rpp, isvfork)) 38333Sbill return (1); 38433Sbill 3854826Swnj /* 3864826Swnj * Make child runnable and add to run queue. 3874826Swnj */ 3881788Sbill (void) spl6(); 38933Sbill rpp->p_stat = SRUN; 39033Sbill setrq(rpp); 3911793Sbill (void) spl0(); 3924826Swnj 3934826Swnj /* 3944826Swnj * Cause child to take a non-local goto as soon as it runs. 3954826Swnj * On older systems this was done with SSWAP bit in proc 3964826Swnj * table; on VAX we use u.u_pcb.pcb_sswap so don't need 3974826Swnj * to do rpp->p_flag |= SSWAP. Actually do nothing here. 3984826Swnj */ 39933Sbill /* rpp->p_flag |= SSWAP; */ 4004826Swnj 4014826Swnj /* 4024826Swnj * Now can be swapped. 4034826Swnj */ 40433Sbill rip->p_flag &= ~SKEEP; 4054826Swnj 4064826Swnj /* 4074826Swnj * If vfork make chain from parent process to child 4084826Swnj * (where virtal memory is temporarily). Wait for 4094826Swnj * child to finish, steal virtual memory back, 4104826Swnj * and wakeup child to let it die. 4114826Swnj */ 41233Sbill if (isvfork) { 41333Sbill u.u_procp->p_xlink = rpp; 41433Sbill u.u_procp->p_flag |= SNOVM; 41533Sbill while (rpp->p_flag & SVFORK) 41633Sbill sleep((caddr_t)rpp, PZERO - 1); 41733Sbill if ((rpp->p_flag & SLOAD) == 0) 41833Sbill panic("newproc vfork"); 41933Sbill uaccess(rpp, Vfmap, &vfutl); 42033Sbill u.u_procp->p_xlink = 0; 42133Sbill vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 42233Sbill u.u_procp->p_flag &= ~SNOVM; 42333Sbill rpp->p_ndx = rpp - proc; 42433Sbill rpp->p_flag |= SVFDONE; 42533Sbill wakeup((caddr_t)rpp); 42633Sbill } 4274826Swnj 4284826Swnj /* 4294826Swnj * 0 return means parent. 4304826Swnj */ 43133Sbill return (0); 43233Sbill } 433