Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!linus!security!genrad!mit-eddie!mit-vax!eagle!harpo!seismo!hao!hplabs!sri-unix!gwyn@brl-vld From: gwyn%brl-vld@sri-unix.UUCP Newsgroups: net.unix-wizards Subject: improved 4.2BSD signal(2) library routine Message-ID: <14791@sri-arpa.UUCP> Date: Tue, 20-Dec-83 05:31:28 EST Article-I.D.: sri-arpa.14791 Posted: Tue Dec 20 05:31:28 1983 Date-Received: Fri, 23-Dec-83 01:35:41 EST Lines: 121 From: Doug Gwyn (VLD/VMB) /* 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 #include 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; }