avoiding 4.2BSD restart of read() after signal
VLD/VMB
gwyn at BRL.ARPA
Sat Jan 18 00:41:49 AEST 1986
/*
signal -- old system call emulation for 4.2BSD (VAX & Gould)
(adapted from BRL UNIX System V emulation for 4.2BSD)
last edit: 10-Jan-1986 D A Gwyn
NOTE: Although this module contains CPU-specific code, it
should be possible to adapt it to other 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();
#ifdef sel
extern int csrt(); /* start of executable text */
#endif
extern etext; /* end of executable text */
extern int errno;
static int (*handler[NSIG])() = /* "current handler" memory */
{
BADSIG /* initially, unknown state */
};
static int inited = 0; /* for initializing above */
static int catchsig();
#ifdef sel
extern int __ret_eintr();
asm(" .text");
asm(" .globl ___ret_intr");
asm(" .align 2");
asm("___ret_eintr:");
asm(" movw #4,r0 -- EINTR");
asm(" jmp cerror -- acts like error return from syscall");
asm(" .data");
#else
static int
__ret_eintr() /* substitute for system call */
{
errno = EINTR; /* <-- resumed starting here */
return -1;
}
#endif
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 */
#ifdef sel
|| func != SIG_DFL
&& func != SIG_IGN
&& func <= (int (*)())csrt
#endif
) {
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 */
}
#ifdef accel /* supplied by David Barto */
/* # bytes to skip at the beginning of __ret_eintr() function code: */
#define OFFSET 0 /* start at beginning */
/* PC will be pointing at a syscall if it is to be restarted: */
typedef unsigned char opcode; /* one byte long */
#define SYSCALL ((opcode)0x18) /* ACCEL syscall instruction */
/* restartable syscall codes: */
#define READ SYS_read
#define WRITE SYS_write
#define IOCTL SYS_ioctl
#define WAIT SYS_wait
#define READV SYS_readv
#define WRITEV SYS_writev
#else
#ifdef sel
/* # bytes to skip at the beginning of __ret_eintr() function code: */
#define OFFSET 0 /* start at beginning */
/* PC will be pointing at a syscall if it is to be restarted: */
typedef unsigned short opcode; /* one halfword long */
#define SYSCALL ((opcode)0xC806)/* Gould SVC instruction */
#define INDEX 0x1000 /* Gould SVC vector index 1 */
/* restartable syscall codes: */
#define READ (INDEX | SYS_read)
#define WRITE (INDEX | SYS_write)
#define IOCTL (INDEX | SYS_ioctl)
#define WAIT (INDEX | SYS_wait)
#define READV (INDEX | SYS_readv)
#define WRITEV (INDEX | SYS_writev)
#else
#ifdef vax
/* # bytes to skip at the beginning of __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 */
/* restartable syscall codes: */
/* syscall codes < 64 are assembled in "literal" mode */
#define READ SYS_read
#define WRITE SYS_write
#define IOCTL SYS_ioctl
/* syscall codes > 63 are assembled in "immediate" mode; there is
actually another 0 byte after the syscall code too */
#define WAIT SYS_wait
#define READV SYS_readv
#define WRITEV SYS_writev
#else
#include "*** ERROR *** signal.c needs to be edited for CPU type"
#endif
#endif
#endif
#ifdef accel /* supplied by David Barto */
#ifndef sc_pc
#define sc_pc AC_fifo_ex
/* This provides a compatible mechanism for examining and changing
the next instruction address. Return from the signal handler
will adjust the interpret and fetch stages of the pipeline to
reflect any change to the execution address.
Note: changes to AC_fifo_interp and AC_fifo_fetch are ignored. */
#endif
#endif
/*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 int (*uhandler)(); /* user handler */
register opcode *pc; /* for snooping instructions */
register opcode num; /* system call number */
struct sigvec oldsv; /* previous state */
struct sigvec newsv; /* state being set */
/* at this point, sig is blocked */
uhandler = handler[sig - 1];
/* most UNIXes usually want the state reset to SIG_DFL */
if ( sig != SIGILL && sig != SIGTRAP /* && sig != SIGPWR */ )
{
handler[sig - 1] = 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)(*uhandler)( sig ); /* user signal handler */
/* must now avoid restarting certain system calls */
pc = (opcode *)scp->sc_pc;
if ( pc[0] == SYSCALL )
{
#ifdef accel
num = (opcode)scp->AC_gen_reg[3];
#else /* sel || vax */
num = pc[1];
#ifdef vax
if ( num == IMMEDIATE )
num = pc[2];
#endif
#endif
if ( num == READ || num == WRITE || num == IOCTL ||
num == WAIT || num == READV || num == WRITEV
) { /* fake return from __ret_eintr() */
#ifdef accel
scp->AC_gen_reg[2] = -1; /* return value */
/* DAG -- Is this really necessary?
__ret_eintr() should do this. */
#endif
scp->sc_pc = (int)__ret_eintr + OFFSET;
}
}
/* return here restores interrupted context */
}
More information about the Comp.unix.wizards
mailing list