⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slp.c

📁 著名的AT&T UNIX v6 源码
💻 C
字号:
#include "../h/param.h"#include "../h/systm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/proc.h"#include "../h/text.h"#include "../h/uba.h"#include "../h/map.h"#include "../h/file.h"#include "../h/inode.h"#include "../h/buf.h"#include "../h/page.h"#include "../h/mtpr.h"/* * Give up the processor till a wakeup occurs * on chan, at which time the process * enters the scheduling queue at priority pri. * The most important effect of pri is that when * pri<=PZERO a signal cannot disturb the sleep; * if pri>PZERO signals will be processed. * Callers of this routine must be prepared for * premature return, and check that the reason for * sleeping has gone away. */sleep(chan, pri)caddr_t chan;{	register struct proc *rp;	register s;	rp = u.u_procp;	s = spl6();	rp->p_stat = SSLEEP;	rp->p_wchan = chan;	rp->p_pri = pri;	if(pri > PZERO) {		if(issig()) {			rp->p_wchan = 0;			rp->p_stat = SRUN;			spl0();			goto psig;		}		spl0();		if(runin != 0) {			runin = 0;			wakeup((caddr_t)&runin);		}		swtch();		if(issig())			goto psig;	} else {		spl0();		swtch();	}	splx(s);	return;	/*	 * If priority was low (>PZERO) and	 * there has been a signal,	 * execute non-local goto to	 * the qsav location.	 * (see trap1/trap.c)	 */psig:	resume(u.u_procp->p_addr, u.u_qsav);}/* * Wake up all processes sleeping on chan. */wakeup(chan)register caddr_t chan;{	register struct proc *p;	register i;	int s;	p = &proc[0];	i = NPROC;	do {		if(p->p_wchan==chan && p->p_stat!=SZOMB) {			/*			 * this code looks dumb, but			 * there is a possible race due			 * to interrupts.			 */			s = spl6();			if(p->p_wchan == chan)				setrun(p);			splx(s);		}		p++;	} while(--i);}/* * when you are sure that it * is impossible to get the * 'proc on q' diagnostic, the * diagnostic loop can be removed. */setrq(p)struct proc *p;{	register struct proc *q;	register s;	s = spl6();	for(q=runq; q!=NULL; q=q->p_link)		if(q == p) {			printf("proc on q\n");			goto out;		}	p->p_link = runq;	runq = p;out:	splx(s);}/* * Set the process running; * arrange for it to be swapped in if necessary. */setrun(p)register struct proc *p;{	if (p->p_stat==0 || p->p_stat==SZOMB)		panic("Running a dead proc");	p->p_wchan = 0;	p->p_stat = SRUN;	setrq(p);	if(p->p_pri < curpri)		runrun++;	if(runout != 0 && (p->p_flag&SLOAD) == 0) {		runout = 0;		wakeup((caddr_t)&runout);	}}/* * Set user priority. * The rescheduling flag (runrun) * is set if the priority is better * than the currently running process. */setpri(pp)register struct proc *pp;{	register p;	p = (pp->p_cpu & 0377)/16;	p += PUSER + pp->p_nice - NZERO;	if(p > 127)		p = 127;	if(p < curpri)		runrun++;	pp->p_pri = p;	return(p);}/* * The main loop of the scheduling (swapping) * process. * The basic idea is: *  see if anyone wants to be swapped in; *  swap out processes until there is room; *  swap him in; *  repeat. * The runout flag is set whenever someone is swapped out. * Sched sleeps on it awaiting work. * * Sched sleeps on runin whenever it cannot find enough * core (by swapping out or otherwise) to fit the * selected swapped process.  It is awakened when the * core situation changes and in any case once per second. */sched(){	register struct proc *rp, *p, *inp;	register outage, inage,memneed,memleft;	int maxsize;	extern  int  freemem;	/*	 * find user to swap in;	 * of users ready, select one out longest	 */loop:	spl6();	outage = -20000;	for (rp = &proc[0]; rp < &proc[NPROC]; rp++)	if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&	    rp->p_time - (rp->p_nice-NZERO)*8 > outage) {		p = rp;		outage = rp->p_time - (rp->p_nice-NZERO)*8;	}	/*	 * If there is no one there, wait.	 */	if (outage == -20000) {		runout++;		sleep((caddr_t)&runout, PSWP);		goto loop;	}	spl0();	/*	 * See if there is core for that process;	 * if so, swap it in.	 */	if (swapin(p))		goto loop;	/*	 * none found.	 * look around for core.	 * Select the largest of those sleeping	 * at bad priority; if none, select the oldest.	 */	spl6();	inp = p;		/* we are trying to swap this guy in */	p = NULL;	maxsize = -1;	inage = -1;	for (rp = &proc[0]; rp < &proc[NPROC]; rp++) {		if (rp->p_stat==SZOMB)			continue;		if (rp == inp)			continue;		if (rp->p_flag&SSPART) {	/* we have found one partially swapped */			p = rp;			maxsize = 0;			break;		}		if ((rp->p_flag&(SSYS|SLOCK|SULOCK|SLOAD))!=SLOAD)			continue;		if (rp->p_textp && rp->p_textp->x_flag&XLOCK)			continue;		if (rp->p_stat==SSLEEP&&rp->p_pri>=PZERO || rp->p_stat==SSTOP) {			if (maxsize < rp->p_size) {				p = rp;				maxsize = rp->p_size;			}		} else if (maxsize<0 && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) {			if (rp->p_time+rp->p_nice-NZERO > inage) {				p = rp;				inage = rp->p_time+rp->p_nice-NZERO;			}		}	}	spl0();	/*	 * Swap found user out if sleeping at bad pri,	 * or if he has spent at least 2 seconds in core and	 * the swapped-out process has spent at least 3 seconds out.	 * Otherwise wait a bit and try again.	 */	if (maxsize>=0 || (outage>=3 && inage>=2)) {		p->p_flag &= ~SLOAD;		if (inp->p_flag & SSPART)			memneed = inp->p_swsize - UPAGES;		else			memneed = inp->p_size;		if (inp->p_textp)			if (inp->p_textp->x_ccount == 0)				memneed += inp->p_textp->x_size;		memneed -= freemem;		/* amount we must swap out */		memneed += 11 + SWAPSIZE - (memneed+11)%SWAPSIZE;		memleft = p->p_size;		if (p->p_flag & SSPART)			memleft -= p->p_swsize;	/* core left */		if ((memleft - memneed) < 2*SWAPSIZE)			memneed = memleft; 	/* take it all */		xswap(p,-memneed,0,-1);		goto loop;	}	spl6();	runin++;	sleep((caddr_t)&runin, PSWP);	goto loop;}/* * Swap a process in. */swapin(p)register struct proc *p;{	extern int Swapmap[], swaputl[], Swap2map[], swap2utl[];	register struct text *xp;	register int i, *ip;	int x, pt, tsize, tmem;	struct proc *prc;	if (xp = p->p_textp) {		xlock(xp);		tsize = xp->x_size;		tmem = xp->x_ccount == 0 ? tsize : 0;	} else {		tsize = p->p_tsize;		tmem = 0;	}		if ((p->p_flag & SSPART) == 0) {		pt = (p->p_size - UPAGES + tsize + 127)/128;	/* number of pages of page table */		if (memall(Swapmap,UPAGES + pt) == 0)			goto nomem;		for (i=UPAGES+pt; --i>=0; ) {	/* map u-area & page tables */			Swapmap[i] |= PG_V + PG_KW;			mtpr(TBIS, swaputl + (128 * i));		}		if(memall(&swaputl[(UPAGES*128)+tsize-tmem],p->p_size-UPAGES+tmem)==0){				memfree(Swapmap, UPAGES + pt);	/* free u-area & page tables */				goto nomem;		}		ip = &swaputl[UPAGES*128];		for (i=tmem; --i>=0;)			*ip++ |= PG_V + PG_URKR;		ip = &swaputl[(UPAGES*128) + tsize];		for (i=p->p_size-UPAGES; --i>=0; )			*ip++ |= PG_V + PG_UW;		((struct user *)swaputl)->u_pcb.pcb_szpt = pt;	/* for swap I/O */		x = p->p_swaddr;		/* disk address */		for (i=0; i<UPAGES; i++)			p->p_addr[i] = Swapmap[i];		for (i=0; i<pt; i++)			((struct user *)swaputl)->u_ptable[i] = (Swapmap+UPAGES)[i] & PG_PFNUM;	} else {		ptaccess(p, Swapmap, swaputl);		pt = ((struct user *)swaputl)->u_pcb.pcb_szpt;		if (memall(&swaputl[(UPAGES*128)+tsize-tmem], p->p_swsize-UPAGES				+ tmem) == 0)			goto nomem;		ip = &swaputl[(UPAGES*128)];		for (i=tmem; --i>=0; )			*ip++ |= PG_V + PG_URKR;		ip = &swaputl[(UPAGES*128)+tsize];		for (i=p->p_swsize-UPAGES; --i>=0; )			*ip++ |= PG_V + PG_UW;		x = p->p_swaddr;	}	if (xp) {		if (xp->x_ccount==0) {			xp->x_caddr = p;	/* make link to loaded proc */			if ((xp->x_flag&XLOAD)==0)				swap(p,xp->x_daddr,0,xp->x_size,B_READ,0);		} else {			if (xp->x_caddr == 0)	/* must find the text */				for (prc= &proc[0]; prc<&proc[NPROC]; prc++)					if ((prc->p_flag&SLOAD) && (prc->p_textp==xp)					  && (prc->p_flag&SLOCK)==0 && (prc!=p)){						xp->x_caddr = prc;	/* found it */						break;					}			if (xp->x_caddr == 0)				panic("lost text");			ptaccess(xp->x_caddr, Swap2map, swap2utl);			bcopy(swap2utl + 128*UPAGES, swaputl + 128*UPAGES, 4*xp->x_size);		}		xp->x_ccount++;		xunlock(xp);	}	if ((p->p_flag & SSPART) == 0)		swap(p, x, tsize, p->p_size, B_READ, 1);	else {		swap(p, x+UPAGES, tsize, p->p_swsize-UPAGES, B_READ, 0);		p->p_flag &= ~SSPART;	}	((struct user *)swaputl)->u_pcb.pcb_szpt = pt;   /* may have shrunk */	((struct user *)swaputl)->u_pcb.pcb_p1br = (int)&u + UPAGES*512					+ pt*512 - 0x800000;  /* if page table shrunk, its moved */	mfree(swapmap, ctod(p->p_size), x);	x = (UPAGES*128) + tsize +  p->p_size - UPAGES;	for (i=1; i<=((struct user *)swaputl)->u_ssize; i++) {		swaputl[((UPAGES+pt)*128) - i] = swaputl[x - i];		if ( x != (UPAGES+pt)*128 )			swaputl[x - i] = 0;	}	p->p_flag |= SLOAD;	p->p_time = 0;	return(1);nomem:	if (xp)		xunlock(xp);	return(0);}/* * put the current process on * the Q of running processes and * call the scheduler. */qswtch(){	setrq(u.u_procp);	swtch();}/* * This routine is called to reschedule the CPU. * if the calling process is not in RUN state, * arrangements for it to restart must have * been made elsewhere, usually by calling via sleep. * There is a race here. A process may become * ready after it has been examined. * In this case, idle() will be called and * will return in at most 1HZ time. * i.e. its not worth putting an spl() in. */swtch(){	register n;	register struct proc *p, *q, *pp, *pq;	/*	 * If not the idle process, resume the idle process.	 */	if (u.u_procp != &proc[0]) {		if (save(u.u_rsav)) {			return;		}		resume(proc[0].p_addr, u.u_qsav);	}	/*	 * The first save returns nonzero when proc 0 is resumed	 * by another process (above); then the second is not done	 * and the process-search loop is entered.	 *	 * The first save returns 0 when swtch is called in proc 0	 * from sched().  The second save returns 0 immediately, so	 * in this case too the process-search loop is entered.	 * Thus when proc 0 is awakened by being made runnable, it will	 * find itself and resume itself at rsav, and return to sched().	 */	if (save(u.u_qsav)==0 && save(u.u_rsav))		return;loop:	spl6();	runrun = 0;	pp = NULL;	q = NULL;	n = 128;	/*	 * Search for highest-priority runnable process	 */	for(p=runq; p!=NULL; p=p->p_link) {		if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {			if(p->p_pri < n) {				pp = p;				pq = q;				n = p->p_pri;			}		}		q = p;	}	/*	 * If no process is runnable, idle.	 */	p = pp;	if(p == NULL) {		idle();		goto loop;	}	q = pq;	if(q == NULL)		runq = p->p_link;	else		q->p_link = p->p_link;	curpri = n;	spl0();	/*	 * The rsav (ssav) contents are interpreted in the new address space	 */	n = p->p_flag&SSWAP;	p->p_flag &= ~SSWAP;	resume(p->p_addr, n? u.u_ssav: u.u_rsav);}/* * Create a new process-- the internal version of * sys fork. * It returns 1 in the new process, 0 in the old. */newproc(){	register struct proc *p, *up;	register struct proc *rpp, *rip;	register n;	p = NULL;	/*	 * First, just locate a slot for a process	 * and copy the useful info from this process into it.	 * The panic "cannot happen" because fork has already	 * checked for the existence of a slot.	 */retry:	mpid++;	if(mpid >= 30000) {		mpid = 0;		goto retry;	}	for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {		if(rpp->p_stat == NULL && p==NULL)			p = rpp;		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)			goto retry;	}	if ((rpp = p)==NULL)		panic("no procs");	/*	 * make proc entry for new proc	 */	rip = u.u_procp;	up = rip;	rpp->p_stat = SRUN;	rpp->p_clktim = 0;	rpp->p_flag = SLOAD;	rpp->p_uid = rip->p_uid;	rpp->p_pgrp = rip->p_pgrp;	rpp->p_nice = rip->p_nice;	rpp->p_textp = rip->p_textp;	rpp->p_pid = mpid;	rpp->p_ppid = rip->p_pid;	rpp->p_time = 0;	rpp->p_cpu = 0;	rpp->p_tsize = rip->p_tsize;	/*	 * make duplicate entries	 * where needed	 */	for(n=0; n<NOFILE; n++)		if(u.u_ofile[n] != NULL)			u.u_ofile[n]->f_count++;	if(up->p_textp != NULL) {		up->p_textp->x_count++;		up->p_textp->x_ccount++;	}	u.u_cdir->i_count++;	if (u.u_rdir)		u.u_rdir->i_count++;	/*	 * Partially simulate the environment	 * of the new process so that when it is actually	 * created (by copying) it will look right.	 */	rpp = p;	u.u_procp = rpp;	rip = up;	rpp->p_size = rip->p_size;	/*	 * When the resume is executed for the new process,	 * here's where it will resume.	 */	if (save(u.u_ssav)) {		return(1);	}	/*	 * If there is not enough core for the	 * new process, swap out the current process to generate the	 * copy.	 */	if (procdup(rpp) == NULL) {		rip->p_stat = SIDL;		for(n=UPAGES; --n>=0; )			rpp->p_addr[n] = rip->p_addr[n];		xswap(rpp, 0, 0, -1);		rip->p_stat = SRUN;	}	u.u_procp = rip;	setrq(rpp);	rpp->p_flag |= SSWAP;	return(0);}/* * Change the size of the data+stack regions of the process. * If the size is shrinking, it's easy-- just release the extra core. * If it's growing, and there is core, just allocate it * and copy the image, taking care to reset registers to account * for the fact that the system's stack has moved. * If there is no core, arrange for the process to be swapped * out after adjusting the size requirement-- when it comes * in, enough core will be allocated. * * After the expansion, the caller will take care of copying * the user's stack towards or away from the data area. */expand(change,region){	int n,p0,p1,oldss;	register struct proc *p;	register  new;	register  struct  pt_entry  *base;	p = u.u_procp;	n = p->p_size;	oldss = 0x200000 - u.u_pcb.pcb_p1lr;	p->p_size += change;	if (change == 0)		return;	p0 = mfpr(P0BR) + 4 * mfpr(P0LR);	p1 = mfpr(P1BR) + 4 * mfpr(P1LR);	/* see if we must add another page to the user page table */	if ((new = (p0 - p1 + 4*change)/4) > 0) {		new = ptexpand((new + 127)/128);	}	if (region == P0BR) {		base = (struct pt_entry *)mfpr(P0BR);		base += (p0 = mfpr(P0LR)) + (change > 0 ? 0 : change);	} else {		base = (struct pt_entry *)mfpr(P1BR);		base += (p1 = mfpr(P1LR)) - (change > 0 ? change : 0);	}	if (change > 0) {		new = memall(base,change);	} else		memfree(base,-change);	if (region == P0BR)  {		mtpr(P0LR,p0 + change);		u.u_pcb.pcb_p0lr = p0 + change | 0x04000000;	} else {		mtpr(P1LR,p1 - change);		u.u_pcb.pcb_p1lr = p1 - change;	}	if (change < 0 || new > 0) {		new = 1;		if (change < 0) {			change = -change;			new = 0;		}		while (--change >= 0) {			*(int *)base |= PG_UW;			base->pg_v = new;  			base++;		}		return;	}	/*	 * When the resume is executed for the new process	 * here's where it will resume.	 */	if (save(u.u_ssav)) {		return;	}	xswap(p, 1, n, oldss);	p->p_flag |= SSWAP;	qswtch();	/* no return */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -