File:  [MW Coherent from dump] / coherent / b / kernel / coh.386 / sys1.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 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) */
/*
 * coh.386/sys1.c
 *
 * Coherent.
 * General system calls.
 *
 * Revised: Tue May 11 11:12:03 1993 CDT
 */
#include <sys/coherent.h>
#include <sys/acct.h>
#include <sys/con.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/times.h>

/*
 * Send alarm signal to specified process - function timed by ualarm()
 */
sigalrm(pp)
register PROC * pp;
{
	sendsig(SIGALRM, pp);
}

/*
 * Send a SIGALARM signal in `n' seconds.
 */
ualarm(n)
unsigned n;
{
	register PROC * pp = SELF;
	register unsigned s;

	/*
	 * Calculate time left before current alarm timeout.
	 */
	s = 0;
	if (pp->p_alrmtim.t_last != NULL)
		s = (pp->p_alrmtim.t_lbolt - lbolt + HZ - 1) / HZ;

	/*
	 * Cancel previous alarm [if any], start new alarm [if n != 0].
	 */
	timeout2(&pp->p_alrmtim, (long) n * HZ, sigalrm, pp);

	/*
	 * Return time left before previous alarm timeout.
	 */
	return(s);
}


/*
 * Change the size of our data segment.
 */
char *
ubrk(cp)
caddr_t cp;
{
	register SEG *sp;
	register caddr_t sb;
	register SR	*stack_sr;
	caddr_t top_of_stack;

	T_HAL(0x8000, printf("%s:ubrk(%x) ", u.u_comm, cp));

	/*
	 * Pick up the segment handle for our data segment.
	 */
	sp = SELF->p_segp[SIPDATA];

	/*
	 * Extract the starting virtual address for our data segment,
	 * as it is currently mapped into the memory space.
	 */
	sb = u.u_segl[SIPDATA].sr_base;

	/*
	 * We can not move the top of the data segment below the
	 * start of the data segment.
	 */
	if (cp < sb) {
		SET_U_ERROR(ENOMEM,
		    "Requested brk address is below start of data segment.");
		return 0;
	}

	/*
	 * Would the request cause a collision with the stack segment?
	 *
	 * Since the stack grows downward, its top is below its base :-).
	 */
	stack_sr = &u.u_segl[SISTACK];
	top_of_stack = (stack_sr->sr_base) - (stack_sr->sr_size);

	if (btoc(cp) >= btoc(top_of_stack)) {
		SET_U_ERROR(ENOMEM,
		    "Requested brk address would collide with stack segment.");
 		return 0;
	}

	/*
	 * Attempt to establish the segment with the newly requested size.
	 */
	segsize(sp, (cp - sb));

	/*
	 * Be sure to return the true new top of data segment.
	 */
	sb += sp->s_size;

	T_HAL(0x8000, printf("=%x ", sb));
	return sb;
}

/*
 * Execute a l.out.
 */
uexece(np, argp, envp)
char *np;
char *argp[];
char *envp[];
{
	pexece(np, argp, envp);
}

/*
 * Exit.
 */
uexit(s)
{
	pexit(s<<8);
}

/*
 * Fork.
 */
ufork()
{
	return (pfork());
}

/*
 * Get group id.
 * Get effective group id.
 */
ugetgid()
{
	u.u_rval2 = u.u_gid;
	return u.u_rgid;
}

/*
 * Get user id.
 * Get effective user id.
 */
ugetuid()
{
	u.u_rval2 = u.u_uid;
	return u.u_ruid;
}

/*
 * Get process group.
 * Set the process group.
 *
 * This is System V type setpgrp().
 * Set process group equal to process id (make process its own group leader).
 * If process was NOT already a group leader, lose its controlling terminal.
 */
upgrp(fl)
{
	register PROC * pp = SELF;
	
	if (fl) {
		if (pp->p_group != pp->p_pid)
			pp->p_ttdev = NODEV;
		pp->p_group = pp->p_pid;
	}
	return pp->p_group;
}

/*
 * Get process id.
 */
ugetpid()
{
	register PROC *pp = SELF;

	u.u_rval2 = pp->p_ppid;
	return pp->p_pid;
}

/*
 * Send the signal `sig' to the process with id `pid'.
 */
ukill(pid, sig)
int pid;
register unsigned sig;
{
	register PROC *pp;
	register int sigflag;

	if (sig > NSIG) {
		u.u_error = EINVAL;
		return;
	}
	sigflag = 0;
	lock(pnxgate);
	if (pid > 0) {	/* send to matching process */
		for (pp=procq.p_nforw; pp != &procq; pp=pp->p_nforw) {
			if (pp->p_state == PSDEAD)
				continue;
			if (pp->p_pid == pid) {
				sigflag = 1;
				if (sig) {
					if (sigperm(sig, pp))
						sendsig(sig, pp);
					else
						u.u_error = EPERM;
				}
				break;
			}
		}
	}
	else if (pid < -1) {
		pid = -pid;
		for (pp=procq.p_nforw; pp != &procq; pp=pp->p_nforw) {
			if (pp->p_state == PSDEAD)
				continue;
			if (pp->p_group == pid) {
				sigflag = 1;
				if (sig) {
					if (sigperm(sig, pp))
						sendsig(sig,pp);
					else
						u.u_error = EPERM;
				}
			}
		}
	}
	else if (pid == 0) {
		for (pp=procq.p_nforw; pp != &procq; pp=pp->p_nforw) {
			if (pp->p_state == PSDEAD)
				continue;
			if (pp->p_group == SELF->p_group) {
				sigflag = 1;
				if (sig && sigperm(sig, pp))
					sendsig(sig, pp);
			}
		}
	}
	else if (pid == -1) {
		for (pp=procq.p_nforw; pp != &procq; pp=pp->p_nforw) {
			if (pp->p_state == PSDEAD)
				continue;
			if (pp->p_pid == 0)
				continue;
			if (pp->p_pid == 1)
				continue;
			if (pp->p_flags & PFKERN)
				continue;
			sigflag = 1;
			if (sig && super())
				sendsig(sig, pp);
		}
	}
	unlock(pnxgate);
	if (sigflag == 0)
		u.u_error = ESRCH;
	return 0;
}

/*
 * See if we have permission to send the signal, `sig' to the process, `pp'.
 */
sigperm(sig, pp)
register PROC *pp;
{
	if (u.u_uid == pp->p_uid)
		return (1);
	if (u.u_ruid == pp->p_ruid) {
		if (sig == SIGHUP
		||  sig == SIGINT
		||  sig == SIGQUIT
		||  sig == SIGTERM)
			return (1);
	}
	if (u.u_uid == 0) {
		u.u_flag |= ASU;
		return (1);
	}
	return 0;
}

/*
 * Lock a process in core.
 */
ulock(f)
{
	if (super() == 0)
		return;
	if (f)
		SELF->p_flags |= PFLOCK;
	else
		SELF->p_flags &= ~PFLOCK;
	return 0;
}

/*
 * Change priority by the given increment.
 */
unice(n)
register int n;
{
	n += SELF->p_nice;
	if (n < MINNICE)
		n = MINNICE;
	if (n > MAXNICE)
		n = MAXNICE;
	if (n<SELF->p_nice && super()==0)
		return;
	SELF->p_nice = n;
	return 0;
}

/*
 * Non existant system call.
 */
unone()
{
	u.u_error = EFAULT;
}

/*
 * Null system call.
 */
unull()
{
}

/*
 * Pause.  Go to sleep on a channel that nobody will wakeup so that only
 * signals will wake us up.
 */
upause()
{
	x_sleep((char *)&u, prilo, slpriSigLjmp, "pause");
}

/*
 * Start/stop profiling.
 *
 * buff:	address in user data of an array of shorts
 * bufsiz:	number of bytes in the area at buff
 * offset:	address in user text of start of profiling area
 * scale:	0 or 1 - turn off profiling
 *		other - treat as 16 bit scale factor
 *
 * For purposes of compatibility with System 5, scale values work as follows:
 *	0xFFFF	profile buffer is same length as text being profiled.
 *	0x7FFF  profile buffer is half as long as text being profiled.
 *	0x4000	profile buffer is one fourth as long as text profiled.
 *		(each short in the buffer covers 8 bytes of text)
 *	...	...
 *	0x0002	each short in the buffer covers 64K bytes of text.
 *
 * Values 0xFFFF and 0x7FFF are used, for historical reasons, when 0x10000
 * and 0x8000, respectively, should be used.  To clean up the ensuing
 * arithmetic, there is an upward rounding kluge below.
 *
 * Each clock interrupt, take (pc - offset) * scale * (2**-16) as a byte
 * offset into pbase.  Add 1 to the short at or below the given address
 * when profiling.
 */
uprofil(buff, bufsiz, offset, scale)
short * buff;
int bufsiz, offset, scale;
{
	u.u_pbase = buff;
	u.u_pbend = buff + bufsiz;
	u.u_pofft = offset;
	u.u_pscale = scale & 0xffff;	/* scale is really unsigned short */

	/* round up kluge - see above */
	if ((scale & 0xfff) == 0xfff)
		u.u_pscale++;
}

/*
 * Process trace.
 */
uptrace(req, pid, add, data)
int *add;
{
	int ret;

#ifdef TRACER
	int readChild = 0;	/* for debug, true if reading child memory */

	if (t_hal & 0x10000) {
		switch(req) {
		case 0:	/* init called by child */
			printf("PSetup: child=%d  ", SELF->p_pid);
			break;
		case 1:	/* parent reads child text */
			printf("PRdT: add=%x ", add);
			readChild = 1;
			break;
		case 2:	/* parent reads child data */
			printf("PRdD: add=%x ", add);
			readChild = 1;
			break;
		case 3:	/* parent reads child u area */
			printf("PRdU: add=%x ", add);
			readChild = 1;
			break;
		case 4:	/* parent writes child text */
			printf("PWrT: add=%x data=%x  ", add, data);
			break;
		case 5:	/* parent writes child data */
			printf("PWrD: add=%x data=%x  ", add, data);
			break;
		case 6:	/* parent writes child u area */
			printf("PWrU: add=%x data=%x ", add, data);
			break;
		case 7:	/* resume child, maybe fake signal to child */
			printf("PResume: sig=%d  ", data);
			break;
		case 8:	/* terminate child */
			printf("PTerm: pid=%d  ", pid);
			break;
		case 9:	/* single-step child, maybe fake signal to child */
			printf("PSStp: sig=%d  ", data);
			break;
		}
	}
#endif

	if (req == 0) {
		SELF->p_flags |= PFTRAC;
		ret = 0;
	} else
		ret = ptset(req, pid, add, data);

#ifdef TRACER
	if (t_hal & 0x10000) {
		if (readChild)
			printf("data=%x  ", ret);
	}
#endif

	return ret;
}

/*
 * Set group id.
 *
 * As in SVID issue 2:
 *
 * if effective gid is superuser
 *	set real, effective, and saved effective gid to argument "gid"
 * else if real gid is same as "gid"
 *	set effective gid to "gid"
 * else if saved effective gid is same as "gid"
 *	set effective gid to "gid"
 */
usetgid(gid)
register int gid;
{
	if (super()) {
		u.u_gid = u.u_rgid = u.u_egid = gid;
		SELF->p_rgid = gid;
	} else {
		u.u_error = 0;  /* super() sets u_error when it fails */
		if (u.u_rgid == gid || u.u_egid == gid) {
			u.u_gid = gid;
		} else {
			SET_U_ERROR(EPERM, "Illegal gid");
		}
	}
	return 0;
}

/*
 * Set user id.
 *
 * As in SVID issue 2:
 *
 * if effective uid is superuser
 *	set real, effective, and saved effective uid to argument "uid"
 * else if real uid is same as "uid"
 *	set effective uid to "uid"
 * else if saved effective uid is same as "uid"
 *	set effective uid to "uid"
 */
usetuid(uid)
register int uid;
{
	if (super()) {
		u.u_uid = u.u_ruid = u.u_euid = uid;
		SELF->p_uid = SELF->p_ruid = uid;
	} else {
		u.u_error = 0;  /* super() sets u_error when it fails */
		if (u.u_ruid == uid || u.u_euid == uid) {
			SELF->p_uid = u.u_uid = uid;
		} else {
			SET_U_ERROR(EPERM, "Illegal uid");
		}
	}
	return 0;
}

/*
 * Load a device driver.
 */
usload(np)
char *np;
{
	return pload(np);
}

/*
 * Set time and date.
 *
 * Unlike the libc interface, this routine expects a time_t value
 * as an arg, not a time_t pointer.
 */
ustime(tp)
time_t tp;
{
	register int s;

	if (super() == 0) {
		return;
	}
	s = sphi();
	ukcopy(&tp, &timer.t_time, sizeof(tp));
	spl(s);
	return 0;
}

/*
 * Return process times.
 */
utimes(tp)
struct tms *tp;
{
	register PROC *pp;
	struct tms tbuffer;

	if (tp) {
		pp = SELF;
		tbuffer.tms_utime = pp->p_utime;
		tbuffer.tms_stime = pp->p_stime;
		tbuffer.tms_cutime = pp->p_cutime;
		tbuffer.tms_cstime = pp->p_cstime;
		kucopyS(&tbuffer, tp, sizeof(tbuffer));
	}
	return lbolt;
}

/*
 * Unload a device driver.
 */
usuload(m)
register int m;
{
	if (super() == 0)
		return;
	puload(m);
	return 0;
}

/*
 * Wait for a child to terminate.
 *
 * iBCS2 says the same system call number is wait() and waitpid(), the
 * distinction being in how the psw is set on entry.
 *
 * iBCS2 fails to mention that when wait() or waitpid() report status
 * by writing into the pointer supplied, the status is put into %edx by
 * the kernel, and moved from there into user space by the function in
 * libc.a.  uwait() and uwaitpid() specify a value for %edx by writing
 * to u.u_rval2.
 *
 * Do wait() unless (ZF|PF|SF|OF) (=WPMASK) are set in psw.
 */
#define	WPMASK	0x8C4

uwait(arg1, arg2, arg3)
{
	register PROC *pp;
	register PROC *ppp;
	register PROC *cpp;
	register int pid;

	if ((u.u_regl[EFL] & WPMASK) == WPMASK)
		return uwaitpid(arg1, arg2, arg3);

	/* Wait for a child to stop or die. */
	T_HAL(8, printf("[%d]waits ", SELF->p_pid));
	ppp = SELF;
	for (;;) {
		int x_s;

		/* Look at all processes. */
		lock(pnxgate);
		cpp = NULL;
		pp = &procq;
		while ((pp=pp->p_nforw) != &procq) {

			/* Ignore the current process. */
			if (pp == ppp)
				continue;
			/*
			 * Ignore processes that aren't children of the
			 * current one.
			 */
			if (pp->p_ppid != ppp->p_pid)
				continue;
			if (pp->p_flags&PFSTOP)
				continue;

			/* Here is a child that hit a breakpoint. */
			if (pp->p_flags&PFWAIT) {
				int work;	/* virtual click number */
				int childUseg;	/* system global addr */
				UPROC * uprc;
				SEG * sp;

				pp->p_flags &= ~PFWAIT;
				pp->p_flags |= PFSTOP;

				/* fetch u.u_signo from the child */

				/* Find u area for child process pp */
				sp = pp->p_segp[SIUSERP];
				childUseg = MAPIO(sp->s_vmem, U_OFFSET);
				work = workAlloc();
				ptable1_v[work] =
				  sysmem.u.pbase[btocrd(childUseg)] | SEG_RW;
				mmuupd();
				uprc = (UPROC *) (ctob(work) + U_OFFSET);
				u.u_rval2 = ((uprc->u_signo)<<8) | 0177;
				workFree(work);

				unlock(pnxgate);
				T_HAL(8, printf("[%d]ends waiting, %d stopped ",
				  SELF->p_pid, pid));
				return pp->p_pid;
			}
			if (pp->p_state == PSDEAD) {
				ppp->p_cutime += pp->p_utime + pp->p_cutime;
				ppp->p_cstime += pp->p_stime + pp->p_cstime;
				u.u_rval2 = pp->p_exit;
				pid = pp->p_pid;
				unlock(pnxgate);
				relproc(pp);
				if (SIG_BIT(SIGCLD) & ppp->p_isig)
					continue;
				else {
					T_HAL(8, printf("[%d]ends waiting,"
					  " %d died ", SELF->p_pid, pid));
					return pid;
				}
			}
			cpp = pp;
		}
		unlock(pnxgate);
		if (cpp == NULL) {
			T_HAL(8, printf("[%d]ends waiting, no children ",
			  SELF->p_pid));
			u.u_error = ECHILD;
			return;
		}
		x_s = x_sleep((char *)ppp, prilo, slpriSigLjmp, "wait");
		/* Wait for a child to terminate.  */
	}
}

/*
 * waitpid() and wait() share the same system call number under BCS.
 *
 * pid argument:
 *	>  0	wait for child whose process matches pid
 *	=  0	wait for any child in current process group
 *	= -1	wait for any child - same as wait()
 *	< -1	wait for any child in group given by -pid
 *
 * The only waitpid() options supported are WNOHANG and WUNTRACED.
 *
 */
int
uwaitpid(opid, stat_loc, options)
register pid_t opid;
int	*stat_loc, options;
{
	register PROC *pp;
	register PROC *ppp;
	register PROC *cpp;
	register int pid;

	if (options & WUNTRACED) {	
                printf("waitpid(%d,%d, WUNTRACED): unsupported\n", opid,
								     stat_loc);
		u.u_error = EINVAL;
		return;
	}

	/* Wait for a child to stop or die. */
	ppp = SELF;
	for (;;) {
		int x_s;

		/* Look at all processes. */
		lock(pnxgate);
		cpp = NULL;
		pp = &procq;
		while ((pp=pp->p_nforw) != &procq) {

			/* Ignore the current process. */
			if (pp == ppp)
				continue;
			/*
			 * Ignore processes that aren't children of the
			 * current one.
			 */
			if (pp->p_ppid != ppp->p_pid)
				continue;

			if (pp->p_flags&PFSTOP)
				continue;

			/* If opid == 0 we want to match gids */
			if ((opid == 0) && (pp->p_group != ppp->p_group))
				continue;

			/* If opid>0, want to match opid to child pid */
			else if ((opid > 0) && (opid != pp->p_pid))
				continue;

			/* If opid<-1, want to match -opid to child gid */
			else if ((opid < -1) && ((-opid) != pp->p_group))
				continue;

			/* if opid == -1, then any child is acceptable */

			/* Here is an acceptable child that hit a breakpoint. */
			if (pp->p_flags&PFWAIT) {
				int work;	/* virtual click number */
				int childUseg;	/* system global addr */
				UPROC * uprc;
				SEG * sp;

				pp->p_flags &= ~PFWAIT;
				pp->p_flags |= PFSTOP;

				/* fetch u.u_signo from the child */

				/* Find u area for child process pp */
				sp = pp->p_segp[SIUSERP];
				childUseg = MAPIO(sp->s_vmem, U_OFFSET);
				work = workAlloc();
				ptable1_v[work] =
				  sysmem.u.pbase[btocrd(childUseg)] | SEG_RW;
				mmuupd();
				uprc = (UPROC *) (ctob(work) + U_OFFSET);
				u.u_rval2 = ((uprc->u_signo)<<8) | 0177;
				workFree(work);

				unlock(pnxgate);
				return pp->p_pid;
			}

			/* Here is an acceptable child that is a zombie. */
			if (pp->p_state == PSDEAD) {
				ppp->p_cutime += pp->p_utime + pp->p_cutime;
				ppp->p_cstime += pp->p_stime + pp->p_cstime;
				u.u_rval2 = pp->p_exit;
				pid = pp->p_pid;
				unlock(pnxgate);
				relproc(pp);
				if (SIG_BIT(SIGCLD) & ppp->p_isig)
					continue;
				else {
					return pid;
				}
			}
			cpp = pp;
		}
		unlock(pnxgate);
		if (cpp == NULL) {
			u.u_error = ECHILD;
			return;
		}

		if (options & WNOHANG) {
               		u.u_rval2 = 0;
			return 0;
		}
		else
			/* Wait for a child to terminate. */
			x_s = x_sleep((char *)ppp, prilo, slpriSigLjmp,
			  "waitpid");
	}
}

unix.superglobalmegacorp.com

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