xref: /csrg-svn/sys/kern/kern_synch.c (revision 131)
1*131Sbill /*	kern_synch.c	3.7	10/14/12	*/
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"
1233Sbill 
1333Sbill 
1433Sbill #define SQSIZE 0100	/* Must be power of 2 */
1533Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
1633Sbill struct proc *slpque[SQSIZE];
1733Sbill 
1833Sbill /*
1933Sbill  * Give up the processor till a wakeup occurs
2033Sbill  * on chan, at which time the process
2133Sbill  * enters the scheduling queue at priority pri.
2233Sbill  * The most important effect of pri is that when
2333Sbill  * pri<=PZERO a signal cannot disturb the sleep;
2433Sbill  * if pri>PZERO signals will be processed.
2533Sbill  * Callers of this routine must be prepared for
2633Sbill  * premature return, and check that the reason for
2733Sbill  * sleeping has gone away.
2833Sbill  */
2933Sbill sleep(chan, pri)
3033Sbill caddr_t chan;
3133Sbill {
3233Sbill 	register struct proc *rp;
3333Sbill 	register s, h;
3433Sbill 
3533Sbill 	rp = u.u_procp;
3633Sbill 	s = spl6();
3733Sbill 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
3833Sbill 		panic("sleep");
3933Sbill 	rp->p_stat = SSLEEP;
4033Sbill 	rp->p_wchan = chan;
4133Sbill 	rp->p_slptime = 0;
4233Sbill 	rp->p_pri = pri;
4333Sbill 	h = HASH(chan);
4433Sbill 	rp->p_link = slpque[h];
4533Sbill 	slpque[h] = rp;
4633Sbill 	if(pri > PZERO) {
4733Sbill 		if(rp->p_sig && issig()) {
4833Sbill 			rp->p_wchan = 0;
4933Sbill 			rp->p_stat = SRUN;
5033Sbill 			slpque[h] = rp->p_link;
51*131Sbill 			(void) spl0();
5233Sbill 			goto psig;
5333Sbill 		}
54*131Sbill 		(void) spl0();
5533Sbill 		if(runin != 0) {
5633Sbill 			runin = 0;
5733Sbill 			wakeup((caddr_t)&runin);
5833Sbill 		}
5933Sbill 		swtch();
6033Sbill 		if(rp->p_sig && issig())
6133Sbill 			goto psig;
6233Sbill 	} else {
63*131Sbill 		(void) spl0();
6433Sbill 		swtch();
6533Sbill 	}
6633Sbill 	splx(s);
6733Sbill 	return;
6833Sbill 
6933Sbill 	/*
7033Sbill 	 * If priority was low (>PZERO) and
7133Sbill 	 * there has been a signal,
7233Sbill 	 * execute non-local goto to
7333Sbill 	 * the qsav location.
7433Sbill 	 * (see trap1/trap.c)
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
88100Sbill  */
89100Sbill tsleep(chan, pri, seconds)
90100Sbill caddr_t chan;
91100Sbill {
92100Sbill 	label_t lqsav;
93100Sbill 	register struct proc *pp;
94100Sbill 	register sec, n, rval;
95100Sbill 
96100Sbill 	pp = u.u_procp;
97102Sbill 	n = spl7();
98100Sbill 	sec = 0;
99100Sbill 	rval = 0;
100100Sbill 	if (pp->p_clktim && pp->p_clktim<seconds)
101100Sbill 		seconds = 0;
102100Sbill 	if (seconds) {
103100Sbill 		pp->p_flag |= STIMO;
104103Sbill 		sec = pp->p_clktim-seconds;
105100Sbill 		pp->p_clktim = seconds;
106100Sbill 	}
107100Sbill 	bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
108100Sbill 	if (setjmp(u.u_qsav))
109100Sbill 		rval = TS_SIG;
110100Sbill 	else {
111100Sbill 		sleep(chan, pri);
112100Sbill 		if ((pp->p_flag&STIMO)==0 && seconds)
113100Sbill 			rval = TS_TIME;
114100Sbill 		else
115100Sbill 			rval = TS_OK;
116100Sbill 	}
117100Sbill 	pp->p_flag &= ~STIMO;
118100Sbill 	bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
119103Sbill 	if (sec > 0)
120103Sbill 		pp->p_clktim += sec;
121103Sbill 	else
122103Sbill 		pp->p_clktim = 0;
123100Sbill 	splx(n);
124100Sbill 	return(rval);
125100Sbill }
126100Sbill 
127100Sbill /*
12833Sbill  * Wake up all processes sleeping on chan.
12933Sbill  */
13033Sbill wakeup(chan)
13133Sbill register caddr_t chan;
13233Sbill {
13333Sbill 	register struct proc *p, *q;
13433Sbill 	register i;
13533Sbill 	int s;
13633Sbill 
13733Sbill 	s = spl6();
13833Sbill 	i = HASH(chan);
13933Sbill restart:
14033Sbill 	p = slpque[i];
14133Sbill 	q = NULL;
14233Sbill 	while(p != NULL) {
14333Sbill 		if (p->p_rlink || p->p_stat != SSLEEP)
14433Sbill 			panic("wakeup");
14533Sbill 		if (p->p_wchan==chan && p->p_stat!=SZOMB) {
14633Sbill 			if (q == NULL)
14733Sbill 				slpque[i] = p->p_link;
14833Sbill 			else
14933Sbill 				q->p_link = p->p_link;
15033Sbill 			p->p_wchan = 0;
15133Sbill 			p->p_slptime = 0;
15233Sbill 			/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
15333Sbill 			p->p_stat = SRUN;
15433Sbill 			if (p->p_flag & SLOAD) {
15533Sbill #ifndef FASTVAX
15633Sbill 				p->p_link = runq;
15733Sbill 				runq = p->p_link;
15833Sbill #else
15933Sbill 				setrq(p);
16033Sbill #endif
16133Sbill 			}
16233Sbill 			if(p->p_pri < curpri)
16333Sbill 				runrun++;
16433Sbill 			if(runout != 0 && (p->p_flag&SLOAD) == 0) {
16533Sbill 				runout = 0;
16633Sbill 				wakeup((caddr_t)&runout);
16733Sbill 			}
16833Sbill 			/* END INLINE EXPANSION */
16933Sbill 			goto restart;
17033Sbill 		}
17133Sbill 		q = p;
17233Sbill 		p = p->p_link;
17333Sbill 	}
17433Sbill 	splx(s);
17533Sbill }
17633Sbill 
17733Sbill #ifdef FASTVAX
17833Sbill /*
17933Sbill  * Initialize the (doubly-linked) run queues
18033Sbill  * to be empty.
18133Sbill  */
18233Sbill rqinit()
18333Sbill {
18433Sbill 	register int i;
18533Sbill 
18633Sbill 	for (i = 0; i < NQS; i++)
18733Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
18833Sbill }
18933Sbill #endif
19033Sbill 
19133Sbill /*
19233Sbill  * Set the process running;
19333Sbill  * arrange for it to be swapped in if necessary.
19433Sbill  */
19533Sbill setrun(p)
19633Sbill register struct proc *p;
19733Sbill {
19833Sbill 	register caddr_t w;
19933Sbill 	register s;
20033Sbill 
20133Sbill 	s = spl6();
20233Sbill 	switch (p->p_stat) {
20333Sbill 
20433Sbill 	case 0:
20533Sbill 	case SWAIT:
20633Sbill 	case SRUN:
20733Sbill 	case SZOMB:
20833Sbill 	default:
20933Sbill 		panic("setrun");
21033Sbill 
21133Sbill 	case SSLEEP:
21233Sbill 		if (w = p->p_wchan) {
21333Sbill 			wakeup(w);
21433Sbill 			splx(s);
21533Sbill 			return;
21633Sbill 		}
21733Sbill 		break;
21833Sbill 
21933Sbill 	case SIDL:
22033Sbill 	case SSTOP:
22133Sbill 		break;
22233Sbill 	}
22333Sbill 	p->p_stat = SRUN;
22433Sbill 	if (p->p_flag & SLOAD)
22533Sbill 		setrq(p);
22633Sbill 	splx(s);
22733Sbill 	if(p->p_pri < curpri)
22833Sbill 		runrun++;
22933Sbill 	if(runout != 0 && (p->p_flag&SLOAD) == 0) {
23033Sbill 		runout = 0;
23133Sbill 		wakeup((caddr_t)&runout);
23233Sbill 	}
23333Sbill }
23433Sbill 
23533Sbill /*
23633Sbill  * Set user priority.
23733Sbill  * The rescheduling flag (runrun)
23833Sbill  * is set if the priority is better
23933Sbill  * than the currently running process.
24033Sbill  */
24133Sbill setpri(pp)
24233Sbill register struct proc *pp;
24333Sbill {
24433Sbill 	register p;
24533Sbill 
24633Sbill 	p = (pp->p_cpu & 0377)/16;
24733Sbill 	p += PUSER + pp->p_nice - NZERO;
24833Sbill 	if(p > 127)
24933Sbill 		p = 127;
25033Sbill 	if(p < curpri)
25133Sbill 		runrun++;
25233Sbill 	pp->p_usrpri = p;
25333Sbill 	return(p);
25433Sbill }
25533Sbill 
25633Sbill /*
25733Sbill  * Create a new process-- the internal version of
25833Sbill  * sys fork.
25933Sbill  * It returns 1 in the new process, 0 in the old.
26033Sbill  */
26133Sbill newproc(isvfork)
26233Sbill {
26333Sbill 	register struct proc *p;
26433Sbill 	register struct proc *rpp, *rip;
26533Sbill 	register int n;
26633Sbill 
26733Sbill 	p = NULL;
26833Sbill 	/*
26933Sbill 	 * First, just locate a slot for a process
27033Sbill 	 * and copy the useful info from this process into it.
27133Sbill 	 * The panic "cannot happen" because fork has already
27233Sbill 	 * checked for the existence of a slot.
27333Sbill 	 */
27433Sbill retry:
27533Sbill 	mpid++;
27633Sbill 	if(mpid >= 30000) {
27733Sbill 		mpid = 0;
27833Sbill 		goto retry;
27933Sbill 	}
28033Sbill 	for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
28133Sbill 		if(rpp->p_stat == NULL && p==NULL)
28233Sbill 			p = rpp;
28333Sbill 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
28433Sbill 			goto retry;
28533Sbill 	}
28633Sbill 	if ((rpp = p)==NULL)
28733Sbill 		panic("no procs");
28833Sbill 
28933Sbill 	/*
29033Sbill 	 * make proc entry for new proc
29133Sbill 	 */
29233Sbill 
29333Sbill 	rip = u.u_procp;
29433Sbill 	rpp->p_stat = SIDL;
29533Sbill 	rpp->p_clktim = 0;
29633Sbill 	rpp->p_flag = SLOAD | (rip->p_flag & SPAGI);
29733Sbill 	if (isvfork) {
29833Sbill 		rpp->p_flag |= SVFORK;
29933Sbill 		rpp->p_ndx = rip->p_ndx;
30033Sbill 	} else
30133Sbill 		rpp->p_ndx = rpp - proc;
30233Sbill 	rpp->p_uid = rip->p_uid;
30333Sbill 	rpp->p_pgrp = rip->p_pgrp;
30433Sbill 	rpp->p_nice = rip->p_nice;
30533Sbill 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
30633Sbill 	rpp->p_pid = mpid;
30733Sbill 	rpp->p_ppid = rip->p_pid;
30833Sbill 	rpp->p_time = 0;
30933Sbill 	rpp->p_cpu = 0;
31033Sbill 	if (isvfork) {
31133Sbill 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
31233Sbill 		rpp->p_szpt = clrnd(ctopt(UPAGES));
31333Sbill 		forkstat.cntvfork++;
31433Sbill 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
31533Sbill 	} else {
31633Sbill 		rpp->p_tsize = rip->p_tsize;
31733Sbill 		rpp->p_dsize = rip->p_dsize;
31833Sbill 		rpp->p_ssize = rip->p_ssize;
31933Sbill 		rpp->p_szpt = rip->p_szpt;
32033Sbill 		forkstat.cntfork++;
32133Sbill 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
32233Sbill 	}
32333Sbill 	rpp->p_rssize = 0;
32433Sbill 	rpp->p_wchan = 0;
32533Sbill 	rpp->p_slptime = 0;
32633Sbill 	rpp->p_aveflt = rip->p_aveflt;
32733Sbill 	rate.v_pgin += rip->p_aveflt;
32833Sbill 	rpp->p_faults = 0;
32933Sbill 	n = PIDHASH(rpp->p_pid);
33033Sbill 	p->p_idhash = pidhash[n];
33133Sbill 	pidhash[n] = rpp - proc;
33233Sbill 
33333Sbill 	/*
33433Sbill 	 * make duplicate entries
33533Sbill 	 * where needed
33633Sbill 	 */
33733Sbill 
33833Sbill 	multprog++;
33933Sbill 
34033Sbill 	for(n=0; n<NOFILE; n++)
34133Sbill 		if(u.u_ofile[n] != NULL) {
34233Sbill 			u.u_ofile[n]->f_count++;
34333Sbill 			if(!isvfork && u.u_vrpages[n])
34433Sbill 				u.u_ofile[n]->f_inode->i_vfdcnt++;
34533Sbill 		}
34633Sbill 
34733Sbill 	u.u_cdir->i_count++;
34833Sbill 	if (u.u_rdir)
34933Sbill 		u.u_rdir->i_count++;
35033Sbill 	/*
35133Sbill 	 * Partially simulate the environment
35233Sbill 	 * of the new process so that when it is actually
35333Sbill 	 * created (by copying) it will look right.
35433Sbill 	 */
35533Sbill 
35633Sbill 	rip->p_flag |= SKEEP;	/* prevent parent from being swapped */
35733Sbill 
35833Sbill 	if (procdup(rpp, isvfork))
35933Sbill 		return (1);
36033Sbill 
36133Sbill 	spl6();
36233Sbill 	rpp->p_stat = SRUN;
36333Sbill 	setrq(rpp);
36433Sbill 	spl0();
36588Sbill 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
36633Sbill 	/* rpp->p_flag |= SSWAP; */
36733Sbill 	rip->p_flag &= ~SKEEP;
36833Sbill 	if (isvfork) {
36933Sbill 		u.u_procp->p_xlink = rpp;
37033Sbill 		u.u_procp->p_flag |= SNOVM;
37133Sbill 		while (rpp->p_flag & SVFORK)
37233Sbill 			sleep((caddr_t)rpp, PZERO - 1);
37333Sbill 		if ((rpp->p_flag & SLOAD) == 0)
37433Sbill 			panic("newproc vfork");
37533Sbill 		uaccess(rpp, Vfmap, &vfutl);
37633Sbill 		u.u_procp->p_xlink = 0;
37733Sbill 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
37833Sbill 		for (n = 0; n < NOFILE; n++)
37933Sbill 			if (vfutl.u_vrpages[n]) {
38033Sbill 				if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
38133Sbill 					if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
38233Sbill 						panic("newproc i_vfdcnt");
38333Sbill 				vfutl.u_vrpages[n] = 0;
38433Sbill 			}
38533Sbill 		u.u_procp->p_flag &= ~SNOVM;
38633Sbill 		rpp->p_ndx = rpp - proc;
38733Sbill 		rpp->p_flag |= SVFDONE;
38833Sbill 		wakeup((caddr_t)rpp);
38933Sbill 	}
39033Sbill 	return (0);
39133Sbill }
392