xref: /csrg-svn/sys/kern/kern_synch.c (revision 2453)
1*2453Swnj /*	kern_synch.c	4.6	02/16/81	*/
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;
4633Sbill 	if(pri > PZERO) {
47181Sbill 		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();
59181Sbill 		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
7233Sbill 	 * there has been a signal,
7333Sbill 	 * execute non-local goto to
7433Sbill 	 * the qsav location.
7533Sbill 	 * (see trap1/trap.c)
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
89100Sbill  */
90100Sbill tsleep(chan, pri, seconds)
91100Sbill caddr_t chan;
92100Sbill {
93100Sbill 	label_t lqsav;
94100Sbill 	register struct proc *pp;
95100Sbill 	register sec, n, rval;
96100Sbill 
97100Sbill 	pp = u.u_procp;
98102Sbill 	n = spl7();
99100Sbill 	sec = 0;
100100Sbill 	rval = 0;
101100Sbill 	if (pp->p_clktim && pp->p_clktim<seconds)
102100Sbill 		seconds = 0;
103100Sbill 	if (seconds) {
104100Sbill 		pp->p_flag |= STIMO;
105103Sbill 		sec = pp->p_clktim-seconds;
106100Sbill 		pp->p_clktim = seconds;
107100Sbill 	}
108100Sbill 	bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
109100Sbill 	if (setjmp(u.u_qsav))
110100Sbill 		rval = TS_SIG;
111100Sbill 	else {
112100Sbill 		sleep(chan, pri);
113100Sbill 		if ((pp->p_flag&STIMO)==0 && seconds)
114100Sbill 			rval = TS_TIME;
115100Sbill 		else
116100Sbill 			rval = TS_OK;
117100Sbill 	}
118100Sbill 	pp->p_flag &= ~STIMO;
119100Sbill 	bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
120103Sbill 	if (sec > 0)
121103Sbill 		pp->p_clktim += sec;
122103Sbill 	else
123103Sbill 		pp->p_clktim = 0;
124100Sbill 	splx(n);
125100Sbill 	return(rval);
126100Sbill }
127100Sbill 
128100Sbill /*
129181Sbill  * Remove a process from its wait queue
130181Sbill  */
131181Sbill unsleep(p)
132181Sbill register struct proc *p;
133181Sbill {
134181Sbill 	register struct proc **hp;
135181Sbill 	register s;
136181Sbill 
137181Sbill 	s = spl6();
138181Sbill 	if (p->p_wchan) {
139181Sbill 		hp = &slpque[HASH(p->p_wchan)];
140181Sbill 		while (*hp != p)
141181Sbill 			hp = &(*hp)->p_link;
142181Sbill 		*hp = p->p_link;
143181Sbill 		p->p_wchan = 0;
144181Sbill 	}
145181Sbill 	splx(s);
146181Sbill }
147181Sbill 
148181Sbill /*
14933Sbill  * Wake up all processes sleeping on chan.
15033Sbill  */
15133Sbill wakeup(chan)
15233Sbill register caddr_t chan;
15333Sbill {
154187Sbill 	register struct proc *p, **q, **h;
15533Sbill 	int s;
15633Sbill 
15733Sbill 	s = spl6();
158187Sbill 	h = &slpque[HASH(chan)];
15933Sbill restart:
160187Sbill 	for (q = h; p = *q; ) {
161181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
16233Sbill 			panic("wakeup");
163207Sbill 		if (p->p_wchan==chan) {
16433Sbill 			p->p_wchan = 0;
165187Sbill 			*q = p->p_link;
16633Sbill 			p->p_slptime = 0;
167181Sbill 			if (p->p_stat == SSLEEP) {
168181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
169181Sbill 				p->p_stat = SRUN;
170181Sbill 				if (p->p_flag & SLOAD) {
17133Sbill #ifndef FASTVAX
172181Sbill 					p->p_link = runq;
173181Sbill 					runq = p->p_link;
17433Sbill #else
175181Sbill 					setrq(p);
17633Sbill #endif
177181Sbill 				}
1782443Swnj 				if(p->p_pri < curpri) {
179181Sbill 					runrun++;
1802443Swnj 					aston();
1812443Swnj 				}
182181Sbill 				if(runout != 0 && (p->p_flag&SLOAD) == 0) {
183181Sbill 					runout = 0;
184181Sbill 					wakeup((caddr_t)&runout);
185181Sbill 				}
186181Sbill 				/* END INLINE EXPANSION */
187187Sbill 				goto restart;
18833Sbill 			}
189187Sbill 		} else
190187Sbill 			q = &p->p_link;
19133Sbill 	}
19233Sbill 	splx(s);
19333Sbill }
19433Sbill 
19533Sbill #ifdef FASTVAX
19633Sbill /*
19733Sbill  * Initialize the (doubly-linked) run queues
19833Sbill  * to be empty.
19933Sbill  */
20033Sbill rqinit()
20133Sbill {
20233Sbill 	register int i;
20333Sbill 
20433Sbill 	for (i = 0; i < NQS; i++)
20533Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
20633Sbill }
20733Sbill #endif
20833Sbill 
20933Sbill /*
21033Sbill  * Set the process running;
21133Sbill  * arrange for it to be swapped in if necessary.
21233Sbill  */
21333Sbill setrun(p)
21433Sbill register struct proc *p;
21533Sbill {
21633Sbill 	register s;
21733Sbill 
21833Sbill 	s = spl6();
21933Sbill 	switch (p->p_stat) {
22033Sbill 
22133Sbill 	case 0:
22233Sbill 	case SWAIT:
22333Sbill 	case SRUN:
22433Sbill 	case SZOMB:
22533Sbill 	default:
22633Sbill 		panic("setrun");
22733Sbill 
228207Sbill 	case SSTOP:
22933Sbill 	case SSLEEP:
230181Sbill 		unsleep(p);		/* e.g. when sending signals */
23133Sbill 		break;
23233Sbill 
23333Sbill 	case SIDL:
23433Sbill 		break;
23533Sbill 	}
23633Sbill 	p->p_stat = SRUN;
23733Sbill 	if (p->p_flag & SLOAD)
23833Sbill 		setrq(p);
23933Sbill 	splx(s);
2402443Swnj 	if(p->p_pri < curpri) {
24133Sbill 		runrun++;
2422443Swnj 		aston();
2432443Swnj 	}
24433Sbill 	if(runout != 0 && (p->p_flag&SLOAD) == 0) {
24533Sbill 		runout = 0;
24633Sbill 		wakeup((caddr_t)&runout);
24733Sbill 	}
24833Sbill }
24933Sbill 
25033Sbill /*
25133Sbill  * Set user priority.
25233Sbill  * The rescheduling flag (runrun)
25333Sbill  * is set if the priority is better
25433Sbill  * than the currently running process.
25533Sbill  */
25633Sbill setpri(pp)
25733Sbill register struct proc *pp;
25833Sbill {
25933Sbill 	register p;
26033Sbill 
26133Sbill 	p = (pp->p_cpu & 0377)/16;
2621543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
26333Sbill 	if(p > 127)
26433Sbill 		p = 127;
265*2453Swnj 	if(p < curpri) {
26633Sbill 		runrun++;
267*2453Swnj 		aston();
268*2453Swnj 	}
26933Sbill 	pp->p_usrpri = p;
27033Sbill 	return(p);
27133Sbill }
27233Sbill 
27333Sbill /*
27433Sbill  * Create a new process-- the internal version of
27533Sbill  * sys fork.
27633Sbill  * It returns 1 in the new process, 0 in the old.
27733Sbill  */
27833Sbill newproc(isvfork)
27933Sbill {
28033Sbill 	register struct proc *p;
28133Sbill 	register struct proc *rpp, *rip;
28233Sbill 	register int n;
28333Sbill 
28433Sbill 	p = NULL;
28533Sbill 	/*
28633Sbill 	 * First, just locate a slot for a process
28733Sbill 	 * and copy the useful info from this process into it.
28833Sbill 	 * The panic "cannot happen" because fork has already
28933Sbill 	 * checked for the existence of a slot.
29033Sbill 	 */
29133Sbill retry:
29233Sbill 	mpid++;
29333Sbill 	if(mpid >= 30000) {
29433Sbill 		mpid = 0;
29533Sbill 		goto retry;
29633Sbill 	}
29733Sbill 	for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
29833Sbill 		if(rpp->p_stat == NULL && p==NULL)
29933Sbill 			p = rpp;
30033Sbill 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
30133Sbill 			goto retry;
30233Sbill 	}
30333Sbill 	if ((rpp = p)==NULL)
30433Sbill 		panic("no procs");
30533Sbill 
30633Sbill 	/*
30733Sbill 	 * make proc entry for new proc
30833Sbill 	 */
30933Sbill 
31033Sbill 	rip = u.u_procp;
31133Sbill 	rpp->p_stat = SIDL;
31233Sbill 	rpp->p_clktim = 0;
313913Sbill 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SDETACH|SNUSIG));
31433Sbill 	if (isvfork) {
31533Sbill 		rpp->p_flag |= SVFORK;
31633Sbill 		rpp->p_ndx = rip->p_ndx;
31733Sbill 	} else
31833Sbill 		rpp->p_ndx = rpp - proc;
31933Sbill 	rpp->p_uid = rip->p_uid;
32033Sbill 	rpp->p_pgrp = rip->p_pgrp;
32133Sbill 	rpp->p_nice = rip->p_nice;
32233Sbill 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
32333Sbill 	rpp->p_pid = mpid;
32433Sbill 	rpp->p_ppid = rip->p_pid;
325181Sbill 	rpp->p_pptr = rip;
32633Sbill 	rpp->p_time = 0;
32733Sbill 	rpp->p_cpu = 0;
328181Sbill 	rpp->p_siga0 = rip->p_siga0;
329181Sbill 	rpp->p_siga1 = rip->p_siga1;
330181Sbill 	/* take along any pending signals, like stops? */
33133Sbill 	if (isvfork) {
33233Sbill 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
33333Sbill 		rpp->p_szpt = clrnd(ctopt(UPAGES));
33433Sbill 		forkstat.cntvfork++;
33533Sbill 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
33633Sbill 	} else {
33733Sbill 		rpp->p_tsize = rip->p_tsize;
33833Sbill 		rpp->p_dsize = rip->p_dsize;
33933Sbill 		rpp->p_ssize = rip->p_ssize;
34033Sbill 		rpp->p_szpt = rip->p_szpt;
34133Sbill 		forkstat.cntfork++;
34233Sbill 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
34333Sbill 	}
34433Sbill 	rpp->p_rssize = 0;
34533Sbill 	rpp->p_wchan = 0;
34633Sbill 	rpp->p_slptime = 0;
3471400Sbill 	rpp->p_pctcpu = 0;
3481400Sbill 	rpp->p_cpticks = 0;
34933Sbill 	n = PIDHASH(rpp->p_pid);
35033Sbill 	p->p_idhash = pidhash[n];
35133Sbill 	pidhash[n] = rpp - proc;
35233Sbill 
35333Sbill 	/*
35433Sbill 	 * make duplicate entries
35533Sbill 	 * where needed
35633Sbill 	 */
35733Sbill 
35833Sbill 	multprog++;
35933Sbill 
36033Sbill 	for(n=0; n<NOFILE; n++)
36133Sbill 		if(u.u_ofile[n] != NULL) {
3622329Swnj #ifdef UCBIPC
3632329Swnj 			if (u.u_pofile[n] & ISPORT)
3642329Swnj 				u.u_oport[n]->pt_count++;
3652329Swnj 			else {
3662329Swnj #endif
3672329Swnj 				u.u_ofile[n]->f_count++;
3682329Swnj 				if(!isvfork && u.u_vrpages[n])
3692329Swnj 					u.u_ofile[n]->f_inode->i_vfdcnt++;
3702329Swnj #ifdef UCBIPC
3712329Swnj 			}
3722329Swnj #endif UCBIPC
37333Sbill 		}
37433Sbill 
37533Sbill 	u.u_cdir->i_count++;
37633Sbill 	if (u.u_rdir)
37733Sbill 		u.u_rdir->i_count++;
37833Sbill 	/*
37933Sbill 	 * Partially simulate the environment
38033Sbill 	 * of the new process so that when it is actually
38133Sbill 	 * created (by copying) it will look right.
38233Sbill 	 */
38333Sbill 
38433Sbill 	rip->p_flag |= SKEEP;	/* prevent parent from being swapped */
38533Sbill 
38633Sbill 	if (procdup(rpp, isvfork))
38733Sbill 		return (1);
38833Sbill 
3891788Sbill 	(void) spl6();
39033Sbill 	rpp->p_stat = SRUN;
39133Sbill 	setrq(rpp);
3921793Sbill 	(void) spl0();
39388Sbill 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
39433Sbill 	/* rpp->p_flag |= SSWAP; */
39533Sbill 	rip->p_flag &= ~SKEEP;
39633Sbill 	if (isvfork) {
39733Sbill 		u.u_procp->p_xlink = rpp;
39833Sbill 		u.u_procp->p_flag |= SNOVM;
39933Sbill 		while (rpp->p_flag & SVFORK)
40033Sbill 			sleep((caddr_t)rpp, PZERO - 1);
40133Sbill 		if ((rpp->p_flag & SLOAD) == 0)
40233Sbill 			panic("newproc vfork");
40333Sbill 		uaccess(rpp, Vfmap, &vfutl);
40433Sbill 		u.u_procp->p_xlink = 0;
40533Sbill 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
40633Sbill 		for (n = 0; n < NOFILE; n++)
40733Sbill 			if (vfutl.u_vrpages[n]) {
40833Sbill 				if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
40933Sbill 					if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
41033Sbill 						panic("newproc i_vfdcnt");
41133Sbill 				vfutl.u_vrpages[n] = 0;
41233Sbill 			}
41333Sbill 		u.u_procp->p_flag &= ~SNOVM;
41433Sbill 		rpp->p_ndx = rpp - proc;
41533Sbill 		rpp->p_flag |= SVFDONE;
41633Sbill 		wakeup((caddr_t)rpp);
41733Sbill 	}
41833Sbill 	return (0);
41933Sbill }
420