pdp-11 signals

utzoo!decvax!harpo!npois!ucbvax!dove at mit-dspg utzoo!decvax!harpo!npois!ucbvax!dove at mit-dspg
Tue May 18 13:47:33 AEST 1982


From: dove at mit-dspg at mit-mc
I found the solution to the signal catching problem I had been having.
I changed the code in /usr/sys/sig.c in the following way:
---before--
psig()
{
	register n, p;
	register struct proc *rp;

	rp = u.u_procp;
	if (u.u_fpsaved==0) {
		savfp(&u.u_fps);
		u.u_fpsaved = 1;
	}
	if (rp->p_flag&STRC)
		stop();
	while(n = fsig(rp)) {
		rp->p_sig &= ~(1<<(n-1));
		if((p=u.u_signal[n]) != 0) {
			u.u_error = 0;
			if(n != SIGILL && n != SIGTRAP)
				u.u_signal[n] = 0;
			sendsig((caddr_t)p, n);
		} else {
			switch(n) {

			case SIGQUIT:
			case SIGILL:
			case SIGTRAP:
			case SIGIOT:
			case SIGEMT:
			case SIGFPE:
			case SIGBUS:
			case SIGSEGV:
			case SIGSYS:
				if(core())
					n += 0200;
			}
			exit(n);
		}
	}
}
--after--
psig()
{
	register n, p;
	register struct proc *rp;

	rp = u.u_procp;
	if (u.u_fpsaved==0) {
		savfp(&u.u_fps);
		u.u_fpsaved = 1;
	}
	if (rp->p_flag&STRC)
		stop();
	/*
	 * Scan for a SIG_DFL signal first.  This is to guarantee that
	 * the user doesn't go into a signal fielding loop forever.
	 */
	while(n = fdsig(rp))
	{
		rp->p_sig &= ~(1<<(n-1));
		switch(n)
		{
		case SIGQUIT:
		case SIGILL:
		case SIGTRAP:
		case SIGIOT:
		case SIGEMT:
		case SIGFPE:
		case SIGBUS:
		case SIGSEGV:
		case SIGSYS:
			if(core())
				n += 0200;
		}
		exit(n);
	}
	
	/*
	 * Scan again for any signals (SIG_DFL may have come in in
	 * the mean time so check for them too)
	 */
	while(n = fsig(rp))
	{
		rp->p_sig &= ~(1<<(n-1));
		if((p=u.u_signal[n]) != 0)
		{
			if(p==1) /* this SIG_IGN came in since issig() */
				continue;
			u.u_error = 0;
			if(n != SIGILL && n != SIGTRAP)
				u.u_signal[n] = 0;
			/* arrange for user to execute it on return */
			sendsig((caddr_t)p, n);
			/* can only do one of these so must leave now */
			/* and process others next system call */
			break;
		}
		else
		{
			switch(n)
			{
			case SIGQUIT:
			case SIGILL:
			case SIGTRAP:
			case SIGIOT:
			case SIGEMT:
			case SIGFPE:
			case SIGBUS:
			case SIGSEGV:
			case SIGSYS:
				if(core())
					n += 0200;
			}
			exit(n);
		}
	}
}

----
This reflects 2 changes.

1) The added continue is in case an ignored signal comes in after the 
call to issig() (which clears any such signals) .  One cannot try
having the user prog start executing the code at user address 1 since
that causes odd address traps.

2) The break is because no more than one caught signal can be handled
per system trap.  Subsequent ones must be collected on subsequent traps.

3) The preliminary scan for defaulted signals is in case the user gets
into a loop of catching a signal and causing it.  That essentially
raises the priority of SIG_DFL signals above that of caught ones.


These problems were demonstrated with the following program:
#include <stdio.h>
#include <signal.h>

getsig(sig)
{
	signal(sig, SIG_IGN);
	fprintf(stderr, "sig(%d)\n", sig);
	signal(sig, getsig);
}

main()
{
	int tmp, count=100;
	
	signal(SIGINT, getsig);
	signal(SIGQUIT, getsig);
	while(count-->0)
	{
		fprintf(stderr, "                                     \r");
/*		if((tmp=sleep(1))!=0)
			fprintf(stderr, "%d=sleep(1)", tmp);*/
	}
	fprintf(stderr, "done\n");
}

One just runs it and hits <interrupt> and <quit> together as fast
as possible.  If you have the problem I had, the program will die early,
either from an odd address trap or from one of the two signals.

-------------------------------------
By the way, who knows what sends the user into the kernel to deal with
these signals in the first place?  Interrupts don't appear to exit through
_trap which is where the signals are dealt with.



More information about the Comp.bugs.2bsd mailing list