signal(2) emulation for 4.2BSD
gwyn%brl-vld at sri-unix.UUCP
gwyn%brl-vld at sri-unix.UUCP
Fri Jan 13 22:35:57 AEST 1984
From: Doug Gwyn (VLD/VMB) <gwyn at brl-vld>
I found the following problems in the previously posted emulation:
(1) Incorrect initialization of the local handler history array;
(2) Failure to update the history to SIG_DFL in the signal catcher.
The following code replaces the previous submission. It does not
depend on the BRL kernel modification you have been hearing about
recently. Recipients of the BRL UNIX System V emulation for 4.2BSD
should install corresponding corrections in the two signal.c source
files and rebuild things, especially the Bourne shell.
/*
signal -- old system call emulation for 4.2BSD (VAX version)
(adapted from BRL UNIX System V emulation for 4.2BSD)
last edit: 13-Jan-1984 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>
#include <syscall.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 ((opcode)0xBC) /* VAX CHMK instruction */
#define IMMEDIATE ((opcode)0x8F) /* VAX immediate addressing */
static int (*handler[NSIG])() = /* "current handler" memory */
{
BADSIG /* initially, unknown state */
};
static int inited = 0; /* for initializing above */
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 */
/* C language provides no good way to initialize handler[] */
if ( !inited ) /* once only */
{
register int i;
for ( i = 1; i < NSIG; ++i )
handler[i] = BADSIG; /* initialize */
++inited;
}
/* 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 */
{
register opcode *pc; /* for snooping instructions */
struct sigvec newsv; /* state being set */
register int (*uhandler)() = handler[sig-1]; /* user handler */
/* at this point, sig is blocked */
/* most UNIXes usually want the state reset to SIG_DFL */
if ( sig != SIGILL && sig != SIGTRAP )
{
handler[sig-1] = newsv.sv_handler = SIG_DFL;
newsv.sv_mask = newsv.sv_onstack = 0;
(void)sigvec( sig, &newsv, (struct sigvec *)0 );
}
(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)(*uhandler)( sig ); /* user signal handler */
/* must now avoid restarting certain system calls */
pc = (opcode *)scp->sc_pc;
if ( *pc++ == SYSCALL
&& (*pc == SYS_read || *pc == SYS_write || *pc == SYS_ioctl
|| *pc++ == IMMEDIATE
&& (*pc == SYS_wait || *pc == SYS_readv || *pc == SYS_writev)
)
)
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