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