xref: /csrg-svn/sys/kern/kern_synch.c (revision 7698)
1*7698Ssam /*	kern_synch.c	4.18	82/08/10	*/
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)
3233Sbill caddr_t chan;
3333Sbill {
34187Sbill 	register struct proc *rp, **hp;
35207Sbill 	register s;
3633Sbill 
3733Sbill 	rp = u.u_procp;
3833Sbill 	s = spl6();
3933Sbill 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
4033Sbill 		panic("sleep");
4133Sbill 	rp->p_wchan = chan;
4233Sbill 	rp->p_slptime = 0;
4333Sbill 	rp->p_pri = pri;
44187Sbill 	hp = &slpque[HASH(chan)];
45187Sbill 	rp->p_link = *hp;
46187Sbill 	*hp = rp;
474826Swnj 	if (pri > PZERO) {
484826Swnj 		if (ISSIG(rp)) {
49187Sbill 			if (rp->p_wchan)
50187Sbill 				unsleep(rp);
5133Sbill 			rp->p_stat = SRUN;
52131Sbill 			(void) spl0();
5333Sbill 			goto psig;
5433Sbill 		}
55187Sbill 		if (rp->p_wchan == 0)
56187Sbill 			goto out;
57187Sbill 		rp->p_stat = SSLEEP;
58131Sbill 		(void) spl0();
5933Sbill 		swtch();
604826Swnj 		if (ISSIG(rp))
6133Sbill 			goto psig;
6233Sbill 	} else {
63207Sbill 		rp->p_stat = SSLEEP;
64131Sbill 		(void) spl0();
6533Sbill 		swtch();
6633Sbill 	}
67187Sbill out:
6833Sbill 	splx(s);
6933Sbill 	return;
7033Sbill 
7133Sbill 	/*
7233Sbill 	 * If priority was low (>PZERO) and
734826Swnj 	 * there has been a signal, execute non-local goto through
744826Swnj 	 * u.u_qsav, aborting the system call in progress (see trap.c)
754826Swnj 	 * (or finishing a tsleep, see below)
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
894826Swnj  *
904826Swnj  * SHOULD HAVE OPTION TO SLEEP TO ABSOLUTE TIME OR AN
914826Swnj  * INCREMENT IN MILLISECONDS!
92100Sbill  */
93100Sbill tsleep(chan, pri, seconds)
944826Swnj 	caddr_t chan;
954826Swnj 	int pri, seconds;
96100Sbill {
97100Sbill 	label_t lqsav;
98100Sbill 	register struct proc *pp;
997485Skre 	register sec, n, rval, sov;
100100Sbill 
101100Sbill 	pp = u.u_procp;
102102Sbill 	n = spl7();
103100Sbill 	sec = 0;
104100Sbill 	rval = 0;
1057485Skre 	sov = 0;
106100Sbill 	if (pp->p_clktim && pp->p_clktim<seconds)
1077485Skre 		if (pri > PZERO)
1087485Skre 			seconds = 0;
1097485Skre 		else
1107485Skre 			sov++;
111100Sbill 	if (seconds) {
112100Sbill 		pp->p_flag |= STIMO;
113103Sbill 		sec = pp->p_clktim-seconds;
114100Sbill 		pp->p_clktim = seconds;
115100Sbill 	}
116100Sbill 	bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
117100Sbill 	if (setjmp(u.u_qsav))
118100Sbill 		rval = TS_SIG;
119100Sbill 	else {
120100Sbill 		sleep(chan, pri);
121100Sbill 		if ((pp->p_flag&STIMO)==0 && seconds)
122100Sbill 			rval = TS_TIME;
123100Sbill 		else
124100Sbill 			rval = TS_OK;
125100Sbill 	}
126100Sbill 	pp->p_flag &= ~STIMO;
127100Sbill 	bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
128103Sbill 	if (sec > 0)
129103Sbill 		pp->p_clktim += sec;
1307485Skre 	else if (sov) {
1317485Skre 		if ((pp->p_clktim += sec) <= 0) {
1327485Skre 			pp->p_clktim = 0;
1337485Skre 			psignal(pp, SIGALRM);
1347485Skre 		}
1357485Skre 	} else
136103Sbill 		pp->p_clktim = 0;
137100Sbill 	splx(n);
1384826Swnj 	return (rval);
139100Sbill }
140100Sbill 
141100Sbill /*
142181Sbill  * Remove a process from its wait queue
143181Sbill  */
144181Sbill unsleep(p)
1454826Swnj 	register struct proc *p;
146181Sbill {
147181Sbill 	register struct proc **hp;
148181Sbill 	register s;
149181Sbill 
150181Sbill 	s = spl6();
151181Sbill 	if (p->p_wchan) {
152181Sbill 		hp = &slpque[HASH(p->p_wchan)];
153181Sbill 		while (*hp != p)
154181Sbill 			hp = &(*hp)->p_link;
155181Sbill 		*hp = p->p_link;
156181Sbill 		p->p_wchan = 0;
157181Sbill 	}
158181Sbill 	splx(s);
159181Sbill }
160181Sbill 
161181Sbill /*
16233Sbill  * Wake up all processes sleeping on chan.
16333Sbill  */
16433Sbill wakeup(chan)
1654826Swnj 	register caddr_t chan;
16633Sbill {
167187Sbill 	register struct proc *p, **q, **h;
16833Sbill 	int s;
16933Sbill 
17033Sbill 	s = spl6();
171187Sbill 	h = &slpque[HASH(chan)];
17233Sbill restart:
173187Sbill 	for (q = h; p = *q; ) {
174181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
17533Sbill 			panic("wakeup");
176207Sbill 		if (p->p_wchan==chan) {
17733Sbill 			p->p_wchan = 0;
178187Sbill 			*q = p->p_link;
17933Sbill 			p->p_slptime = 0;
180181Sbill 			if (p->p_stat == SSLEEP) {
181181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
182181Sbill 				p->p_stat = SRUN;
1832702Swnj 				if (p->p_flag & SLOAD)
184181Sbill 					setrq(p);
1854826Swnj 				if (p->p_pri < curpri) {
186181Sbill 					runrun++;
1872443Swnj 					aston();
1882443Swnj 				}
1893545Swnj 				if ((p->p_flag&SLOAD) == 0) {
1903545Swnj 					if (runout != 0) {
1913545Swnj 						runout = 0;
1923545Swnj 						wakeup((caddr_t)&runout);
1933545Swnj 					}
1943545Swnj 					wantin++;
195181Sbill 				}
196181Sbill 				/* END INLINE EXPANSION */
197187Sbill 				goto restart;
19833Sbill 			}
199187Sbill 		} else
200187Sbill 			q = &p->p_link;
20133Sbill 	}
20233Sbill 	splx(s);
20333Sbill }
20433Sbill 
20533Sbill /*
20633Sbill  * Initialize the (doubly-linked) run queues
20733Sbill  * to be empty.
20833Sbill  */
20933Sbill rqinit()
21033Sbill {
21133Sbill 	register int i;
21233Sbill 
21333Sbill 	for (i = 0; i < NQS; i++)
21433Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
21533Sbill }
21633Sbill 
21733Sbill /*
21833Sbill  * Set the process running;
21933Sbill  * arrange for it to be swapped in if necessary.
22033Sbill  */
22133Sbill setrun(p)
2224826Swnj 	register struct proc *p;
22333Sbill {
2244826Swnj 	register int s;
22533Sbill 
22633Sbill 	s = spl6();
22733Sbill 	switch (p->p_stat) {
22833Sbill 
22933Sbill 	case 0:
23033Sbill 	case SWAIT:
23133Sbill 	case SRUN:
23233Sbill 	case SZOMB:
23333Sbill 	default:
23433Sbill 		panic("setrun");
23533Sbill 
236207Sbill 	case SSTOP:
23733Sbill 	case SSLEEP:
238181Sbill 		unsleep(p);		/* e.g. when sending signals */
23933Sbill 		break;
24033Sbill 
24133Sbill 	case SIDL:
24233Sbill 		break;
24333Sbill 	}
24433Sbill 	p->p_stat = SRUN;
24533Sbill 	if (p->p_flag & SLOAD)
24633Sbill 		setrq(p);
24733Sbill 	splx(s);
2484826Swnj 	if (p->p_pri < curpri) {
24933Sbill 		runrun++;
2502443Swnj 		aston();
2512443Swnj 	}
2523545Swnj 	if ((p->p_flag&SLOAD) == 0) {
2534826Swnj 		if (runout != 0) {
2543545Swnj 			runout = 0;
2553545Swnj 			wakeup((caddr_t)&runout);
2563545Swnj 		}
2573545Swnj 		wantin++;
25833Sbill 	}
25933Sbill }
26033Sbill 
26133Sbill /*
26233Sbill  * Set user priority.
26333Sbill  * The rescheduling flag (runrun)
26433Sbill  * is set if the priority is better
26533Sbill  * than the currently running process.
26633Sbill  */
26733Sbill setpri(pp)
2684826Swnj 	register struct proc *pp;
26933Sbill {
2704826Swnj 	register int p;
27133Sbill 
2723875Swnj 	p = (pp->p_cpu & 0377)/4;
2731543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
2743530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
2753530Swnj 		p += 2*4;	/* effectively, nice(4) */
2764826Swnj 	if (p > 127)
27733Sbill 		p = 127;
2784826Swnj 	if (p < curpri) {
27933Sbill 		runrun++;
2802453Swnj 		aston();
2812453Swnj 	}
28233Sbill 	pp->p_usrpri = p;
2834826Swnj 	return (p);
28433Sbill }
28533Sbill 
28633Sbill /*
28733Sbill  * Create a new process-- the internal version of
28833Sbill  * sys fork.
28933Sbill  * It returns 1 in the new process, 0 in the old.
29033Sbill  */
29133Sbill newproc(isvfork)
2924826Swnj 	int isvfork;
29333Sbill {
29433Sbill 	register struct proc *p;
29533Sbill 	register struct proc *rpp, *rip;
29633Sbill 	register int n;
297*7698Ssam 	register struct file *fp;
29833Sbill 
29933Sbill 	p = NULL;
30033Sbill 	/*
30133Sbill 	 * First, just locate a slot for a process
30233Sbill 	 * and copy the useful info from this process into it.
30333Sbill 	 * The panic "cannot happen" because fork has already
30433Sbill 	 * checked for the existence of a slot.
30533Sbill 	 */
30633Sbill retry:
30733Sbill 	mpid++;
3084826Swnj 	if (mpid >= 30000) {
30933Sbill 		mpid = 0;
31033Sbill 		goto retry;
31133Sbill 	}
3124826Swnj 	for (rpp = proc; rpp < procNPROC; rpp++) {
3134826Swnj 		if (rpp->p_stat == NULL && p==NULL)
31433Sbill 			p = rpp;
31533Sbill 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
31633Sbill 			goto retry;
31733Sbill 	}
3184826Swnj 	if ((rpp = p) == NULL)
31933Sbill 		panic("no procs");
32033Sbill 
32133Sbill 	/*
3224826Swnj 	 * Make a proc table entry for the new process.
32333Sbill 	 */
32433Sbill 	rip = u.u_procp;
3257485Skre #ifdef QUOTA
3267485Skre 	(rpp->p_quota = rip->p_quota)->q_cnt++;
3277485Skre #endif
32833Sbill 	rpp->p_stat = SIDL;
32933Sbill 	rpp->p_clktim = 0;
3305619Swnj 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG));
33133Sbill 	if (isvfork) {
33233Sbill 		rpp->p_flag |= SVFORK;
33333Sbill 		rpp->p_ndx = rip->p_ndx;
33433Sbill 	} else
33533Sbill 		rpp->p_ndx = rpp - proc;
33633Sbill 	rpp->p_uid = rip->p_uid;
33733Sbill 	rpp->p_pgrp = rip->p_pgrp;
33833Sbill 	rpp->p_nice = rip->p_nice;
33933Sbill 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
34033Sbill 	rpp->p_pid = mpid;
34133Sbill 	rpp->p_ppid = rip->p_pid;
342181Sbill 	rpp->p_pptr = rip;
3437485Skre 	rpp->p_osptr = rip->p_cptr;
3447485Skre 	if (rip->p_cptr)
3457485Skre 		rip->p_cptr->p_ysptr = rpp;
3467485Skre 	rpp->p_ysptr = NULL;
3477485Skre 	rpp->p_cptr = NULL;
3487485Skre 	rip->p_cptr = rpp;
34933Sbill 	rpp->p_time = 0;
35033Sbill 	rpp->p_cpu = 0;
351181Sbill 	rpp->p_siga0 = rip->p_siga0;
352181Sbill 	rpp->p_siga1 = rip->p_siga1;
353181Sbill 	/* take along any pending signals, like stops? */
35433Sbill 	if (isvfork) {
35533Sbill 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
35633Sbill 		rpp->p_szpt = clrnd(ctopt(UPAGES));
35733Sbill 		forkstat.cntvfork++;
35833Sbill 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
35933Sbill 	} else {
36033Sbill 		rpp->p_tsize = rip->p_tsize;
36133Sbill 		rpp->p_dsize = rip->p_dsize;
36233Sbill 		rpp->p_ssize = rip->p_ssize;
36333Sbill 		rpp->p_szpt = rip->p_szpt;
36433Sbill 		forkstat.cntfork++;
36533Sbill 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
36633Sbill 	}
36733Sbill 	rpp->p_rssize = 0;
3683514Sroot 	rpp->p_maxrss = rip->p_maxrss;
36933Sbill 	rpp->p_wchan = 0;
37033Sbill 	rpp->p_slptime = 0;
3711400Sbill 	rpp->p_pctcpu = 0;
3721400Sbill 	rpp->p_cpticks = 0;
37333Sbill 	n = PIDHASH(rpp->p_pid);
37433Sbill 	p->p_idhash = pidhash[n];
37533Sbill 	pidhash[n] = rpp - proc;
3764826Swnj 	multprog++;
37733Sbill 
37833Sbill 	/*
3794826Swnj 	 * Increase reference counts on shared objects.
38033Sbill 	 */
381*7698Ssam 	for (n = 0; n < NOFILE; n++) {
382*7698Ssam 		fp = u.u_ofile[n];
383*7698Ssam 		if (fp == NULL)
384*7698Ssam 			continue;
385*7698Ssam 		fp->f_count++;
386*7698Ssam 		if (u.u_pofile[n]&RDLOCK)
387*7698Ssam 			fp->f_inode->i_rdlockc++;
388*7698Ssam 		if (u.u_pofile[n]&WRLOCK)
389*7698Ssam 			fp->f_inode->i_wrlockc++;
390*7698Ssam 	}
39133Sbill 	u.u_cdir->i_count++;
39233Sbill 	if (u.u_rdir)
39333Sbill 		u.u_rdir->i_count++;
3944826Swnj 
39533Sbill 	/*
39633Sbill 	 * Partially simulate the environment
39733Sbill 	 * of the new process so that when it is actually
39833Sbill 	 * created (by copying) it will look right.
3994826Swnj 	 * This begins the section where we must prevent the parent
4004826Swnj 	 * from being swapped.
40133Sbill 	 */
4024826Swnj 	rip->p_flag |= SKEEP;
40333Sbill 	if (procdup(rpp, isvfork))
40433Sbill 		return (1);
40533Sbill 
4064826Swnj 	/*
4074826Swnj 	 * Make child runnable and add to run queue.
4084826Swnj 	 */
4091788Sbill 	(void) spl6();
41033Sbill 	rpp->p_stat = SRUN;
41133Sbill 	setrq(rpp);
4121793Sbill 	(void) spl0();
4134826Swnj 
4144826Swnj 	/*
4154826Swnj 	 * Cause child to take a non-local goto as soon as it runs.
4164826Swnj 	 * On older systems this was done with SSWAP bit in proc
4174826Swnj 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
4184826Swnj 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
4194826Swnj 	 */
42033Sbill 	/* rpp->p_flag |= SSWAP; */
4214826Swnj 
4224826Swnj 	/*
4234826Swnj 	 * Now can be swapped.
4244826Swnj 	 */
42533Sbill 	rip->p_flag &= ~SKEEP;
4264826Swnj 
4274826Swnj 	/*
4284826Swnj 	 * If vfork make chain from parent process to child
4294826Swnj 	 * (where virtal memory is temporarily).  Wait for
4304826Swnj 	 * child to finish, steal virtual memory back,
4314826Swnj 	 * and wakeup child to let it die.
4324826Swnj 	 */
43333Sbill 	if (isvfork) {
43433Sbill 		u.u_procp->p_xlink = rpp;
43533Sbill 		u.u_procp->p_flag |= SNOVM;
43633Sbill 		while (rpp->p_flag & SVFORK)
43733Sbill 			sleep((caddr_t)rpp, PZERO - 1);
43833Sbill 		if ((rpp->p_flag & SLOAD) == 0)
43933Sbill 			panic("newproc vfork");
44033Sbill 		uaccess(rpp, Vfmap, &vfutl);
44133Sbill 		u.u_procp->p_xlink = 0;
44233Sbill 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
44333Sbill 		u.u_procp->p_flag &= ~SNOVM;
44433Sbill 		rpp->p_ndx = rpp - proc;
44533Sbill 		rpp->p_flag |= SVFDONE;
44633Sbill 		wakeup((caddr_t)rpp);
44733Sbill 	}
4484826Swnj 
4494826Swnj 	/*
4504826Swnj 	 * 0 return means parent.
4514826Swnj 	 */
45233Sbill 	return (0);
45333Sbill }
454