File:  [MW Coherent from dump] / coherent / d / PS2_KERNEL / coh.386 / sig.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

/* $Header: /var/lib/cvsd/repos/coherent/coherent/d/PS2_KERNEL/coh.386/sig.c,v 1.1.1.1 2019/05/29 04:56:39 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 2.3.37
 *	Copyright (c) 1982, 1983, 1984.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * Coherent.
 * Signal handling.
 *
 * $Log: sig.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:39  root
 * coherent
 *
 * Revision 1.2  92/08/04  12:34:36  bin
 * changed for ker 59
 * 
 * Revision 1.2  92/01/06  12:00:24  hal
 * Compile with cc.mwc.
 * 
 * Revision 1.1	88/03/24  16:14:24	src
 * Initial revision
 * 
 * 87/11/05	Allan Cornish		/usr/src/sys/coh/sig.c
 * New seg struct now used to allow extended addressing.
 *
 * 86/11/19	Allan Cornish		/usr/src/sys/coh/sig.c
 * sigdump() initializes the (new) (IO).io_flag field to 0.
 */
#include <sys/coherent.h>
#include <errno.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <sys/io.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <signal.h>

/*
 * Set up the action to be taken on a signal.
 */
usigsys(signal, func)
int	signal;
register void (*func)();
{
	register PROC *pp;
	register sig_t s;
	register int (*old_sig)();
	int	sigtype;

	sigtype = signal & ~0xFF;
	signal ^= sigtype;

	pp = SELF;
	if (signal<=0 || signal>NSIG || signal==SIGKILL) {
		u.u_error = EINVAL;
		return;
	}

	/*
	 * In order to avoid runaway, don't allow user to set
	 * handler for SIGSEGV to anything but SIG_DFL.
	 *
	 * We should do something more sophisticated, like detecting
	 * two SEGV's in a row and then killing the process.
	 */
	if (signal == SIGSEGV && func != SIG_DFL) {
		u.u_error = EINVAL;
		return;
	}

	if (sigtype==SIGDEFER || sigtype==0) {
		if (func==SIG_IGN)
			sigtype = SIGIGNORE;
		if (func==SIG_HOLD)
			sigtype = SIGHOLD;
	}

	s = (sig_t)1 << --signal;
	if (pp->p_isig&s)
		old_sig = SIG_IGN;
	else if (pp->p_hsig&s)
		old_sig = SIG_HOLD;
	else
		old_sig = u.u_sfunc[signal];

	switch (sigtype) {
	case SIGHOLD:
		pp->p_hsig |= s;
		break;
	case SIGRELSE:
		pp->p_hsig &= ~s;
		if (nondsig()) {
			T_PIGGY( 0x100, printf("a(s)"); );
			actvsig();
		}
	case SIGIGNORE:
		pp->p_dfsig &= ~s;	/* No longer defaulted.  */
		pp->p_isig |= s;	/* Mark signal as ignored.  */
		pp->p_ssig &= ~s;	/* Turn off any pending signal.  */
		break;
	case 0:				/* old system entry */
	case SIGDEFER:			/* new system entry */
		u.u_sigreturn = (void (*)())u.u_regl[EDX];
		u.u_sfunc[signal] = func;
		/*
		 * Be sure to mark the signal as defaulted or not.
		 */
		if (SIG_DFL == func) {
			pp->p_dfsig |= s;
		} else {
			pp->p_dfsig &= ~s;
		}
		/*
		 * The signal is no longer ignored or held, and
		 * any pending signal is lost.
		 */
		pp->p_isig &= ~s;
		pp->p_hsig &= ~s;
		pp->p_ssig &= ~s;
		if (sigtype==SIGDEFER)
			pp->p_dsig |= s;
		else
			pp->p_dsig &= ~s;
		break;
	/* SIGPAUSE not done yet */
	default:
		u.u_error = SIGSYS;
		break;
	}
	return old_sig;
}


/*
 * Send a signal to the process `pp'.
 */
sendsig(sig, pp)
register unsigned sig;
register PROC *pp;
{
	register sig_t f;
	register int s;


	T_PIGGY( 0x40000000,
	    printf("<send sig: %d, id: %d, state: %x, flags: %x, event: %x>",
		   sig, pp->p_pid, pp->p_state, pp->p_flags, pp->p_event);
	); /* T_PIGGY() */

	/*
	 * Convert the signal to a bit position.
	 */
	f = ((sig_t)1) << (sig-1);

	/*
	 * If the signal is ignored, do nothing.
	 */
	if (pp->p_isig&f) {
		return;
	}

	/*
	 * This bit causes SIGCHLD to be ignored here in sendsig().
	 */
	T_PIGGY( 0x10000000, {
		if (SIGCHLD == sig) {
			printf("SIGCHLD ignored, ");
			return;
		}
	}
	);

	/*
	 * I do not understand delayed or held signals.
	 */
	if ((pp->p_ssig & f) && (pp->p_hsig|pp->p_dsig) & f)
		return;
	
	/*
	 * Acutally send the signal by flagging the needed bit.
	 */
	pp->p_ssig |= f;

	/*
	 * If the process is sleeping, wake it up so that
	 * it can process this signal.
	 */
	if (pp->p_state == PSSLEEP) {
		s = sphi();
		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);
		spl(s);
	}
}

/*
 * Return signal number if we have a non ignored or delayed signal, else zero.
 */
nondsig()
{
	register PROC *pp;
	register sig_t mask;
	register int signo;

	pp = SELF;
	signo = 0;
	/*
	 * Turn off all ignored signals.
	 */
	pp->p_ssig &= ~pp->p_isig;
	/*
	 * If any signals have arrived, but which are not held,
	 * figure out what they are.
	 */
	if (pp->p_ssig&~pp->p_hsig) {
		/*
		 * There is at least one signal.  Extract its number
		 * from the signal bits.
		 */
		mask = (sig_t) 1;
		signo += 1;
		while (((pp->p_ssig&~pp->p_hsig) & mask) == 0) {
			mask <<= 1;
			signo += 1;
		}
	}
	return (signo);
}

/*
 * If we have a signal that isn't ignored, activate it.
 */
actvsig()
{
	register int n;
	register PROC *pp;
	register int (*func)();
	sig_t s;


	/*
	 * Fetch an unprocessed signal.
	 * Return if there are none.
	 */
	if ((n = nondsig()) == 0)
		return;

	T_PIGGY( 0x40000, {
		if (SIGCHLD == n) {
			printf("-");
			return;
		}
	} );

	pp = SELF;

	/*
	 * Reset the signal to indicate that it has been processed.
	 */
	--n;
	pp->p_ssig &= ~((sig_t)1<<n);

	/*
	 * Fetch the user function that goes with this signal.
	 */
	func = u.u_sfunc[n];

	/*
	 * Store the signal number in the u area.  This is how
	 * a core dump records the death signal.
	 */
	u.u_signo = ++n;

	/*
	 * If the signal is not defaulted, go run the requested
	 * function.
	 */
	if (func != SIG_DFL) {
		if (XMODE_286)
			oldsigstart(n, func);
		else
			msigstart(n, func);
		return;
	}

	/*
	 * ASSERTION:  the signal being processed is SIG_DFL'd.
	 */

	/*
	 * msysgen() is a nop for COHERENT 4.0.  The comment in the
	 * assembly code is "Nothing useful to save".
	 */
	msysgen(u.u_sysgen);

	/*
	 * Do something special for traced processes.  (?)
	 */
	if (pp->p_flags&PFTRAC) {
		pp->p_flags |= PFWAIT;
		n = ptret();
		pp->p_flags &= ~(PFWAIT|PFSTOP);
		if (n == 0)
			return;
	}

	/*
	 * Some signals cause a core file to be written.
	 */
	switch(n) {
	case SIGQUIT:
	case SIGILL:
	case SIGTRAP:
	case SIGABRT:
	case SIGFPE:
	case SIGSEGV:
	case SIGSYS:
		if (sigdump())
			n |= 0200;
		break;
	}
	pexit(n);
}

/*
 * Create a dump of ourselves onto the file `core'.
 */
sigdump()
{
	register INODE *ip;
	register SR *srp;
	register SEG * sp;
	register int n;
	register paddr_t ssize;
	extern	int	DUMP_LIM;

	if (SELF->p_flags&PFNDMP)
		return (0);
	u.u_io.io_seg  = IOSYS;
	u.u_io.io_flag = 0;
	/* Make the core with the real owners */
	schizo();
	if (ftoi("core", 'c')) {
		schizo();
		return (0);
	}
	if ((ip=u.u_cdiri) == NULL) {
		if ((ip=imake(IFREG|0644, 0)) == NULL) {
			schizo();
			return (0);
		}
	} else {
		if ((ip->i_mode&IFMT)!=IFREG
		 || iaccess(ip, IPW)==0
		 || getment(ip->i_dev, 1)==NULL) {
			idetach(ip);
			schizo();
			return (0);
		}
		iclear(ip);
	}
	schizo();
	u.u_error = 0;
	u.u_io.io_seek = 0;
	for (srp=u.u_segl; u.u_error==0 && srp<&u.u_segl[NUSEG]; srp++) {
		if ((sp = srp->sr_segp)==NULL || (srp->sr_flag&SRFDUMP)==0)
			continue;
		u.u_io.io_seg = IOPHY;
		u.u_io.io.pbase = MAPIO(sp->s_vmem, 0);
		u.u_io.io_flag = 0;
		ssize = sp->s_size;
		if (ssize > DUMP_LIM) {
			printf("seg %d truncated from %d to %d bytes\n",
			  srp-u.u_segl, ssize, DUMP_LIM);
			ssize = DUMP_LIM;
		}
		sp->s_lrefc++;
		while (u.u_error == 0 && ssize != 0) {
			n = ssize > SCHUNK ? SCHUNK : ssize;
			u.u_io.io_ioc = n;
			iwrite(ip, &u.u_io);
			u.u_io.io.pbase += n;
			ssize -= (paddr_t)n;
		}
		sp->s_lrefc--;
	}
	idetach(ip);
	return (u.u_error==0);
}

/*
 * Send a ptrace command to the child.
 */
ptset(req, pid, addr, data)
unsigned req;
int *addr;
{

	register PROC *pp;

	lock(pnxgate);
	for (pp=procq.p_nforw; pp!=&procq; pp=pp->p_nforw)
		if (pp->p_pid == pid)
			break;
	unlock(pnxgate);
	if (pp==&procq || (pp->p_flags&PFSTOP)==0 || pp->p_ppid!=SELF->p_pid){
		u.u_error = ESRCH;
		return;
	}
	lock(pts.pt_gate);
	pts.pt_req = req;
	pts.pt_pid = pid;
	pts.pt_addr = addr;
	pts.pt_data = data;
	pts.pt_errs = 0;
	pts.pt_rval = 0;
	pts.pt_busy = 1;
	wakeup((char *)&pts.pt_req);
	while (pts.pt_busy) {
		v_sleep((char *)&pts.pt_busy, CVPTSET, IVPTSET, SVPTSET, "ptrace");
		/* Send a ptrace command to the child.  */
	}
	u.u_error = pts.pt_errs;
	unlock(pts.pt_gate);
	return (pts.pt_rval);
}

/*
 * This routine is called when a child that is being traced receives a signal
 * that is not caught or ignored.  It follows up on any requests by the parent
 * and returns when done.
 */
ptret()
{
	register PROC *pp;
	register PROC *pp1;
	register int sign;
	unsigned off;

	pp = SELF;
next:
	u.u_error = 0;
	if (pp->p_ppid == 1)
		return (SIGKILL);
	sign = -1;
	lock(pnxgate);
	pp1 = &procq;
	for (;;) {
		if ((pp1=pp1->p_nforw) == &procq) {
			sign = SIGKILL;
			break;
		}
		if (pp1->p_pid != pp->p_ppid)
			continue;
		if (pp1->p_state == PSSLEEP)
			wakeup((char *)pp1);
		break;
	}
	unlock(pnxgate);
	while (sign < 0) {
		if (pts.pt_busy==0 || pp->p_pid!=pts.pt_pid) {
			v_sleep((char *)&pts.pt_req, CVPTRET, IVPTRET, SVPTRET, "ptret");
			/* Something about signals to a traced child.  */
			goto next;
		}
		switch (pts.pt_req) {
		case 1:
			if (XMODE_286) {
				pts.pt_rval = getuwd(NBPS+pts.pt_addr);
				break;
			}
		case 2:
			pts.pt_rval = getuwd(pts.pt_addr);
			break;
		case 3:
			off = (unsigned)pts.pt_addr;
			if (off < UPASIZE)
				pts.pt_rval = *(int *)((char *)&u+off);
			else
				u.u_error = EINVAL;
			break;
		case 4:
			if (XMODE_286) {
				putuwd(NBPS+pts.pt_addr, pts.pt_data);
				break;
			}
		case 5:
			putuwd(pts.pt_addr, pts.pt_data);
			break;
		case 6:
			if (msetuof(pts.pt_addr, pts.pt_data) == 0)
				u.u_error = EINVAL;
			break;
		case 7:
			goto sig;
		case 8:
			sign = SIGKILL;
			break;
		case 9:
			msigsin();
		sig:
			if (pts.pt_data<0 || pts.pt_data>NSIG) {
				u.u_error = EINVAL;
				break;
			}
			sign = pts.pt_data;
			if (pts.pt_addr != SIG_IGN)
				msetppc((vaddr_t)pts.pt_addr);
			break;
		default:
			u.u_error = EINVAL;
		}
		if ((pts.pt_errs=u.u_error) == EFAULT)
			pts.pt_errs = EINVAL;
		pts.pt_busy = 0;
		wakeup((char *)&pts.pt_busy);
	}
	return (sign);
}

unix.superglobalmegacorp.com

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