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

/* $Header: /var/lib/cvsd/repos/coherent/coherent/b/STREAMS/coh.386/proc.c,v 1.1.1.1 2019/05/29 04:56:36 root Exp $ */
/* (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 3.x, 4.x
 *	Copyright (c) 1982, 1993.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * Process handling and scheduling.
 *
 * $Log: proc.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:36  root
 * coherent
 *
 * Revision 2.3  93/08/09  13:35:59  bin
 * Kernel 82 changes
 * 
 * Revision 2.2  93/07/26  15:53:52  nigel
 * Nigel's R80
 * 
 */

#include <common/_wait.h>
#include <kernel/_sleep.h>
#include <kernel/ker_data.h>
#include <kernel/sigproc.h>
#include <sys/wait.h>
#include <stddef.h>

#include <sys/coherent.h>
#include <sys/acct.h>
#include <sys/errno.h>
#include <sys/inode.h>
#include <sys/ptrace.h>
#include <sys/sched.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. We use the
	 * kernel initialize routine with SELF set to NULL so that the first
	 * process gets started out with default values for fields that are
	 * normally inherited.
	 */

	pp = & procq;
	procq.p_nforw = pp;
	procq.p_nback = pp;
	procq.p_lforw = pp;
	procq.p_lback = pp;

	/* Segments are initialized in mchinit() and eveinit().	*/
	/* procq is static, so p_shmsr[] initializes to nulls.	*/

	PROC_INIT (& procq);

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

	/*
	 * After we have set things up, we can have a current process.
	 */

	SELF = pp;
}

/*
 * Initiate a process.
 */

static PROC *
process ()
{
	register PROC *pp1;
	register PROC *pp;

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

	PROC_INIT (pp);

	lock (pnxgate);
next:

	/*
	 * Pick the next process id.
	 */
	if (++ cpid >= NPID)
		cpid = 2;
	pp->p_pid = cpid;


	/*
	 * 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]) {

		/*
		 * 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;

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

	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;
	}

	shmDup(cpp);	/* copy shared memory info & update ref counts */

	if (u.u_rdir)
		u.u_rdir->i_refc ++;
	if (u.u_cdir)
		u.u_cdir->i_refc ++;
	fdadupl ();

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

	/*
	 * Parent process.
	 */

	if ((pp = SELF) != cpp) {
		segfinm (cpp->p_segp [SIUSERP]);
		dmaout (sizeof (mcon),
			MAPIO (cpp->p_segp [SIUSERP]->s_vmem,
			       U_OFFSET + offsetof (struct uproc, u_syscon)),
			(char *) & mcon);
		s = sphi ();
		setrun (cpp);
		spl (s);

		u.u_rval2 = 0;
		return cpp->p_pid;
	} else {
		/*
		 * Child process.
		 */

		u.u_btime = timer.t_time;
		u.u_flag = AFORK;

#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);
		segload ();
		u.u_rval2 = SELF->p_ppid;
		return 0;
	}
}

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

	pp = SELF;
	T_PIGGY( 0x1, printf("%s:pexit(%x)", u.u_comm, s));

	ndpEndProc ();

	/*
	 * 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]) {
			pp->p_segp[n] = NULL;
			sfree(sp);
		}
	}

	/* Detach remaining shared memory segments. */
	shmAllDt();

	/* Adjust(undo) all semaphores. */
	semAllAdjust(pp);

	/*
	 * 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;

	/* pp1 runs through the list of all processes */
	while ((pp1=pp1->p_nforw) != &procq) {

		/* if pp1 points to parent of the current process...*/
		if (pp1->p_pid == pp->p_ppid) {
			parent = pp1;	/* Remember our parent.  */
			if (ASLEEP(pp1) && pp1->p_event==(char *)pp1)
				wakeup((char *)pp1);
		}

		/* if pp1 points to child of the current process...*/
		if (pp1->p_ppid == pp->p_pid) {
			pp1->p_ppid = 1;
			if (pp1->p_state == PSDEAD)
				wakeup((char *)eprocp);
			if (pp1->p_flags&PFTRAC)
				wakeup((char *)&pts.pt_req);
		}
	}

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

	/*
	 * 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);

	/*
	 * If the parent is ignoring SIGCLD, 
	 * remove the zombie right away.
	 */

	if (parent == NULL)
		panic ("%d (@ %x) has no parent!\n", SELF->p_pid, SELF);

	if ((proc_signal_misc (parent) & __SF_NOCLDWAIT) != 0) {
		/*
		 * The parent has requested that no zombie processes be
		 * created out of childen.
		 */

		parent->p_cutime += pp->p_utime + pp->p_cutime;
		parent->p_cstime += pp->p_stime + pp->p_cstime;
		relproc (pp);
	} else {
		/*
		 * Send parent a notification of our demise.
		 */
		__siginfo_t	sigchld;

		sigchld.__si_signo = SIGCHLD;
		sigchld.__si_errno = 0;
		if (__WIFEXITED (s)) {
			sigchld.__si_code = __CLD_EXITED;
			sigchld.__si_status = __WEXITSTATUS (s);
		} else {
			sigchld.__si_code = __WCOREDUMP (s) ? __CLD_DUMPED :
							      __CLD_KILLED;
			sigchld.__si_status = __WTERMSIG (s);
		}
		sigchld.__si_pid = SELF->p_pid;
		proc_send_signal (parent, & sigchld);
	}

	dispatch();
}

/*
 * x_sleep()
 *
 * Surrender CPU while awaiting some event or resource.
 *
 * Arguments:
 *	event:		key value; so wakeup() can find this sleep
 *	schedPri:	prilo/primed/prihi/pritape/pritty/pridisk/prinet
 *			just copied into proc struct for scheduler to use.
 *			(see sys/v_types.h)
 *	sleepPri:	slpriNoSig	- signals may not interrupt sleep
 *			slpriSigLjmp	- signals cause longjmp (EINTR)
 *			slpriSigCatch	- signals are caught
 *			(see sys/sched.h)
 *	reason:		up to 10 chars of text for ps command "event"
 *
 * Return values:
 *	PROCESS_NORMAL_WAKE	wakeup received
 *	PROCESS_SIGNALLED	signal (other than SIGSTOP/SIGCONT) received
 *	PROCESS_CONTINUED	SIGSTOP/SIGCONT (unimplemented now)
 *
 * If longjmp occurs, won't return from x_sleep!
 */

__sleep_t
x_sleep(event, schedPri, sleepPri, reason)
char * event;
int schedPri;
int sleepPri;
char * reason;
{
	int i;
	register PROC *bp;
	register PROC *fp;
	register PROC *pp;
	register int s;

	/*
	 * 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 < U_SLEEP_LEN; ++i) {
		if ('\0' == (u.u_sleep[i] = reason[i])) {
			break;
		}
	}

	pp = SELF;

	/*
	 * Get ready to go to sleep and do so.
	 */
	s = sphi();
	pp->p_state = (sleepPri == slpriNoSig) ? PSSLEEP : PSSLSIG;
	pp->p_schedPri = schedPri;
	pp->p_event = event;
	fp = &linkq[hash(event)];
	bp = fp->p_lback;
	pp->p_lforw = fp;
	fp->p_lback = pp;
	pp->p_lback = bp;
	bp->p_lforw = pp;
	spl(s);

	/* Here is sleep if signals may *not* interrupt. */
	if (sleepPri == slpriNoSig) {
		dispatch ();
		u.u_sleep [0] = '\0';
		return PROCESS_NORMAL_WAKE;
	}

	/* Here is sleep if signals *may* interrupt. */
	/* Don't sleep at all if there is already a signal pending. */

	if (curr_signal_pending () == 0) {
		dispatch ();
		u.u_sleep [0] = '\0';
		if (curr_signal_pending () == 0)
			return PROCESS_NORMAL_WAKE;
	}

	/* The process has been interrupted from sleep by a signal. */

	if (sleepPri == slpriSigCatch)
		return PROCESS_SIGNALLED;

	/* Do longjmp to beginning of system call. */
	T_HAL(8, printf("[%d]Ljmps ", SELF->p_pid));
	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 "event".
 */
void
dwakeup(event)
char *event;
{
	register PROC *pp;
	register PROC *pp1;
	register int s;

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

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

		/*
		 * Process is waiting on event 'event'.
		 */
		if (pp->p_event == event) {
			/*
			 * 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;
			setrun(pp);

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

/*
 * Select next process for execution, working backward from iprocp.
 * If it is not the idle process, delete it from the run queue.
 * If it is not the current process, consave the current process and
 * conrest the selected process.
 */
dispatch()
{
	register PROC *pp;
	register int s;

	s = sphi();
	pp = iprocp->p_lback;
	if (pp != iprocp) {
		pp->p_lforw->p_lback = pp->p_lback;
		pp->p_lback->p_lforw = pp->p_lforw;
	}
	spl(s);

	quantum = NCRTICK;
	disflag = 0;
	if (pp != 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 = pp;
		if (consave (& u.u_syscon) == 0) {
			conrest (* pp->p_segp [SIUSERP]->s_vmem,
				 & u.u_syscon);
		}

		if (SELF->p_pid) {	/* init is special! */
			ndpConRest ();
			segload ();
		}

		spl (s);
	}
}

/*
 * Add a process to the run queue, just forward of iprocp.
 * This routine must be called at high priority.
 */
setrun(pp)
register PROC *pp;
{
	pp->p_lback = iprocp;
	pp->p_lforw = iprocp->p_lforw;
	pp->p_lback->p_lforw = pp;
	pp->p_lforw->p_lback = pp;
	pp->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->_lock [0]) {
#ifdef	TRACER
		if (g->_lock [0] != 1)
			panic ("Uninitialised gate");
#endif
		g->_lock [1] = 1;
		x_sleep ((char *) g, primed, slpriNoSig, "lock");
		/* Waiting for a gate to unlock.  */
	}
	g->_lock [0] = 1;
	__GATE_LOCK_COUNT (g);
	spl (s);
}

/*
 * Unlock the gate `g'.
 */
unlock(g)
register GATE g;
{
#ifdef	TRACER
	if (g->_lock [0] == 0)
		panic ("Gate not locked!");
#endif
	g->_lock [0] = 0;
	if (g->_lock [1]) {
#ifdef	TRACER
		if (g->_lock [1] != 1)
			panic ("Uninitialised gate");
#endif
		g->_lock [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.