xref: /csrg-svn/sys/kern/kern_synch.c (revision 88)
1*88Sbill /*	kern_synch.c	3.2	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 #ifdef FASTVAX
1433Sbill asm(" .globl _eintr");
1533Sbill #endif
1633Sbill 
1733Sbill #define SQSIZE 0100	/* Must be power of 2 */
1833Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
1933Sbill struct proc *slpque[SQSIZE];
2033Sbill 
2133Sbill /*
2233Sbill  * Give up the processor till a wakeup occurs
2333Sbill  * on chan, at which time the process
2433Sbill  * enters the scheduling queue at priority pri.
2533Sbill  * The most important effect of pri is that when
2633Sbill  * pri<=PZERO a signal cannot disturb the sleep;
2733Sbill  * if pri>PZERO signals will be processed.
2833Sbill  * Callers of this routine must be prepared for
2933Sbill  * premature return, and check that the reason for
3033Sbill  * sleeping has gone away.
3133Sbill  */
3233Sbill sleep(chan, pri)
3333Sbill caddr_t chan;
3433Sbill {
3533Sbill 	register struct proc *rp;
3633Sbill 	register s, h;
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_stat = SSLEEP;
4333Sbill 	rp->p_wchan = chan;
4433Sbill 	rp->p_slptime = 0;
4533Sbill 	rp->p_pri = pri;
4633Sbill 	h = HASH(chan);
4733Sbill 	rp->p_link = slpque[h];
4833Sbill 	slpque[h] = rp;
4933Sbill 	if(pri > PZERO) {
5033Sbill 		if(rp->p_sig && issig()) {
5133Sbill 			rp->p_wchan = 0;
5233Sbill 			rp->p_stat = SRUN;
5333Sbill 			slpque[h] = rp->p_link;
5433Sbill 			VOID spl0();
5533Sbill 			goto psig;
5633Sbill 		}
5733Sbill 		VOID spl0();
5833Sbill 		if(runin != 0) {
5933Sbill 			runin = 0;
6033Sbill 			wakeup((caddr_t)&runin);
6133Sbill 		}
6233Sbill 		swtch();
6333Sbill 		if(rp->p_sig && issig())
6433Sbill 			goto psig;
6533Sbill 	} else {
6633Sbill 		VOID spl0();
6733Sbill 		swtch();
6833Sbill 	}
6933Sbill 	splx(s);
7033Sbill 	return;
7133Sbill 
7233Sbill 	/*
7333Sbill 	 * If priority was low (>PZERO) and
7433Sbill 	 * there has been a signal,
7533Sbill 	 * execute non-local goto to
7633Sbill 	 * the qsav location.
7733Sbill 	 * (see trap1/trap.c)
7833Sbill 	 */
7933Sbill psig:
8033Sbill #ifndef FASTVAX
8133Sbill 	longjmp(u.u_qsav);
8233Sbill #else
8333Sbill 	asm(".set U_SSAV,140");
8433Sbill 	asm("movl _u+U_SSAV,fp");
8533Sbill 	asm("movl _u+U_SSAV+4,sp");
8633Sbill 	asm("movl _u+U_SSAV+8,r11");
8733Sbill 	u.u_error = EINTR;
8833Sbill 	asm("jmp _eintr");
8933Sbill #endif
9033Sbill 	/*NOTREACHED*/
9133Sbill }
9233Sbill 
9333Sbill /*
9433Sbill  * Wake up all processes sleeping on chan.
9533Sbill  */
9633Sbill wakeup(chan)
9733Sbill register caddr_t chan;
9833Sbill {
9933Sbill 	register struct proc *p, *q;
10033Sbill 	register i;
10133Sbill 	int s;
10233Sbill 
10333Sbill 	s = spl6();
10433Sbill 	i = HASH(chan);
10533Sbill restart:
10633Sbill 	p = slpque[i];
10733Sbill 	q = NULL;
10833Sbill 	while(p != NULL) {
10933Sbill 		if (p->p_rlink || p->p_stat != SSLEEP)
11033Sbill 			panic("wakeup");
11133Sbill 		if (p->p_wchan==chan && p->p_stat!=SZOMB) {
11233Sbill 			if (q == NULL)
11333Sbill 				slpque[i] = p->p_link;
11433Sbill 			else
11533Sbill 				q->p_link = p->p_link;
11633Sbill 			p->p_wchan = 0;
11733Sbill 			p->p_slptime = 0;
11833Sbill 			/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
11933Sbill 			p->p_stat = SRUN;
12033Sbill 			if (p->p_flag & SLOAD) {
12133Sbill #ifndef FASTVAX
12233Sbill 				p->p_link = runq;
12333Sbill 				runq = p->p_link;
12433Sbill #else
12533Sbill 				setrq(p);
12633Sbill #endif
12733Sbill 			}
12833Sbill 			if(p->p_pri < curpri)
12933Sbill 				runrun++;
13033Sbill 			if(runout != 0 && (p->p_flag&SLOAD) == 0) {
13133Sbill 				runout = 0;
13233Sbill 				wakeup((caddr_t)&runout);
13333Sbill 			}
13433Sbill 			/* END INLINE EXPANSION */
13533Sbill 			goto restart;
13633Sbill 		}
13733Sbill 		q = p;
13833Sbill 		p = p->p_link;
13933Sbill 	}
14033Sbill 	splx(s);
14133Sbill }
14233Sbill 
14333Sbill #ifdef FASTVAX
14433Sbill /*
14533Sbill  * Initialize the (doubly-linked) run queues
14633Sbill  * to be empty.
14733Sbill  */
14833Sbill rqinit()
14933Sbill {
15033Sbill 	register int i;
15133Sbill 
15233Sbill 	for (i = 0; i < NQS; i++)
15333Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
15433Sbill }
15533Sbill #endif
15633Sbill 
15733Sbill /*
15833Sbill  * Set the process running;
15933Sbill  * arrange for it to be swapped in if necessary.
16033Sbill  */
16133Sbill setrun(p)
16233Sbill register struct proc *p;
16333Sbill {
16433Sbill 	register caddr_t w;
16533Sbill 	register s;
16633Sbill 
16733Sbill 	s = spl6();
16833Sbill 	switch (p->p_stat) {
16933Sbill 
17033Sbill 	case 0:
17133Sbill 	case SWAIT:
17233Sbill 	case SRUN:
17333Sbill 	case SZOMB:
17433Sbill 	default:
17533Sbill 		panic("setrun");
17633Sbill 
17733Sbill 	case SSLEEP:
17833Sbill 		if (w = p->p_wchan) {
17933Sbill 			wakeup(w);
18033Sbill 			splx(s);
18133Sbill 			return;
18233Sbill 		}
18333Sbill 		break;
18433Sbill 
18533Sbill 	case SIDL:
18633Sbill 	case SSTOP:
18733Sbill 		break;
18833Sbill 	}
18933Sbill 	p->p_stat = SRUN;
19033Sbill 	if (p->p_flag & SLOAD)
19133Sbill 		setrq(p);
19233Sbill 	splx(s);
19333Sbill 	if(p->p_pri < curpri)
19433Sbill 		runrun++;
19533Sbill 	if(runout != 0 && (p->p_flag&SLOAD) == 0) {
19633Sbill 		runout = 0;
19733Sbill 		wakeup((caddr_t)&runout);
19833Sbill 	}
19933Sbill }
20033Sbill 
20133Sbill /*
20233Sbill  * Set user priority.
20333Sbill  * The rescheduling flag (runrun)
20433Sbill  * is set if the priority is better
20533Sbill  * than the currently running process.
20633Sbill  */
20733Sbill setpri(pp)
20833Sbill register struct proc *pp;
20933Sbill {
21033Sbill 	register p;
21133Sbill 
21233Sbill 	p = (pp->p_cpu & 0377)/16;
21333Sbill 	p += PUSER + pp->p_nice - NZERO;
21433Sbill 	if(p > 127)
21533Sbill 		p = 127;
21633Sbill 	if(p < curpri)
21733Sbill 		runrun++;
21833Sbill 	pp->p_usrpri = p;
21933Sbill 	return(p);
22033Sbill }
22133Sbill 
22233Sbill /*
22333Sbill  * Create a new process-- the internal version of
22433Sbill  * sys fork.
22533Sbill  * It returns 1 in the new process, 0 in the old.
22633Sbill  */
22733Sbill newproc(isvfork)
22833Sbill {
22933Sbill 	register struct proc *p;
23033Sbill 	register struct proc *rpp, *rip;
23133Sbill 	register int n;
23233Sbill 
23333Sbill 	p = NULL;
23433Sbill 	/*
23533Sbill 	 * First, just locate a slot for a process
23633Sbill 	 * and copy the useful info from this process into it.
23733Sbill 	 * The panic "cannot happen" because fork has already
23833Sbill 	 * checked for the existence of a slot.
23933Sbill 	 */
24033Sbill retry:
24133Sbill 	mpid++;
24233Sbill 	if(mpid >= 30000) {
24333Sbill 		mpid = 0;
24433Sbill 		goto retry;
24533Sbill 	}
24633Sbill 	for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
24733Sbill 		if(rpp->p_stat == NULL && p==NULL)
24833Sbill 			p = rpp;
24933Sbill 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
25033Sbill 			goto retry;
25133Sbill 	}
25233Sbill 	if ((rpp = p)==NULL)
25333Sbill 		panic("no procs");
25433Sbill 
25533Sbill 	/*
25633Sbill 	 * make proc entry for new proc
25733Sbill 	 */
25833Sbill 
25933Sbill 	rip = u.u_procp;
26033Sbill 	rpp->p_stat = SIDL;
26133Sbill 	rpp->p_clktim = 0;
26233Sbill 	rpp->p_flag = SLOAD | (rip->p_flag & SPAGI);
26333Sbill 	if (isvfork) {
26433Sbill 		rpp->p_flag |= SVFORK;
26533Sbill 		rpp->p_ndx = rip->p_ndx;
26633Sbill 	} else
26733Sbill 		rpp->p_ndx = rpp - proc;
26833Sbill 	rpp->p_uid = rip->p_uid;
26933Sbill 	rpp->p_pgrp = rip->p_pgrp;
27033Sbill 	rpp->p_nice = rip->p_nice;
27133Sbill 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
27233Sbill 	rpp->p_pid = mpid;
27333Sbill 	rpp->p_ppid = rip->p_pid;
27433Sbill 	rpp->p_time = 0;
27533Sbill 	rpp->p_cpu = 0;
27633Sbill 	if (isvfork) {
27733Sbill 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
27833Sbill 		rpp->p_szpt = clrnd(ctopt(UPAGES));
27933Sbill 		forkstat.cntvfork++;
28033Sbill 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
28133Sbill 	} else {
28233Sbill 		rpp->p_tsize = rip->p_tsize;
28333Sbill 		rpp->p_dsize = rip->p_dsize;
28433Sbill 		rpp->p_ssize = rip->p_ssize;
28533Sbill 		rpp->p_szpt = rip->p_szpt;
28633Sbill 		forkstat.cntfork++;
28733Sbill 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
28833Sbill 	}
28933Sbill 	rpp->p_rssize = 0;
29033Sbill 	rpp->p_wchan = 0;
29133Sbill 	rpp->p_slptime = 0;
29233Sbill 	rpp->p_aveflt = rip->p_aveflt;
29333Sbill 	rate.v_pgin += rip->p_aveflt;
29433Sbill 	rpp->p_faults = 0;
29533Sbill 	n = PIDHASH(rpp->p_pid);
29633Sbill 	p->p_idhash = pidhash[n];
29733Sbill 	pidhash[n] = rpp - proc;
29833Sbill 
29933Sbill 	/*
30033Sbill 	 * make duplicate entries
30133Sbill 	 * where needed
30233Sbill 	 */
30333Sbill 
30433Sbill 	multprog++;
30533Sbill 
30633Sbill 	for(n=0; n<NOFILE; n++)
30733Sbill 		if(u.u_ofile[n] != NULL) {
30833Sbill 			u.u_ofile[n]->f_count++;
30933Sbill 			if(!isvfork && u.u_vrpages[n])
31033Sbill 				u.u_ofile[n]->f_inode->i_vfdcnt++;
31133Sbill 		}
31233Sbill 
31333Sbill 	u.u_cdir->i_count++;
31433Sbill 	if (u.u_rdir)
31533Sbill 		u.u_rdir->i_count++;
31633Sbill 	/*
31733Sbill 	 * Partially simulate the environment
31833Sbill 	 * of the new process so that when it is actually
31933Sbill 	 * created (by copying) it will look right.
32033Sbill 	 */
32133Sbill 
32233Sbill 	rip->p_flag |= SKEEP;	/* prevent parent from being swapped */
32333Sbill 
32433Sbill 	if (procdup(rpp, isvfork))
32533Sbill 		return (1);
32633Sbill 
32733Sbill 	spl6();
32833Sbill 	rpp->p_stat = SRUN;
32933Sbill 	setrq(rpp);
33033Sbill 	spl0();
331*88Sbill 	/* SSWAP NOT NEEDED IN THIS CASE AS u.u_pcb.pcb_sswap SUFFICES */
33233Sbill 	/* rpp->p_flag |= SSWAP; */
33333Sbill 	rip->p_flag &= ~SKEEP;
33433Sbill 	if (isvfork) {
33533Sbill 		u.u_procp->p_xlink = rpp;
33633Sbill 		u.u_procp->p_flag |= SNOVM;
33733Sbill 		while (rpp->p_flag & SVFORK)
33833Sbill 			sleep((caddr_t)rpp, PZERO - 1);
33933Sbill 		if ((rpp->p_flag & SLOAD) == 0)
34033Sbill 			panic("newproc vfork");
34133Sbill 		uaccess(rpp, Vfmap, &vfutl);
34233Sbill 		u.u_procp->p_xlink = 0;
34333Sbill 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
34433Sbill 		for (n = 0; n < NOFILE; n++)
34533Sbill 			if (vfutl.u_vrpages[n]) {
34633Sbill 				if ((u.u_vrpages[n] = vfutl.u_vrpages[n] - 1) == 0)
34733Sbill 					if (--u.u_ofile[n]->f_inode->i_vfdcnt < 0)
34833Sbill 						panic("newproc i_vfdcnt");
34933Sbill 				vfutl.u_vrpages[n] = 0;
35033Sbill 			}
35133Sbill 		u.u_procp->p_flag &= ~SNOVM;
35233Sbill 		rpp->p_ndx = rpp - proc;
35333Sbill 		rpp->p_flag |= SVFDONE;
35433Sbill 		wakeup((caddr_t)rpp);
35533Sbill 	}
35633Sbill 	return (0);
35733Sbill }
358