improved 4.2BSD signal(2) library routine

gwyn%brl-vld at sri-unix.UUCP gwyn%brl-vld at sri-unix.UUCP
Tue Dec 20 20:31:28 AEST 1983


From:      Doug Gwyn (VLD/VMB) <gwyn at brl-vld>

/*
	signal -- old system call emulation for 4.2BSD (VAX version)
		(adapted from BRL UNIX System V emulation for 4.2BSD)

	last edit:	20-Dec-1983	D A Gwyn

	NOTE:  Although this module is VAX-specific, it should be
	possible to adapt it to other fairly clean implementations of
	4.2BSD.  The difficulty lies in avoiding the automatic restart
	of certain system calls when the signal handler returns.  I use
	here a trick first described by Donn Seeley of UCSD Chem. Dept.
*/

#include	<errno.h>
#include	<signal.h>

extern int	sigvec();
extern int	sigsetmask();

extern		etext;
extern int	errno;

/* # bytes to skip at the beginning of C ret_eintr() function code: */
#define	OFFSET	2			/* for VAX .word reg_mask */

/* PC will be pointing at a syscall if it is to be restarted: */
typedef unsigned char	opcode;		/* one byte long */
#define	SYSCALL	0xBC			/* VAX CHMK instruction */

static int	(*handler[NSIG])() =	/* "current handler" memory */
	{
	BADSIG				/* initially, unknown state */
	};

static int	catchsig();
static int	ret_eintr();

int	(*
signal( sig, func )			/* returns previous handler */
	)()
	register int	sig;		/* signal affected */
	register int	(*func)();	/* new handler */
	{
	register int	(*retval)();	/* previous handler value */
	struct sigvec	oldsv;		/* previous state */
	struct sigvec	newsv;		/* state being set */

	if ( func >= (int (*)())&etext )	/* "lint" hates this */
		{
		errno = EFAULT;
		return BADSIG;		/* error */
		}

	/* cancel pending signals */
	newsv.sv_handler = SIG_IGN;
	newsv.sv_mask = newsv.sv_onstack = 0;
	if ( sigvec( sig, &newsv, &oldsv ) != 0 )
		return BADSIG;		/* error */

	/* the first time for this sig, get state from the system */
	if ( (retval = handler[sig-1]) == BADSIG )
		retval = oldsv.sv_handler;

	handler[sig-1] = func;	/* keep track of state */

	if ( func == SIG_DFL )
		newsv.sv_handler = SIG_DFL;
	else if ( func != SIG_IGN )
		newsv.sv_handler = catchsig;	/* actual sig catcher */

	if ( func != SIG_IGN		/* sig already being ignored */
	  && sigvec( sig, &newsv, (struct sigvec *)0 ) != 0
	   )
		return BADSIG;		/* error */

	return retval;			/* previous handler */
	}

/*ARGSUSED*/
static int
catchsig( sig, code, scp )		/* signal interceptor */
	register int	sig;		/* signal number */
	int		code;		/* code for SIGILL, SIGFPE */
	register struct sigcontext	*scp;	/* -> interrupted context */
	{
	struct sigvec	oldsv;		/* previous state */
	struct sigvec	newsv;		/* state being set */

	/* at this point, sig is blocked */

	/* most UNIXes usually want the state reset to SIG_DFL */
	if ( sig != SIGILL && sig != SIGTRAP )
		{
		newsv.sv_handler = SIG_DFL;
		newsv.sv_mask = newsv.sv_onstack = 0;
		(void)sigvec( sig, &newsv, &oldsv );
		}

	(void)sigsetmask( scp->sc_mask );	/* restore old mask */

	/* at this point, sig is not blocked, usually have SIG_DFL;
	   a longjmp may safely be taken by the user signal handler */

	(void)(*handler[sig-1])( sig );	/* user signal handler */

	/* must now avoid restarting certain system calls */
	if ( *(opcode *)scp->sc_pc == (opcode)SYSCALL )
		scp->sc_pc = (int)ret_eintr + OFFSET;

	/* return here restores interrupted context */
	}


static int
ret_eintr()				/* substitute for system call */
{
	errno = EINTR;
	return -1;
}



More information about the Comp.unix.wizards mailing list