diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2003-06-07 03:35:20 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2003-06-07 03:35:20 +0000 |
commit | 912020678b6f45f900b66e637e5848d9fa3b92b7 (patch) | |
tree | fed315ea71f42adc5b7f91b77e54ce06be52220c | |
parent | ca740922f63b8d6806ffacd67092fc0f20e90976 (diff) |
Use interruptible syscalls instead of setjmp/longjmp. This makes
less's signal handlers safe. No one has reported problems so far...
-rw-r--r-- | usr.bin/less/funcs.h | 2 | ||||
-rw-r--r-- | usr.bin/less/less.h | 2 | ||||
-rw-r--r-- | usr.bin/less/os.c | 58 | ||||
-rw-r--r-- | usr.bin/less/signal.c | 33 |
4 files changed, 21 insertions, 74 deletions
diff --git a/usr.bin/less/funcs.h b/usr.bin/less/funcs.h index 4ee00d493f6..5fab0efdf6a 100644 --- a/usr.bin/less/funcs.h +++ b/usr.bin/less/funcs.h @@ -195,7 +195,6 @@ public struct loption * findopt (); public struct loption * findopt_name (); public int iread (); - public void intread (); public long get_time (); public char * errno_message (); public int percentage (); @@ -249,3 +248,4 @@ public void open_getchr (); public void close_getchr (); public int getchr (); + public void (*lsignal()) (); diff --git a/usr.bin/less/less.h b/usr.bin/less/less.h index 07911d5ce7d..abb60f323c5 100644 --- a/usr.bin/less/less.h +++ b/usr.bin/less/less.h @@ -374,7 +374,7 @@ struct textlist #if _OSK_MWC32 #define LSIGNAL(sig,func) os9_signal(sig,func) #else -#define LSIGNAL(sig,func) signal(sig,func) +#define LSIGNAL(sig,func) lsignal(sig,func) #endif #if HAVE_SIGPROCMASK diff --git a/usr.bin/less/os.c b/usr.bin/less/os.c index ac63960df95..c5343a043a8 100644 --- a/usr.bin/less/os.c +++ b/usr.bin/less/os.c @@ -23,7 +23,6 @@ #include "less.h" #include <signal.h> -#include <setjmp.h> #if HAVE_TIME_H #include <time.h> #endif @@ -40,31 +39,10 @@ #define time_type long #endif -/* - * BSD setjmp() saves (and longjmp() restores) the signal mask. - * This costs a system call or two per setjmp(), so if possible we clear the - * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. - * On other systems, setjmp() doesn't affect the signal mask and so - * _setjmp() does not exist; we just use setjmp(). - */ -#if HAVE__SETJMP && HAVE_SIGSETMASK -#define SET_JUMP _setjmp -#define LONG_JUMP _longjmp -#else -#define SET_JUMP setjmp -#define LONG_JUMP longjmp -#endif - -public int reading; - -static jmp_buf read_label; - extern int sigs; /* * Like read() system call, but is deliberately interruptible. - * A call to intread() from a signal handler will interrupt - * any pending iread(). */ public int iread(fd, buf, len) @@ -90,32 +68,8 @@ iread(fd, buf, len) } #endif #endif - if (SET_JUMP(read_label)) - { - /* - * We jumped here from intread. - */ - reading = 0; -#if HAVE_SIGPROCMASK - { - sigset_t mask; - sigemptyset(&mask); - sigprocmask(SIG_SETMASK, &mask, NULL); - } -#else -#if HAVE_SIGSETMASK - sigsetmask(0); -#else -#ifdef _OSK - sigmask(~0); -#endif -#endif -#endif - return (READ_INTR); - } flush(); - reading = 1; #if MSDOS_COMPILER==DJGPPC if (isatty(fd)) { @@ -154,22 +108,12 @@ iread(fd, buf, len) } } #endif - reading = 0; if (n < 0) - return (-1); + return (errno == EINTR ? READ_INTR : -1); return (n); } /* - * Interrupt a pending iread(). - */ - public void -intread() -{ - LONG_JUMP(read_label, 1); -} - -/* * Return the current time. */ #if HAVE_TIME diff --git a/usr.bin/less/signal.c b/usr.bin/less/signal.c index a641d99ee9d..01b510f73e8 100644 --- a/usr.bin/less/signal.c +++ b/usr.bin/less/signal.c @@ -15,8 +15,6 @@ * A signal usually merely causes a bit to be set in the "signals" word. * At some convenient time, the mainline code checks to see if any * signals need processing by calling psignal(). - * If we happen to be reading from a file [in iread()] at the time - * the signal is received, we call intread to interrupt the iread. */ #include "less.h" @@ -32,7 +30,6 @@ extern int screen_trashed; extern int lnloop; extern int linenums; extern int wscroll; -extern int reading; /* * Interrupt signal handler. @@ -45,7 +42,6 @@ u_interrupt(type) #if OS2 LSIGNAL(SIGINT, SIG_ACK); #endif - LSIGNAL(SIGINT, u_interrupt); sigs |= S_INTERRUPT; #if MSDOS_COMPILER==DJGPPC /* @@ -56,8 +52,6 @@ u_interrupt(type) if (kbhit()) getkey(); #endif - if (reading) - intread(); } #ifdef SIGTSTP @@ -69,10 +63,7 @@ u_interrupt(type) stop(type) int type; { - LSIGNAL(SIGTSTP, stop); sigs |= S_STOP; - if (reading) - intread(); } #endif @@ -85,10 +76,7 @@ stop(type) winch(type) int type; { - LSIGNAL(SIGWINCH, winch); sigs |= S_WINCH; - if (reading) - intread(); } #else #ifdef SIGWIND @@ -100,10 +88,7 @@ winch(type) winch(type) int type; { - LSIGNAL(SIGWIND, winch); sigs |= S_WINCH; - if (reading) - intread(); } #endif #endif @@ -268,3 +253,21 @@ psignals() } } + +/* + * Custom version of signal() that causes syscalls to be interrupted. + */ + public void +(*lsignal(s, a))() + int s; + void (*a) (); +{ + struct sigaction sa, osa; + + sa.sa_handler = a; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; /* don't restart system calls */ + if (sigaction(s, &sa, &osa) != 0) + return (SIG_ERR); + return (osa.sa_handler); +} |