xref: /csrg-svn/sys/kern/kern_synch.c (revision 8033)
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