xref: /csrg-svn/sys/kern/kern_synch.c (revision 5619)
1*5619Swnj /*	kern_synch.c	4.16	82/01/24	*/
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;
464826Swnj 	if (pri > PZERO) {
474826Swnj 		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();
594826Swnj 		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
724826Swnj 	 * there has been a signal, execute non-local goto through
734826Swnj 	 * u.u_qsav, aborting the system call in progress (see trap.c)
744826Swnj 	 * (or finishing a tsleep, see below)
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
884826Swnj  *
894826Swnj  * SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN
904826Swnj  * INCREMENT IN MILLISECONDS!
91100Sbill  */
92100Sbill tsleep(chan, pri, seconds)
934826Swnj 	caddr_t chan;
944826Swnj 	int pri, seconds;
95100Sbill {
96100Sbill 	label_t lqsav;
97100Sbill 	register struct proc *pp;
98100Sbill 	register sec, n, rval;
99100Sbill 
100100Sbill 	pp = u.u_procp;
101102Sbill 	n = spl7();
102100Sbill 	sec = 0;
103100Sbill 	rval = 0;
104100Sbill 	if (pp->p_clktim && pp->p_clktim<seconds)
105100Sbill 		seconds = 0;
106100Sbill 	if (seconds) {
107100Sbill 		pp->p_flag |= STIMO;
108103Sbill 		sec = pp->p_clktim-seconds;
109100Sbill 		pp->p_clktim = seconds;
110100Sbill 	}
111100Sbill 	bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
112100Sbill 	if (setjmp(u.u_qsav))
113100Sbill 		rval = TS_SIG;
114100Sbill 	else {
115100Sbill 		sleep(chan, pri);
116100Sbill 		if ((pp->p_flag&STIMO)==0 && seconds)
117100Sbill 			rval = TS_TIME;
118100Sbill 		else
119100Sbill 			rval = TS_OK;
120100Sbill 	}
121100Sbill 	pp->p_flag &= ~STIMO;
122100Sbill 	bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
123103Sbill 	if (sec > 0)
124103Sbill 		pp->p_clktim += sec;
125103Sbill 	else
126103Sbill 		pp->p_clktim = 0;
127100Sbill 	splx(n);
1284826Swnj 	return (rval);
129100Sbill }
130100Sbill 
131100Sbill /*
132181Sbill  * Remove a process from its wait queue
133181Sbill  */
134181Sbill unsleep(p)
1354826Swnj 	register struct proc *p;
136181Sbill {
137181Sbill 	register struct proc **hp;
138181Sbill 	register s;
139181Sbill 
140181Sbill 	s = spl6();
141181Sbill 	if (p->p_wchan) {
142181Sbill 		hp = &slpque[HASH(p->p_wchan)];
143181Sbill 		while (*hp != p)
144181Sbill 			hp = &(*hp)->p_link;
145181Sbill 		*hp = p->p_link;
146181Sbill 		p->p_wchan = 0;
147181Sbill 	}
148181Sbill 	splx(s);
149181Sbill }
150181Sbill 
151181Sbill /*
15233Sbill  * Wake up all processes sleeping on chan.
15333Sbill  */
15433Sbill wakeup(chan)
1554826Swnj 	register caddr_t chan;
15633Sbill {
157187Sbill 	register struct proc *p, **q, **h;
15833Sbill 	int s;
15933Sbill 
16033Sbill 	s = spl6();
161187Sbill 	h = &slpque[HASH(chan)];
16233Sbill restart:
163187Sbill 	for (q = h; p = *q; ) {
164181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
16533Sbill 			panic("wakeup");
166207Sbill 		if (p->p_wchan==chan) {
16733Sbill 			p->p_wchan = 0;
168187Sbill 			*q = p->p_link;
16933Sbill 			p->p_slptime = 0;
170181Sbill 			if (p->p_stat == SSLEEP) {
171181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
172181Sbill 				p->p_stat = SRUN;
1732702Swnj 				if (p->p_flag & SLOAD)
174181Sbill 					setrq(p);
1754826Swnj 				if (p->p_pri < curpri) {
176181Sbill 					runrun++;
1772443Swnj 					aston();
1782443Swnj 				}
1793545Swnj 				if ((p->p_flag&SLOAD) == 0) {
1803545Swnj 					if (runout != 0) {
1813545Swnj 						runout = 0;
1823545Swnj 						wakeup((caddr_t)&runout);
1833545Swnj 					}
1843545Swnj 					wantin++;
185181Sbill 				}
186181Sbill 				/* END INLINE EXPANSION */
187187Sbill 				goto restart;
18833Sbill 			}
189187Sbill 		} else
190187Sbill 			q = &p->p_link;
19133Sbill 	}
19233Sbill 	splx(s);
19333Sbill }
19433Sbill 
19533Sbill /*
19633Sbill  * Initialize the (doubly-linked) run queues
19733Sbill  * to be empty.
19833Sbill  */
19933Sbill rqinit()
20033Sbill {
20133Sbill 	register int i;
20233Sbill 
20333Sbill 	for (i = 0; i < NQS; i++)
20433Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
20533Sbill }
20633Sbill 
20733Sbill /*
20833Sbill  * Set the process running;
20933Sbill  * arrange for it to be swapped in if necessary.
21033Sbill  */
21133Sbill setrun(p)
2124826Swnj 	register struct proc *p;
21333Sbill {
2144826Swnj 	register int s;
21533Sbill 
21633Sbill 	s = spl6();
21733Sbill 	switch (p->p_stat) {
21833Sbill 
21933Sbill 	case 0:
22033Sbill 	case SWAIT:
22133Sbill 	case SRUN:
22233Sbill 	case SZOMB:
22333Sbill 	default:
22433Sbill 		panic("setrun");
22533Sbill 
226207Sbill 	case SSTOP:
22733Sbill 	case SSLEEP:
228181Sbill 		unsleep(p);		/* e.g. when sending signals */
22933Sbill 		break;
23033Sbill 
23133Sbill 	case SIDL:
23233Sbill 		break;
23333Sbill 	}
23433Sbill 	p->p_stat = SRUN;
23533Sbill 	if (p->p_flag & SLOAD)
23633Sbill 		setrq(p);
23733Sbill 	splx(s);
2384826Swnj 	if (p->p_pri < curpri) {
23933Sbill 		runrun++;
2402443Swnj 		aston();
2412443Swnj 	}
2423545Swnj 	if ((p->p_flag&SLOAD) == 0) {
2434826Swnj 		if (runout != 0) {
2443545Swnj 			runout = 0;
2453545Swnj 			wakeup((caddr_t)&runout);
2463545Swnj 		}
2473545Swnj 		wantin++;
24833Sbill 	}
24933Sbill }
25033Sbill 
25133Sbill /*
25233Sbill  * Set user priority.
25333Sbill  * The rescheduling flag (runrun)
25433Sbill  * is set if the priority is better
25533Sbill  * than the currently running process.
25633Sbill  */
25733Sbill setpri(pp)
2584826Swnj 	register struct proc *pp;
25933Sbill {
2604826Swnj 	register int p;
26133Sbill 
2623875Swnj 	p = (pp->p_cpu & 0377)/4;
2631543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
2643530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
2653530Swnj 		p += 2*4;	/* effectively, nice(4) */
2664826Swnj 	if (p > 127)
26733Sbill 		p = 127;
2684826Swnj 	if (p < curpri) {
26933Sbill 		runrun++;
2702453Swnj 		aston();
2712453Swnj 	}
27233Sbill 	pp->p_usrpri = p;
2734826Swnj 	return (p);
27433Sbill }
27533Sbill 
27633Sbill /*
27733Sbill  * Create a new process-- the internal version of
27833Sbill  * sys fork.
27933Sbill  * It returns 1 in the new process, 0 in the old.
28033Sbill  */
28133Sbill newproc(isvfork)
2824826Swnj 	int isvfork;
28333Sbill {
28433Sbill 	register struct proc *p;
28533Sbill 	register struct proc *rpp, *rip;
28633Sbill 	register int n;
28733Sbill 
28833Sbill 	p = NULL;
28933Sbill 	/*
29033Sbill 	 * First, just locate a slot for a process
29133Sbill 	 * and copy the useful info from this process into it.
29233Sbill 	 * The panic "cannot happen" because fork has already
29333Sbill 	 * checked for the existence of a slot.
29433Sbill 	 */
29533Sbill retry:
29633Sbill 	mpid++;
2974826Swnj 	if (mpid >= 30000) {
29833Sbill 		mpid = 0;
29933Sbill 		goto retry;
30033Sbill 	}
3014826Swnj 	for (rpp = proc; rpp < procNPROC; rpp++) {
3024826Swnj 		if (rpp->p_stat == NULL && p==NULL)
30333Sbill 			p = rpp;
30433Sbill 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
30533Sbill 			goto retry;
30633Sbill 	}
3074826Swnj 	if ((rpp = p) == NULL)
30833Sbill 		panic("no procs");
30933Sbill 
31033Sbill 	/*
3114826Swnj 	 * Make a proc table entry for the new process.
31233Sbill 	 */
31333Sbill 	rip = u.u_procp;
31433Sbill 	rpp->p_stat = SIDL;
31533Sbill 	rpp->p_clktim = 0;
316*5619Swnj 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG));
31733Sbill 	if (isvfork) {
31833Sbill 		rpp->p_flag |= SVFORK;
31933Sbill 		rpp->p_ndx = rip->p_ndx;
32033Sbill 	} else
32133Sbill 		rpp->p_ndx = rpp - proc;
32233Sbill 	rpp->p_uid = rip->p_uid;
32333Sbill 	rpp->p_pgrp = rip->p_pgrp;
32433Sbill 	rpp->p_nice = rip->p_nice;
32533Sbill 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
32633Sbill 	rpp->p_pid = mpid;
32733Sbill 	rpp->p_ppid = rip->p_pid;
328181Sbill 	rpp->p_pptr = rip;
32933Sbill 	rpp->p_time = 0;
33033Sbill 	rpp->p_cpu = 0;
331181Sbill 	rpp->p_siga0 = rip->p_siga0;
332181Sbill 	rpp->p_siga1 = rip->p_siga1;
333181Sbill 	/* take along any pending signals, like stops? */
33433Sbill 	if (isvfork) {
33533Sbill 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
33633Sbill 		rpp->p_szpt = clrnd(ctopt(UPAGES));
33733Sbill 		forkstat.cntvfork++;
33833Sbill 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
33933Sbill 	} else {
34033Sbill 		rpp->p_tsize = rip->p_tsize;
34133Sbill 		rpp->p_dsize = rip->p_dsize;
34233Sbill 		rpp->p_ssize = rip->p_ssize;
34333Sbill 		rpp->p_szpt = rip->p_szpt;
34433Sbill 		forkstat.cntfork++;
34533Sbill 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
34633Sbill 	}
34733Sbill 	rpp->p_rssize = 0;
3483514Sroot 	rpp->p_maxrss = rip->p_maxrss;
34933Sbill 	rpp->p_wchan = 0;
35033Sbill 	rpp->p_slptime = 0;
3511400Sbill 	rpp->p_pctcpu = 0;
3521400Sbill 	rpp->p_cpticks = 0;
35333Sbill 	n = PIDHASH(rpp->p_pid);
35433Sbill 	p->p_idhash = pidhash[n];
35533Sbill 	pidhash[n] = rpp - proc;
3564826Swnj 	multprog++;
35733Sbill 
35833Sbill 	/*
3594826Swnj 	 * Increase reference counts on shared objects.
36033Sbill 	 */
36133Sbill 	for(n=0; n<NOFILE; n++)
3624826Swnj 		if (u.u_ofile[n] != NULL)
3632938Swnj 			u.u_ofile[n]->f_count++;
36433Sbill 	u.u_cdir->i_count++;
36533Sbill 	if (u.u_rdir)
36633Sbill 		u.u_rdir->i_count++;
3674826Swnj 
36833Sbill 	/*
36933Sbill 	 * Partially simulate the environment
37033Sbill 	 * of the new process so that when it is actually
37133Sbill 	 * created (by copying) it will look right.
3724826Swnj 	 * This begins the section where we must prevent the parent
3734826Swnj 	 * from being swapped.
37433Sbill 	 */
3754826Swnj 	rip->p_flag |= SKEEP;
37633Sbill 	if (procdup(rpp, isvfork))
37733Sbill 		return (1);
37833Sbill 
3794826Swnj 	/*
3804826Swnj 	 * Make child runnable and add to run queue.
3814826Swnj 	 */
3821788Sbill 	(void) spl6();
38333Sbill 	rpp->p_stat = SRUN;
38433Sbill 	setrq(rpp);
3851793Sbill 	(void) spl0();
3864826Swnj 
3874826Swnj 	/*
3884826Swnj 	 * Cause child to take a non-local goto as soon as it runs.
3894826Swnj 	 * On older systems this was done with SSWAP bit in proc
3904826Swnj 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
3914826Swnj 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
3924826Swnj 	 */
39333Sbill 	/* rpp->p_flag |= SSWAP; */
3944826Swnj 
3954826Swnj 	/*
3964826Swnj 	 * Now can be swapped.
3974826Swnj 	 */
39833Sbill 	rip->p_flag &= ~SKEEP;
3994826Swnj 
4004826Swnj 	/*
4014826Swnj 	 * If vfork make chain from parent process to child
4024826Swnj 	 * (where virtal memory is temporarily).  Wait for
4034826Swnj 	 * child to finish, steal virtual memory back,
4044826Swnj 	 * and wakeup child to let it die.
4054826Swnj 	 */
40633Sbill 	if (isvfork) {
40733Sbill 		u.u_procp->p_xlink = rpp;
40833Sbill 		u.u_procp->p_flag |= SNOVM;
40933Sbill 		while (rpp->p_flag & SVFORK)
41033Sbill 			sleep((caddr_t)rpp, PZERO - 1);
41133Sbill 		if ((rpp->p_flag & SLOAD) == 0)
41233Sbill 			panic("newproc vfork");
41333Sbill 		uaccess(rpp, Vfmap, &vfutl);
41433Sbill 		u.u_procp->p_xlink = 0;
41533Sbill 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
41633Sbill 		u.u_procp->p_flag &= ~SNOVM;
41733Sbill 		rpp->p_ndx = rpp - proc;
41833Sbill 		rpp->p_flag |= SVFDONE;
41933Sbill 		wakeup((caddr_t)rpp);
42033Sbill 	}
4214826Swnj 
4224826Swnj 	/*
4234826Swnj 	 * 0 return means parent.
4244826Swnj 	 */
42533Sbill 	return (0);
42633Sbill }
427