File:  [MW Coherent from dump] / coherent / d / PS2_KERNEL / coh.386 / proc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* (lgl-
 *	The information contained herein is a trade secret of Mark Williams
 *	Company, and  is confidential information.  It is provided  under a
 *	license agreement,  and may be  copied or disclosed  only under the
 *	terms of  that agreement.  Any  reproduction or disclosure  of this
 *	material without the express written authorization of Mark Williams
 *	Company or persuant to the license agreement is unlawful.
 *
 *	COHERENT Version 2.3.37
 *	Copyright (c) 1982, 1983, 1984.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * Coherent.
 * Process handling and scheduling.
 *
 * $Log: proc.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:39  root
 * coherent
 *
 * Revision 1.2  92/08/04  12:34:18  bin
 * changed for ker 59
 * 
 * Revision 1.5  92/04/03  14:35:36  hal
 * Kernel #49: piggy trace variable.
 * 
 * Revision 1.4  92/02/03  17:00:09  piggy
 * Send SIGHUP to all group members on death of group leader.
 */
#include <sys/coherent.h>
#include <acct.h>
#include <errno.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <signal.h>
#include <sys/stat.h>

/*
 * Initialization.
 * Set up the hash table queues.
 */
pcsinit()
{
	register PROC *pp;
	register PLINK *lp;

	/*
	 * Explicitly initialize everything in the first process.
	 */
	pp = &procq;
	SELF = pp;
	procq.p_nforw = pp;
	procq.p_nback = pp;
	procq.p_lforw = pp;
	procq.p_lback = pp;

#ifdef _I386
	/* Segments are initialized in mchinit() and eveinit().  */

	procq.p_uid = 0;		/* Effective uid */
	procq.p_ruid = 0;		/* Real uid */
	procq.p_rgid = 0;		/* Real gid */
	procq.p_state = 0;		/* Scheduling state */
	procq.p_flags = 0;		/* Flags */
	procq.p_ssig = (sig_t) 0;	/* Signals which have been set */
#ifdef _I386
	procq.p_dfsig = (sig_t) 0xffffffff;  /* All signals are defaulted.  */
	procq.p_hsig = (sig_t) 0;	/* Signals which are being held */
	procq.p_dsig = (sig_t) 0;	/* Signals which are being deferred */
#endif
	procq.p_isig = (sig_t) 0;	/* Signals which are being ignored */
	procq.p_event = NULL;		/* Wakeup event channel */
	procq.p_alarm = 0;		/* Timer for alarms */
	procq.p_group = 0;		/* Process group */
/*
 * Set ttdev to null so that we do not accidentally set a tty for init.
 */
	procq.p_ttdev = makedev(0,0);	/* Controlling terminal */
	procq.p_nice = 0;		/* Nice value */
	procq.p_cval = 0;		/* Cpu schedule value */
	procq.p_sval = 0;		/* Swap schedule value */
	procq.p_ival = 0;		/* Importance value */
	procq.p_rval = 0;		/* Response value */
	procq.p_lctim = 0;		/* Last time cval was updated */
	procq.p_utime = 0L;		/* User time (HZ) */
	procq.p_stime = 0L;		/* System time */
	procq.p_cutime = 0L;		/* Sum of childs user time */
	procq.p_cstime = 0L;		/* Sum of childs system time */
	procq.p_exit = 0;		/* Exit status */
	procq.p_polls = NULL;		/* Enabled polls */
	/* Poll  timer */
	procq.p_polltim.t_next = NULL;
	procq.p_polltim.t_last = NULL;
	procq.p_polltim.t_lbolt = 0L;
	procq.p_polltim.t_func = NULL;
	procq.p_polltim.t_farg = NULL;
#ifndef _I386
	procq.p_polltim.t_ldrv = 0;
#endif /* _I386 */

	/* Alarm timer */
	procq.p_alrmtim.t_next = NULL;
	procq.p_alrmtim.t_last = NULL;
	procq.p_alrmtim.t_lbolt = 0L;
	procq.p_alrmtim.t_func = NULL;
	procq.p_alrmtim.t_farg = NULL;
#ifndef _I386
	procq.p_alrmtim.t_ldrv = 0;
#endif /* _I386 */

	procq.p_prl = NULL;		/* Pending record lock */
#endif /* _I386 */

	for (lp=&linkq[0]; lp<&linkq[NHPLINK]; lp++) {
		lp->p_lforw = lp;
		lp->p_lback = lp;
	}
}

/*
 * Initiate a process.
 */
PROC *
#ifdef _I386
process()
#else
process(f)
int (*f)();
#endif
{
	register PROC *pp1;
	register PROC *pp;
	register SEG *sp;
	MCON mcon;

	if ((pp=kalloc(sizeof(PROC))) == NULL)
		return (NULL);

	pp->p_flags = PFCORE;
	pp->p_state = PSRUN;
	pp->p_ttdev = NODEV;
#ifndef _I386
	/*
	 * What is this, and why is it 286 only?
	 */
	if (f != NULL) {
		pp->p_flags |= PFKERN;
		sp = salloc((fsize_t)UPASIZE, SFSYST|SFHIGH|SFNSWP);
		if (sp == NULL) {
			kfree(pp);
			return (NULL);
		}
		pp->p_segp[SIUSERP] = sp;
		msetsys(&mcon, f, FP_SEL(sp->s_faddr));
		kfcopy(	(char *)&mcon,
			sp->s_faddr + offset(uproc, u_syscon),
			sizeof(mcon));
	}
#endif
	lock(pnxgate);
next:

	/*
	 * Pick the next process id.
	 */
	/* DO NOT MESS WITH THE FOLLOWING CONDITIONAL UNLESS YOU
	   TEST THE RESULTS ON BOTH 286 AND 386 */
#ifdef _I386
	if (++cpid >= NPID)
		cpid = 2;
	pp->p_pid = cpid;
#else
	pp->p_pid = cpid++;
	if (cpid >= NPID)
		cpid = 2;
#endif

	/*
	 * Make sure that process id is not in use.
	 */
	pp1 = &procq;
	while ((pp1=pp1->p_nforw) != &procq) {
		if (pp1->p_pid < pp->p_pid)
			break;
		if (pp1->p_pid == pp->p_pid)
			goto next;
	}

	/*
	 * We've got a valid pid, so let's put this process into
	 * the process table.
	 */
	pp->p_nback = pp1->p_nback;
	pp1->p_nback->p_nforw = pp;
	pp->p_nforw = pp1;
	pp1->p_nback = pp;
	unlock(pnxgate);
	return (pp);
}

/*
 * Remove a process from the next queue and release and space.
 */
relproc(pp)
register PROC *pp;
{
	register SEG * sp;

	/*
	 * Child process still has a user-area.
	 */
	if ((sp = pp->p_segp[SIUSERP]) != NULL) {

		/*
		 * Detach user-area from child process.
		 */
		pp->p_segp[SIUSERP] = NULL;

		/*
		 * Child process is swapped out.
		 */
		if (pp->p_flags & PFSWAP)
			sp->s_lrefc++;

		/*
		 * Release child's user-area.
		 */
		sfree(sp);
	}

	/*
	 * Remove process from doubly-linked list of all processes.
	 * Release space allocated for proc structure.
	 */
	lock(pnxgate);
	pp->p_nback->p_nforw = pp->p_nforw;
	pp->p_nforw->p_nback = pp->p_nback;
	unlock(pnxgate);
	kfree(pp);
}

/*
 * Create a clone of ourselves.
 *	N.B. - consave(&mcon) returns twice; anything not initialized
 *	in automatic storage before the call to segadup() will not be
 *	initialized when the second return from consave() commences.
 */
pfork()
{
	register PROC *cpp;
	register PROC *pp;
	register int s;
	MCON mcon;

#ifdef _I386
	if ((cpp=process()) == NULL) {
#else
	if ((cpp=process(NULL)) == NULL) {
#endif
		SET_U_ERROR( EAGAIN, "no more process table entries" );
		return -1;
	}

#ifndef _I386
	s = sphi();
	usave();	/* Put the current copy of uarea into its segment */
	spl(s);
#endif

	pp = SELF;
	s = sphi();	/* put current interrupt level into s before segadup */
	spl(s);
	/*
	 * As stated above, no auto variable may be changed between calls
	 * to segadup() and consave().
	 */
	if (segadup(cpp) == 0) {
		SET_U_ERROR( EAGAIN, "can not duplicate segments" );
		relproc(cpp);
		return -1;
	}
	if (u.u_rdir != NULL)
		u.u_rdir->i_refc++;
	if (u.u_cdir != NULL)
		u.u_cdir->i_refc++;
	fdadupl();
	cpp->p_uid   = pp->p_uid;
	cpp->p_ruid  = pp->p_ruid;
	cpp->p_rgid  = pp->p_rgid;
	cpp->p_ppid  = pp->p_pid;
	cpp->p_ttdev = pp->p_ttdev;
	cpp->p_group = pp->p_group;
	cpp->p_ssig  = pp->p_ssig;
#ifdef _I386
	cpp->p_dfsig  = pp->p_dfsig;
	cpp->p_dsig  = pp->p_dsig;
	cpp->p_hsig  = pp->p_hsig;
#endif /* _I386 */
	cpp->p_isig  = pp->p_isig;
	cpp->p_cval  = CVCHILD;
	cpp->p_ival  = IVCHILD;
	cpp->p_sval  = SVCHILD;
	cpp->p_rval  = RVCHILD;
#ifdef _I386
	cpp->p_prl = NULL;
#endif

	sphi();		/* s = sphi() was done before segadup() */
	consave(&mcon);
	spl(s);

	/*
	 * Parent process.
	 */
	if ((pp = SELF) != cpp) {
		segfinm(cpp->p_segp[SIUSERP]);
#ifdef _I386
		dmaout(sizeof(mcon), 
		   MAPIO(cpp->p_segp[SIUSERP]->s_vmem,offset(uproc,u_syscon)),
			(char *)&mcon);
#else
		kfcopy((char *)&mcon,
			cpp->p_segp[SIUSERP]->s_faddr + offset(uproc,u_syscon),
			sizeof(mcon));
#endif
		mfixcon(cpp);
		s = sphi();
		setrun(cpp);
		spl(s);
#ifdef _I386
		u.u_rval2 = 0;
#endif
		return(cpp->p_pid);
	}

	/*
	 * Child process.
	 */
	else {
		u.u_btime = timer.t_time;
		u.u_flag = AFORK;
#ifdef _I386
#ifdef UPROC_VERSION
		u.u_version = UPROC_VERSION;
#endif /* UPROC_VERSION */
		u.u_sleep[0] = '\0'; /* We are not sleeping to start with.  */
		sproto(0);
#else
		sproto();
#endif
		segload();
#ifdef _I386
		u.u_rval2 = SELF->p_ppid;
#endif
		return 0;
	}
}

/*
 * Die.
 */
pexit(s)
{
	register PROC *pp1;
	register PROC *pp;
	register SEG  *sp;
	register int n;
	PROC *parent;

	pp = SELF;

	T_PIGGY( 0x1, printf("%s:pexit(%x)", u.u_comm, s); );
	/*
	 * Cancel alarm and poll timers [if any].
	 */
	timeout(&pp->p_alrmtim, 0, NULL, 0);
	timeout(&pp->p_polltim, 0, NULL, 0);

	/*
	 * Write out accounting directory and close all files associated with
	 * this process.
	 */
	setacct();
	if (u.u_rdir)
		ldetach(u.u_rdir);
	if (u.u_cdir)
		ldetach(u.u_cdir);
	fdaclose();

	/*
	 * Free all segments in reverse order, except for user-area.
	 */
	for (n = NUSEG; --n > 0;) {
		if ((sp = pp->p_segp[n]) != NULL) {
			pp->p_segp[n] = NULL;
			sfree(sp);
		}
	}

	/*
	 * Wakeup our parent.  If we have any children, init will become the
	 * new parent.  If there are any children we are tracing who are
	 * waiting for us, we wake them up.
	 */
	pp1 = &procq;
	while ((pp1=pp1->p_nforw) != &procq) {
		if (pp1->p_pid == pp->p_ppid) {
			parent = pp1;	/* Remember our parent.  */
			if (pp1->p_state==PSSLEEP && pp1->p_event==(char *)pp1)
				wakeup((char *)pp1);
		}
		if (pp1->p_ppid == pp->p_pid) {
			pp1->p_ppid = 1;
			if (pp1->p_state == PSDEAD)
				wakeup((char *)eprocp);
			if ((pp1->p_flags&PFTRAC) != 0)
				wakeup((char *)&pts.pt_req);
		}
	}

	/*
	 * Wake up swapper if swap timer is active.
	 */
	if (stimer.t_last != 0)
		wakeup((char *) &stimer);

	/*
	 * Mark us as dead and give up the processor forever.
	 */
	pp->p_exit = s;
	pp->p_state = PSDEAD;

#ifdef _I386
	/*
	 * If this is a process group leader, inform all members of the group
	 * of the recent death with a HUP signal.
	 */
	if (pp->p_group == pp->p_pid) {
		ukill(-pp->p_pid, SIGHUP);
	}
#else
	uasa = 0;
#endif

#ifdef _I386
	T_PIGGY( 0x100, printf("<CHLD pid: %d ppid: %d>",
				pp->p_pid, parent->p_pid); );

	/*
	 * If the parent is ignoring SIGCHLD, 
	 * remove the zombie right away.
	 */
#	define CHLDBIT (((sig_t) 1) << (SIGCHLD - 1))
	if (CHLDBIT & parent->p_isig) {
		parent->p_cutime += pp->p_utime + pp->p_cutime;
		parent->p_cstime += pp->p_stime + pp->p_cstime;
		relproc(pp);
	} else {
		/*
		 * If SIGCHLD is not defaulted, notify our parent
		 * of our demise.
		 */
		if (!(CHLDBIT & parent->p_dfsig)) {
			sendsig(SIGCHLD, parent );
		}
	}
#endif /* _I386 */

	dispatch();
}

#ifdef _I386
/*
 * Sleep verbosely.  Put a short string describing our reason for sleeping
 * into our U area, and then go to sleep.
 */
v_sleep(e, cl, sl, sr, msg)
	char *e;
	int cl, sl, sr;
	char *msg;
{
	int i;

	/*
	 * The descriptive string may be at most 10 characters long.
	 * It will only be NUL terminated if it has 9 or fewer characters.
	 */
	for (i = 0; i < 10; ++i) {
		if ('\0' == (u.u_sleep[i] = msg[i])) {
			break;
		}
	}

	sleep(e, cl, sl, sr);
} /* v_sleep() */
#endif

/*
 * Sleep on the event `e'.  This gives up the processor until someone
 * wakes us up.  Since it is possible for many people to sleep on the
 * same event, the caller when awakened should make sure that what he
 * was waiting for has completed and if not, go to sleep again.  `cl'
 * is the cpu value we get to get the cpu as soon as we are woken up.
 * `sl' is the swap value we get to keep us in memory for the duration
 * of the sleep.  `sr' is the swap value that allows us to get swapped
 * in if we have been swapped out.
 */
sleep(e, cl, sl, sr)
char *e;
{
	register PROC *bp;
	register PROC *fp;
	register PROC *pp;
	register int s;

	pp = SELF;

	/*
	 * See if we have a signal awaiting.
	 */
	if (cl<CVNOSIG && pp->p_ssig && nondsig()) {
		sphi();
		envrest(&u.u_sigenv);
	}

	/*
	 * Get ready to go to sleep and do so.
	 */
	s = sphi();
	pp->p_state = PSSLEEP;
	pp->p_event = e;
	pp->p_lctim = utimer;
	addu(pp->p_cval, cl);
	pp->p_ival = sl;
	pp->p_rval = sr;
	fp = &linkq[hash(e)];
	bp = fp->p_lback;
	pp->p_lforw = fp;
	fp->p_lback = pp;
	pp->p_lback = bp;
	bp->p_lforw = pp;
	spl(s);
	dispatch();

	/*
	 * We have just woken up.  Get ready to return.
	 */
	subu(pp->p_cval, cl);
	pp->p_ival = 0;
	pp->p_rval = 0;

	/*
	 * Since we are no longer asleep, we no longer need 
	 * to publish a reason for sleeping.
	 */
#ifdef _I386
	u.u_sleep[0] = '\0';
#endif

	/*
	 * Check for an interrupted system call.
	 */
	if (cl<CVNOSIG && pp->p_ssig && nondsig()) {
		sphi();
		envrest(&u.u_sigenv);
	}
}

/*
 * Defer function to wake up all processes sleeping on the event `e'.
 */
wakeup(e)
char *e;
{
	void dwakeup();

#ifdef TRACER
	/*
	 * In diagnostic kernel, keep return addr on queue as well.
	 */
	int *r=(int*)(&e);
	defer0(dwakeup, e, *(r-1));
#else
	defer(dwakeup, e);
#endif
}

/*
 * Wake up all processes sleeping on the event `e'.
 */
void
dwakeup(e)
char *e;
{
	register PROC *pp;
	register PROC *pp1;
	register int s;

	/*
	 * Identify event queue to check.
	 * Disable interrupts.
	 */
	pp1 = &linkq[hash(e)];
	pp = pp1;
	s = sphi();

	/*
	 * Traverse doubly-linked circular event-queue.
	 */
	while ((pp = pp->p_lforw) != pp1) {

		/*
		 * Process is waiting on event 'e'.
		 */
		if (pp->p_event == e) {
			/*
			 * Remove process from event queue.
			 * Update process priority.
			 * Insert process into run queue.
			 */
			pp->p_lback->p_lforw = pp->p_lforw;
			pp->p_lforw->p_lback = pp->p_lback;
			addu(pp->p_cval, (utimer-pp->p_lctim)*CVCLOCK);
			setrun(pp);

			/*
			 * Enable interrupts.
			 * Restart search at start of event queue.
			 * Disable interrupts.
			 */
			spl(s);
			pp = pp1;
			s = sphi();
		}
	}
	spl(s);
}

/*
 * Reschedule the processor.
 */
dispatch()
{
	register PROC *pp1;
	register PROC *pp2;
	register unsigned v;
	register int s;

	s = sphi();
	pp1 = iprocp;
	pp2 = &procq;
	v = 0;
	while ((pp2=pp2->p_lforw) != &procq) {
		v -= pp2->p_cval;
		if ((pp2->p_flags&PFCORE) == 0)
			continue;
		pp1 = pp2->p_lforw;
		pp1->p_cval += pp2->p_cval;
		pp2->p_cval = v;
		pp1->p_lback = pp2->p_lback;
		pp1->p_lback->p_lforw = pp1;
		pp1 = pp2;
		break;
	}
	spl(s);

	quantum = NCRTICK;
	disflag = 0;
	if (pp1 != SELF) {
		/*
		 * Consave() returns twice.
		 * 1st time is after our context is saved in u.u_syscon,
		 *	whereupon we should restore other proc's context.
		 * 2nd time is after our context is restored by another proc.
		 * Conrest() forces a context switch to a new process.
		 */
		s = sphi();
		SELF = pp1;
		if (consave(&u.u_syscon) == 0) {
#ifdef _I386
			conrest(*pp1->p_segp[SIUSERP]->s_vmem, &u.u_syscon);
#else
			conrest(
			  FP_SEL(pp1->p_u->s_faddr), offset(uproc,u_syscon));
#endif
		}
		if (SELF->p_pid != 0)
			segload();
		spl(s);
	}
}

/*
 * Add a process to the run queue.
 * This routine must be called at high priority.
 */
setrun(pp1)
register PROC *pp1;
{
	register PROC *pp2;
	register unsigned v;

	v = 0;
	pp2 = &procq;
	for (;;) {
		pp2 = pp2->p_lback;
		if ((v+=pp2->p_lforw->p_cval) >= pp1->p_cval)
			break;
		if (pp2 == &procq)
			break;
	}
	pp2->p_lforw->p_lback = pp1;
	pp1->p_lforw = pp2->p_lforw;
	pp2->p_lforw = pp1;
	pp1->p_lback = pp2;
	v -= pp1->p_cval;
	pp1->p_cval = v;
	pp1->p_lforw->p_cval -= v;
	pp1->p_state = PSRUN;
}

/*
 * Wait for the gate `g' to unlock, and then lock it.
 */
lock(g)
register GATE g;
{
	register int s;

	s = sphi();
	while (g[0]) {
		g[1] = 1;
		v_sleep((char *)g, CVGATE, IVGATE, SVGATE, "lock");
		/* Waiting for a gate to unlock.  */
	}
	g[0] = 1;
	spl(s);
}

/*
 * Unlock the gate `g'.
 */
unlock(g)
register GATE g;
{
	g[0] = 0;
	if (g[1]) {
		g[1] = 0;
		disflag = 1;
		wakeup((char *)g);
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.