diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2013-12-12 22:47:27 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2013-12-12 22:47:27 -0800 |
commit | b3f8bee89e3fa5713ff391e0172b8e1d4b92be25 (patch) | |
tree | 14d49b10503cd3e086d00c79df184e51d444fe6b | |
parent | ccf6c78422c227778c5e6103413849803aa7b158 (diff) | |
download | txr-b3f8bee89e3fa5713ff391e0172b8e1d4b92be25.tar.gz txr-b3f8bee89e3fa5713ff391e0172b8e1d4b92be25.tar.bz2 txr-b3f8bee89e3fa5713ff391e0172b8e1d4b92be25.zip |
First cut at signal handling support.
* Makefile (OBJS-y): Include signal.o if have_posix_sigs is "y".
* configure (have_posix_sigs): New variable, set by detecting POSIX
signal stuff.
* dep.mk: Regenerated.
* arith.c, debug.c, eval.c, filter.c, hash.c, match.c, parser.y,
parser.l, rand.c, regex.c, syslog.c, txr.c, utf8.c: Include new
signal.h header, now required by unwind, and the <signal.h> system
header.
* eval.c (exit_wrap): New function.
(eval_init): New functions registered as intrinsics: exit_wrap,
set_sig_handler, get_sig_handler, sig_check.
* gc.c (release): Unused functions removed.
* gc.h (release): Declaration removed.
* lib.c (init): Call sig_init.
* stream.c (set_putc, se_getc, se_fflush): New static functions.
(stdio_put_char_callback, stdio_get_char_callback, stdio_put_byte,
stdio_flush, stdio_get_byte): Use new functions to enable
signals when blocked on I/O.
(tail_strategy): Allow signals across sleep.
(pipev_close): Allow signals across waitpid.
(se_pclose): New static function.
(pipe_close): Use new function to enable signals across pclose.
* unwind.c (uw_unwind_to_exit_point): use extended_longjmp instead of
longjmp.
* unwind.h (struct uw_block, struct uw_catch): jb member changes from
jmp_buf to extended_jmp_buf.
(uw_block_begin, uw_simple_catch_begin, uw_catch_begin): Use
extended_setjmp instead of setjmp.
* signal.c: New file.
* signal.h: New file.
-rw-r--r-- | ChangeLog | 47 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | arith.c | 2 | ||||
-rwxr-xr-x | configure | 31 | ||||
-rw-r--r-- | debug.c | 2 | ||||
-rw-r--r-- | dep.mk | 34 | ||||
-rw-r--r-- | eval.c | 26 | ||||
-rw-r--r-- | filter.c | 2 | ||||
-rw-r--r-- | gc.c | 18 | ||||
-rw-r--r-- | gc.h | 1 | ||||
-rw-r--r-- | hash.c | 2 | ||||
-rw-r--r-- | lib.c | 16 | ||||
-rw-r--r-- | match.c | 2 | ||||
-rw-r--r-- | parser.l | 2 | ||||
-rw-r--r-- | parser.y | 2 | ||||
-rw-r--r-- | rand.c | 2 | ||||
-rw-r--r-- | regex.c | 2 | ||||
-rw-r--r-- | signal.c | 135 | ||||
-rw-r--r-- | signal.h | 93 | ||||
-rw-r--r-- | stream.c | 57 | ||||
-rw-r--r-- | syslog.c | 2 | ||||
-rw-r--r-- | txr.c | 2 | ||||
-rw-r--r-- | unwind.c | 8 | ||||
-rw-r--r-- | unwind.h | 46 | ||||
-rw-r--r-- | utf8.c | 2 |
25 files changed, 473 insertions, 64 deletions
@@ -1,5 +1,52 @@ 2013-12-12 Kaz Kylheku <kaz@kylheku.com> + First cut at signal handling support. + + * Makefile (OBJS-y): Include signal.o if have_posix_sigs is "y". + + * configure (have_posix_sigs): New variable, set by detecting POSIX + signal stuff. + + * dep.mk: Regenerated. + + * arith.c, debug.c, eval.c, filter.c, hash.c, match.c, parser.y, + parser.l, rand.c, regex.c, syslog.c, txr.c, utf8.c: Include new + signal.h header, now required by unwind, and the <signal.h> system + header. + + * eval.c (exit_wrap): New function. + (eval_init): New functions registered as intrinsics: exit_wrap, + set_sig_handler, get_sig_handler, sig_check. + + * gc.c (release): Unused functions removed. + + * gc.h (release): Declaration removed. + + * lib.c (init): Call sig_init. + + * stream.c (set_putc, se_getc, se_fflush): New static functions. + (stdio_put_char_callback, stdio_get_char_callback, stdio_put_byte, + stdio_flush, stdio_get_byte): Use new functions to enable + signals when blocked on I/O. + (tail_strategy): Allow signals across sleep. + (pipev_close): Allow signals across waitpid. + (se_pclose): New static function. + (pipe_close): Use new function to enable signals across pclose. + + * unwind.c (uw_unwind_to_exit_point): use extended_longjmp instead of + longjmp. + + * unwind.h (struct uw_block, struct uw_catch): jb member changes from + jmp_buf to extended_jmp_buf. + (uw_block_begin, uw_simple_catch_begin, uw_catch_begin): Use + extended_setjmp instead of setjmp. + + * signal.c: New file. + + * signal.h: New file. + +2013-12-12 Kaz Kylheku <kaz@kylheku.com> + * configure (config_flags): Variable removed. This was more trouble than it was worth, and only solved problems caused by not checking that the test program was made all the way to an executable. @@ -42,6 +42,7 @@ OBJS := txr.o lex.yy.o y.tab.o match.o lib.o regex.o gc.o unwind.o stream.o OBJS += arith.o hash.o utf8.o filter.o eval.o rand.o OBJS-$(debug_support) += debug.o OBJS-$(have_syslog) += syslog.o +OBJS-$(have_posix_sigs) += signal.o # MPI objects MPI_OBJ_BASE=mpi.o mplogic.o @@ -36,9 +36,11 @@ #include <wchar.h> #include <limits.h> #include <math.h> +#include <signal.h> #include <ctype.h> #include "config.h" #include "lib.h" +#include "signal.h" #include "unwind.h" #include "gc.h" #include "arith.h" @@ -100,6 +100,7 @@ have_patch= have_unistd= have_timegm= have_syslog= +have_posix_sigs= need_svid_source= need_bsd_source= @@ -576,6 +577,9 @@ tool_prefix := $tool_prefix # do we compile in syslog support? have_syslog := $have_syslog +# do we modern posix signal handling? +have_posix_sigs := $have_posix_sigs + # do we compile in debug support? debug_support := $debug_support @@ -1437,6 +1441,33 @@ else have_syslog=y fi +printf "Checking for reasonably modern POSIX signal handling ... " + +cat > conftest.c <<! +#include <signal.h> +#include <setjmp.h> + +int main(void) +{ + sigjmp_buf jb; + static struct sigaction old, new; + static sigset_t olds, news; + sigaction(0, &new, &old); + sigprocmask(SIG_BLOCK, &news, &olds); + if (!sigsetjmp(jb, 1)) + siglongjmp(jb, 1); + return 0; +} +! +rm -f conftest +if ! $make conftest > conftest.err 2>&1 || ! [ -x conftest ] ; then + printf "no\n" +else + printf "yes\n" + printf "#define HAVE_POSIX_SIGS 1\n" >> config.h + have_posix_sigs=y +fi + # # Dependent variables # @@ -32,10 +32,12 @@ #include <setjmp.h> #include <stdarg.h> #include <wchar.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "debug.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "stream.h" #include "parser.h" @@ -1,18 +1,20 @@ -./txr.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./parser.h $(top_srcdir)/./match.h $(top_srcdir)/./utf8.h $(top_srcdir)/./debug.h $(top_srcdir)/./txr.h -./lex.yy.o: config.h $(top_srcdir)/./lib.h y.tab.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h $(top_srcdir)/./unwind.h $(top_srcdir)/./hash.h $(top_srcdir)/./parser.h -./y.tab.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./utf8.h $(top_srcdir)/./match.h $(top_srcdir)/./hash.h $(top_srcdir)/./eval.h $(top_srcdir)/./parser.h -./match.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./txr.h $(top_srcdir)/./utf8.h $(top_srcdir)/./filter.h $(top_srcdir)/./hash.h $(top_srcdir)/./debug.h $(top_srcdir)/./eval.h $(top_srcdir)/./match.h -./lib.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./arith.h $(top_srcdir)/./rand.h $(top_srcdir)/./hash.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h $(top_srcdir)/./filter.h $(top_srcdir)/./eval.h $(top_srcdir)/./regex.h -./regex.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./txr.h $(top_srcdir)/./gc.h -./gc.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h $(top_srcdir)/./txr.h $(top_srcdir)/./eval.h $(top_srcdir)/./gc.h -./unwind.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h $(top_srcdir)/./txr.h $(top_srcdir)/./unwind.h -./stream.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h -./arith.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./gc.h $(top_srcdir)/./arith.h -./hash.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h -./utf8.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./utf8.h -./filter.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./hash.h $(top_srcdir)/./unwind.h $(top_srcdir)/./match.h $(top_srcdir)/./filter.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h -./eval.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./hash.h $(top_srcdir)/./debug.h $(top_srcdir)/./match.h $(top_srcdir)/./rand.h $(top_srcdir)/./filter.h $(top_srcdir)/./txr.h $(top_srcdir)/./eval.h -./rand.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./unwind.h $(top_srcdir)/./gc.h $(top_srcdir)/./arith.h $(top_srcdir)/./rand.h +./txr.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./parser.h $(top_srcdir)/./match.h $(top_srcdir)/./utf8.h $(top_srcdir)/./debug.h $(top_srcdir)/./syslog.h $(top_srcdir)/./txr.h +./lex.yy.o: config.h $(top_srcdir)/./lib.h y.tab.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./hash.h $(top_srcdir)/./parser.h +./y.tab.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./utf8.h $(top_srcdir)/./match.h $(top_srcdir)/./hash.h $(top_srcdir)/./eval.h $(top_srcdir)/./parser.h +./match.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./txr.h $(top_srcdir)/./utf8.h $(top_srcdir)/./filter.h $(top_srcdir)/./hash.h $(top_srcdir)/./debug.h $(top_srcdir)/./eval.h $(top_srcdir)/./match.h +./lib.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./arith.h $(top_srcdir)/./rand.h $(top_srcdir)/./hash.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h $(top_srcdir)/./filter.h $(top_srcdir)/./eval.h $(top_srcdir)/./regex.h +./regex.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./parser.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./txr.h $(top_srcdir)/./gc.h +./gc.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h $(top_srcdir)/./txr.h $(top_srcdir)/./eval.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h +./unwind.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h $(top_srcdir)/./txr.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h +./stream.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./utf8.h +./arith.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./gc.h $(top_srcdir)/./arith.h +./hash.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h +./utf8.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./utf8.h +./filter.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./hash.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./match.h $(top_srcdir)/./filter.h $(top_srcdir)/./gc.h $(top_srcdir)/./stream.h +./eval.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./regex.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./hash.h $(top_srcdir)/./debug.h $(top_srcdir)/./match.h $(top_srcdir)/./rand.h $(top_srcdir)/./filter.h $(top_srcdir)/./txr.h $(top_srcdir)/./syslog.h $(top_srcdir)/./eval.h +./rand.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./gc.h $(top_srcdir)/./arith.h $(top_srcdir)/./rand.h mpi-1.8.6/mpi.o: config.h $(top_srcdir)/mpi-1.8.6/mpi.h $(top_srcdir)/mpi-1.8.6/logtab.h mpi-1.8.6/mplogic.o: config.h $(top_srcdir)/mpi-1.8.6/mplogic.h -./debug.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./debug.h $(top_srcdir)/./gc.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./txr.h +./debug.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./debug.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./stream.h $(top_srcdir)/./parser.h $(top_srcdir)/./txr.h +./syslog.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h $(top_srcdir)/./utf8.h $(top_srcdir)/./syslog.h +./signal.o: config.h $(top_srcdir)/./lib.h $(top_srcdir)/./stream.h $(top_srcdir)/./hash.h $(top_srcdir)/./gc.h $(top_srcdir)/./signal.h $(top_srcdir)/./unwind.h @@ -32,6 +32,7 @@ #include <setjmp.h> #include <stdarg.h> #include <wchar.h> +#include <signal.h> #include "config.h" #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -41,6 +42,7 @@ #endif #include "lib.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "regex.h" #include "stream.h" @@ -2095,6 +2097,22 @@ static val daemon_wrap(val nochdir, val noclose) } #endif +static val exit_wrap(val status) +{ + int stat; + + if (status == nil) + stat = EXIT_FAILURE; + else if (status == t) + stat = EXIT_SUCCESS; + else + stat = c_num(status); + + exit(stat); + /* notreached */ + return nil; +} + static void reg_fun(val sym, val fun) { sethash(top_fb, sym, cons(sym, fun)); @@ -2591,6 +2609,8 @@ void eval_init(void) reg_fun(intern(lit("make-time-utc"), user_package), func_n7(make_time_utc)); reg_fun(intern(lit("errno"), user_package), func_n1o(errno_wrap, 0)); + reg_fun(intern(lit("exit"), user_package), func_n1(exit_wrap)); + #if HAVE_DAEMON reg_fun(intern(lit("daemon"), user_package), func_n2(daemon_wrap)); #endif @@ -2624,6 +2644,12 @@ void eval_init(void) reg_fun(intern(lit("syslog"), user_package), func_n2v(syslog_wrap)); #endif +#if HAVE_POSIX_SIGS + reg_fun(intern(lit("set-sig-handler"), user_package), func_n2(set_sig_handler)); + reg_fun(intern(lit("get-sig-handler"), user_package), func_n1(get_sig_handler)); + reg_fun(intern(lit("sig-check"), user_package), func_n0(sig_check)); +#endif + reg_fun(intern(lit("source-loc"), user_package), func_n1(source_loc)); reg_fun(intern(lit("source-loc-str"), user_package), func_n1(source_loc_str)); @@ -32,9 +32,11 @@ #include <stdarg.h> #include <dirent.h> #include <stdio.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "hash.h" +#include "signal.h" #include "unwind.h" #include "match.h" #include "filter.h" @@ -31,6 +31,7 @@ #include <setjmp.h> #include <dirent.h> #include <wchar.h> +#include <signal.h> #include "config.h" #ifdef HAVE_VALGRIND #include <valgrind/memcheck.h> @@ -41,6 +42,7 @@ #include "txr.h" #include "eval.h" #include "gc.h" +#include "signal.h" #define PROT_STACK_SIZE 1024 #define HEAP_SIZE 16384 @@ -115,20 +117,6 @@ void protect(val *first, ...) va_end (vl); } -void release(val *last, ...) -{ - val *next = last; - va_list vl; - va_start (vl, last); - - while (next) { - rel1(next); - next = va_arg(vl, val *); - } - - va_end (vl); -} - static void more(void) { heap_t *heap = (heap_t *) chk_malloc(sizeof *heap); @@ -161,6 +149,8 @@ val make_obj(void) { int tries; + assert (!async_sig_enabled); + #if CONFIG_GEN_GC if (opt_gc_debug || freshobj_idx >= FRESHOBJ_VEC_SIZE) { gc(); @@ -28,7 +28,6 @@ void gc_init(val *stack_bottom); val prot1(val *loc); void rel1(val *loc); void protect(val *, ...); -void release(val *, ...); val make_obj(void); void gc(void); int gc_state(int); @@ -31,9 +31,11 @@ #include <stdlib.h> #include <setjmp.h> #include <limits.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "stream.h" #include "hash.h" @@ -36,7 +36,9 @@ #include <wchar.h> #include <math.h> #include <time.h> +#include <signal.h> #include <sys/time.h> +#include <assert.h> #include "config.h" #ifdef HAVE_GETENVIRONMENTSTRINGS #define NOMINMAX @@ -47,6 +49,7 @@ #include "arith.h" #include "rand.h" #include "hash.h" +#include "signal.h" #include "unwind.h" #include "stream.h" #include "utf8.h" @@ -1082,6 +1085,9 @@ static mem_t *malloc_low_bound, *malloc_high_bound; mem_t *chk_malloc(size_t size) { mem_t *ptr = (mem_t *) malloc(size); + + assert (!async_sig_enabled); + if (size && ptr == 0) ptr = (mem_t *) oom_realloc(0, size); if (ptr < malloc_low_bound) @@ -1094,6 +1100,9 @@ mem_t *chk_malloc(size_t size) mem_t *chk_calloc(size_t n, size_t size) { mem_t *ptr = (mem_t *) calloc(n, size); + + assert (!async_sig_enabled); + if (size && ptr == 0) { ptr = (mem_t *) oom_realloc(0, size); memset(ptr, 0, n * size); @@ -1108,6 +1117,9 @@ mem_t *chk_calloc(size_t n, size_t size) mem_t *chk_realloc(mem_t *old, size_t size) { mem_t *newptr = (mem_t *) realloc(old, size); + + assert (!async_sig_enabled); + if (size != 0 && newptr == 0) newptr = oom_realloc(old, size); if (newptr < malloc_low_bound) @@ -1126,6 +1138,7 @@ wchar_t *chk_strdup(const wchar_t *str) { size_t nchar = wcslen(str) + 1; wchar_t *copy = (wchar_t *) chk_malloc(nchar * sizeof *copy); + assert (!async_sig_enabled); wmemcpy(copy, str, nchar); return copy; } @@ -5188,6 +5201,9 @@ void init(const wchar_t *pn, mem_t *(*oom)(mem_t *, size_t), oom_realloc = oom; gc_init(stack_bottom); +#if HAVE_POSIX_SIGS + sig_init(); +#endif obj_init(); arith_init(); rand_init(); @@ -32,9 +32,11 @@ #include <setjmp.h> #include <stdarg.h> #include <wchar.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "regex.h" #include "stream.h" @@ -35,6 +35,7 @@ #include <dirent.h> #include <wchar.h> #include <setjmp.h> +#include <signal.h> #include "config.h" #if HAVE_UNISTD_H #include <unistd.h> @@ -44,6 +45,7 @@ #include "gc.h" #include "stream.h" #include "utf8.h" +#include "signal.h" #include "unwind.h" #include "hash.h" #include "parser.h" @@ -33,8 +33,10 @@ #include <stdlib.h> #include <setjmp.h> #include <wchar.h> +#include <signal.h> #include "config.h" #include "lib.h" +#include "signal.h" #include "unwind.h" #include "regex.h" #include "utf8.h" @@ -35,8 +35,10 @@ #include <wchar.h> #include <limits.h> #include <time.h> +#include <signal.h> #include "config.h" #include "lib.h" +#include "signal.h" #include "unwind.h" #include "gc.h" #include "arith.h" @@ -33,9 +33,11 @@ #include <setjmp.h> #include <dirent.h> #include <limits.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "parser.h" +#include "signal.h" #include "unwind.h" #include "regex.h" #include "txr.h" diff --git a/signal.c b/signal.c new file mode 100644 index 00000000..05ad9eb6 --- /dev/null +++ b/signal.c @@ -0,0 +1,135 @@ +/* Copyright 2013-2014 + * Kaz Kylheku <kaz@kylheku.com> + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <setjmp.h> +#include <wchar.h> +#include <dirent.h> +#include <signal.h> +#include "config.h" +#include "lib.h" +#include "stream.h" +#include "hash.h" +#include "gc.h" +#include "signal.h" +#include "unwind.h" + +#define MAX_SIG 32 + +volatile sig_atomic_t async_sig_enabled = 0; + +static val sig_lambda[MAX_SIG]; +volatile unsigned long sig_deferred; + +static void sig_handler(int sig) +{ + val lambda = sig_lambda[sig]; + if (lambda) { + if (async_sig_enabled) { + async_sig_enabled = 0; + funcall1(lambda, num_fast(sig)); + async_sig_enabled = 1; + } else { + sig_deferred |= (1UL << sig); + } + } +} + +void sig_init(void) +{ + int i; + + for (i = 0; i < MAX_SIG; i++) { + /* t means SIG_DFL, which is what signals + * are before we manipulate them. */ + sig_lambda[i] = t; + prot1(&sig_lambda[i]); + } +} + +val set_sig_handler(val signo, val lambda) +{ + cnum sig = c_num(signo); + val old_lambda; + + if (sig < 0 || sig >= MAX_SIG) + uw_throwf(error_s, lit("set-sig-handler: signal ~s out of range\n"), sig, nao); + + old_lambda = sig_lambda[sig]; + + if (lambda != old_lambda) { + if (lambda == nil) { + signal(sig, SIG_IGN); + } else if (lambda == t) { + signal(sig, SIG_DFL); + } else { + struct sigaction sa = { 0 }; + + type_check(lambda, FUN); + + sa.sa_flags = SA_RESTART; + sa.sa_handler = sig_handler; + sigfillset(&sa.sa_mask); + sigaction(sig, &sa, 0); + } + + sig_lambda[sig] = lambda; + } + + return old_lambda; +} + +val get_sig_handler(val signo) +{ + cnum sig = c_num(signo); + + if (sig < 0 || sig >= MAX_SIG) + uw_throwf(error_s, lit("get-sig-handler: signal ~s out of range\n"), sig, nao); + + return sig_lambda[sig]; +} + +val sig_check(void) +{ + unsigned long sd; + int i; + + if ((sd = sig_deferred) == 0) + return nil; + + for (i = 0; i < MAX_SIG; i++) { + unsigned long mask = 1UL << i; + if ((sd & mask) != 0) { + sd &= ~mask; + sig_deferred = sd; + funcall1(sig_lambda[i], num_fast(i)); + } + } + + return t; +} diff --git a/signal.h b/signal.h new file mode 100644 index 00000000..111c6265 --- /dev/null +++ b/signal.h @@ -0,0 +1,93 @@ +/* Copyright 2013-2014 + * Kaz Kylheku <kaz@kylheku.com> + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#if HAVE_POSIX_SIGS + +#define sig_save_enable \ + do { \ + int sig_save = async_sig_enabled; \ + async_sig_enabled = 1; \ + if (!sig_save) \ + sig_check(); \ + { \ + typedef void v_o_i_d + +#define sig_restore_enable \ + do { } while (0); \ + } \ + async_sig_enabled = sig_save; \ + } while(0) + +#define sig_save_disable \ + do { \ + int sig_save = async_sig_enabled; \ + async_sig_enabled = 1; \ + { \ + typedef void v_o_i_d + +#define sig_restore_disable \ + do { } while (0); \ + } \ + async_sig_enabled = sig_save; \ + if (sig_save) \ + sig_check(); \ + } while(0) + +typedef struct { + jmp_buf jb; + sig_atomic_t se; + int rv; +} extended_jmp_buf; + +#define extended_setjmp(EJB) \ + (sigsetjmp((EJB).jb, 1) \ + ? (async_sig_enabled = (EJB).se, (EJB).rv) \ + : ((EJB).se = async_sig_enabled, 0)) + +#define extended_longjmp(EJB, ARG) \ + ((EJB).rv = (ARG), longjmp((EJB).jb, 1)) + +#else + +#define sig_save_enable do { +#define sig_save_disable do { + +#define sig_restore_enable do { } while (0); } while (0) +#define sig_restore_disable do { } while (0); } while (0) + +tyedef jmp_buf extended_jmp_buf; +#define extended_setjmp(EJB) setjmp(EJB) +#define extended_longjmp(EJB, ARG) longjmp(EJB, ARG) + +#endif + +extern volatile sig_atomic_t async_sig_enabled; + +void sig_init(void); +val set_sig_handler(val signo, val lambda); +val get_sig_handler(val signo); +val sig_check(void); @@ -33,6 +33,7 @@ #include <errno.h> #include <ctype.h> #include <wchar.h> +#include <signal.h> #include "config.h" #if HAVE_UNISTD_H #include <unistd.h> @@ -46,6 +47,7 @@ #endif #include "lib.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "stream.h" #include "utf8.h" @@ -157,14 +159,42 @@ static val stdio_maybe_error(val stream, val action) stream, action, num(errno), string_utf8(strerror(errno)), nao); } +static int se_putc(int ch, FILE *f) +{ + int ret; + sig_save_enable; + ret = putc(ch, f); + sig_restore_enable; + return ret; +} + +static int se_getc(FILE *f) +{ + int ret; + sig_save_enable; + ret = getc(f); + sig_restore_enable; + return ret; +} + +static int se_fflush(FILE *f) +{ + int ret; + sig_save_enable; + ret = fflush(f); + sig_restore_enable; + return ret; +} + static int stdio_put_char_callback(int ch, mem_t *f) { - return putc(ch, (FILE *) f) != EOF; + int ret = se_putc(ch, (FILE *) f) != EOF; + return ret; } static int stdio_get_char_callback(mem_t *f) { - return getc((FILE *) f); + return se_getc((FILE *) f); } static val stdio_put_string(val stream, val str) @@ -204,14 +234,14 @@ static val stdio_put_byte(val stream, int b) if (stream != std_debug && stream != std_error) output_produced = t; - return h->f != 0 && putc(b, (FILE *) h->f) != EOF + return h->f != 0 && se_putc(b, (FILE *) h->f) != EOF ? t : stdio_maybe_error(stream, lit("writing")); } static val stdio_flush(val stream) { struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; - return (h->f != 0 && fflush(h->f) == 0) + return (h->f != 0 && se_fflush(h->f) == 0) ? t : stdio_maybe_error(stream, lit("flushing")); } @@ -313,7 +343,7 @@ static val stdio_get_byte(val stream) { struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; if (h->f) { - int ch = getc(h->f); + int ch = se_getc(h->f); return (ch != EOF) ? num(ch) : stdio_maybe_read_error(stream); } return stdio_maybe_read_error(stream); @@ -384,7 +414,9 @@ static void tail_strategy(val stream, unsigned long *state) FILE *newf; if (!(newf = w_freopen(c_str(h->descr), c_str(h->mode), h->f))) { tail_calc(state, &sec, &mod); + sig_save_enable; sleep(sec); + sig_restore_enable; continue; } h->f = newf; @@ -465,21 +497,32 @@ static int pipevp_close(FILE *f, pid_t pid) { int status; fclose(f); + sig_save_enable; while (waitpid(pid, &status, 0) == -1 && errno == EINTR) ; + sig_restore_enable; return status; } #endif +static int se_pclose(FILE *f) +{ + int ret; + sig_save_enable; + ret = pclose(f); + sig_restore_enable; + return ret; +} + static val pipe_close(val stream, val throw_on_error) { struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; if (h->f != 0) { #if HAVE_FORK_STUFF - int status = h->pid != 0 ? pipevp_close(h->f, h->pid) : pclose(h->f); + int status = h->pid != 0 ? pipevp_close(h->f, h->pid) : se_pclose(h->f); #else - int status = pclose(h->f); + int status = se_pclose(h->f); #endif h->f = 0; @@ -29,6 +29,7 @@ #include <stdarg.h> #include <setjmp.h> #include <wchar.h> +#include <signal.h> #include <dirent.h> #include <syslog.h> #include "config.h" @@ -36,6 +37,7 @@ #include "stream.h" #include "hash.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "utf8.h" #include "syslog.h" @@ -32,10 +32,12 @@ #include <setjmp.h> #include <stdarg.h> #include <wchar.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "stream.h" #include "gc.h" +#include "signal.h" #include "unwind.h" #include "parser.h" #include "match.h" @@ -31,11 +31,13 @@ #include <setjmp.h> #include <dirent.h> #include <stdarg.h> +#include <signal.h> #include "config.h" #include "lib.h" #include "gc.h" #include "stream.h" #include "txr.h" +#include "signal.h" #include "unwind.h" static uw_frame_t *uw_stack; @@ -67,7 +69,7 @@ static void uw_unwind_to_exit_point(void) uw_stack->ca.exception = nil; uw_stack->ca.cont = uw_exit_point; /* 1 means unwind only. */ - longjmp(uw_stack->ca.jb, 1); + extended_longjmp(uw_stack->ca.jb, 1); abort(); case UW_ENV: /* Maintain consistency of unwind stack pointer */ @@ -85,13 +87,13 @@ static void uw_unwind_to_exit_point(void) switch (uw_stack->uw.type) { case UW_BLOCK: - longjmp(uw_stack->bl.jb, 1); + extended_longjmp(uw_stack->bl.jb, 1); abort(); case UW_ENV: /* env frame cannot be exit point */ abort(); case UW_CATCH: /* 2 means actual catch, not just unwind */ - longjmp(uw_stack->ca.jb, 2); + extended_longjmp(uw_stack->ca.jb, 2); default: abort(); } @@ -44,7 +44,7 @@ struct uw_block { val tag; val result; val protocol; - jmp_buf jb; + extended_jmp_buf jb; }; struct uw_dynamic_env { @@ -63,7 +63,7 @@ struct uw_catch { val exception; uw_frame_t *cont; int visible; - jmp_buf jb; + extended_jmp_buf jb; }; struct uw_debug { @@ -126,14 +126,14 @@ noreturn val type_mismatch(val, ...); return VAL; \ } while (0) -#define uw_block_begin(TAG, RESULTVAR) \ - obj_t *RESULTVAR = nil; \ - do { \ - uw_frame_t uw_blk; \ - uw_push_block(&uw_blk, TAG); \ - if (setjmp(uw_blk.bl.jb)) { \ - RESULTVAR = uw_blk.bl.result; \ - } else { \ +#define uw_block_begin(TAG, RESULTVAR) \ + obj_t *RESULTVAR = nil; \ + do { \ + uw_frame_t uw_blk; \ + uw_push_block(&uw_blk, TAG); \ + if (extended_setjmp(uw_blk.bl.jb)) { \ + RESULTVAR = uw_blk.bl.result; \ + } else { \ typedef int uw_d_u_m_m_y #define uw_block_end \ @@ -150,21 +150,21 @@ noreturn val type_mismatch(val, ...); uw_pop_frame(&uw_env); \ } while (0) -#define uw_simple_catch_begin \ - do { \ - uw_frame_t uw_catch; \ - uw_push_catch(&uw_catch, nil); \ - switch (setjmp(uw_catch.ca.jb)) { \ +#define uw_simple_catch_begin \ + do { \ + uw_frame_t uw_catch; \ + uw_push_catch(&uw_catch, nil); \ + switch (extended_setjmp(uw_catch.ca.jb)) { \ case 0: -#define uw_catch_begin(MATCHES, SYMVAR, \ - EXCVAR) \ - obj_t *SYMVAR = nil; \ - obj_t *EXCVAR = nil; \ - do { \ - uw_frame_t uw_catch; \ - uw_push_catch(&uw_catch, MATCHES); \ - switch (setjmp(uw_catch.ca.jb)) { \ +#define uw_catch_begin(MATCHES, SYMVAR, \ + EXCVAR) \ + obj_t *SYMVAR = nil; \ + obj_t *EXCVAR = nil; \ + do { \ + uw_frame_t uw_catch; \ + uw_push_catch(&uw_catch, MATCHES); \ + switch (extended_setjmp(uw_catch.ca.jb)) { \ case 0: #define uw_catch(SYMVAR, EXCVAR) \ @@ -29,8 +29,10 @@ #include <stdlib.h> #include <wchar.h> #include <setjmp.h> +#include <signal.h> #include "config.h" #include "lib.h" +#include "signal.h" #include "unwind.h" #include "utf8.h" |