summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog47
-rw-r--r--Makefile1
-rw-r--r--arith.c2
-rwxr-xr-xconfigure31
-rw-r--r--debug.c2
-rw-r--r--dep.mk34
-rw-r--r--eval.c26
-rw-r--r--filter.c2
-rw-r--r--gc.c18
-rw-r--r--gc.h1
-rw-r--r--hash.c2
-rw-r--r--lib.c16
-rw-r--r--match.c2
-rw-r--r--parser.l2
-rw-r--r--parser.y2
-rw-r--r--rand.c2
-rw-r--r--regex.c2
-rw-r--r--signal.c135
-rw-r--r--signal.h93
-rw-r--r--stream.c57
-rw-r--r--syslog.c2
-rw-r--r--txr.c2
-rw-r--r--unwind.c8
-rw-r--r--unwind.h46
-rw-r--r--utf8.c2
25 files changed, 473 insertions, 64 deletions
diff --git a/ChangeLog b/ChangeLog
index e3407b5f..38e4a8c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/Makefile b/Makefile
index 52f07878..3b8b78ca 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/arith.c b/arith.c
index 6b190f2b..27605034 100644
--- a/arith.c
+++ b/arith.c
@@ -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"
diff --git a/configure b/configure
index 47e88ba9..7ab6931d 100755
--- a/configure
+++ b/configure
@@ -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
#
diff --git a/debug.c b/debug.c
index eb37fd8b..df8426fe 100644
--- a/debug.c
+++ b/debug.c
@@ -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"
diff --git a/dep.mk b/dep.mk
index a43c912d..71997288 100644
--- a/dep.mk
+++ b/dep.mk
@@ -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
diff --git a/eval.c b/eval.c
index cd40a888..f30e895f 100644
--- a/eval.c
+++ b/eval.c
@@ -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));
diff --git a/filter.c b/filter.c
index 0eb4c052..fb69908b 100644
--- a/filter.c
+++ b/filter.c
@@ -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"
diff --git a/gc.c b/gc.c
index 04914783..33328b9e 100644
--- a/gc.c
+++ b/gc.c
@@ -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();
diff --git a/gc.h b/gc.h
index ea7795a3..54afac9f 100644
--- a/gc.h
+++ b/gc.h
@@ -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);
diff --git a/hash.c b/hash.c
index 8e9313f5..3721baf4 100644
--- a/hash.c
+++ b/hash.c
@@ -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"
diff --git a/lib.c b/lib.c
index 16e5d08e..245c864f 100644
--- a/lib.c
+++ b/lib.c
@@ -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();
diff --git a/match.c b/match.c
index d78a3e85..2e4568af 100644
--- a/match.c
+++ b/match.c
@@ -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"
diff --git a/parser.l b/parser.l
index 99967665..bdee6275 100644
--- a/parser.l
+++ b/parser.l
@@ -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"
diff --git a/parser.y b/parser.y
index 8716f6a9..c82ede7c 100644
--- a/parser.y
+++ b/parser.y
@@ -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"
diff --git a/rand.c b/rand.c
index 92b508d0..560f1b0a 100644
--- a/rand.c
+++ b/rand.c
@@ -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"
diff --git a/regex.c b/regex.c
index 85a91ed1..dfe872a8 100644
--- a/regex.c
+++ b/regex.c
@@ -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);
diff --git a/stream.c b/stream.c
index e5e43ac6..5a5d3f74 100644
--- a/stream.c
+++ b/stream.c
@@ -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;
diff --git a/syslog.c b/syslog.c
index 047cc3bf..36edb2d7 100644
--- a/syslog.c
+++ b/syslog.c
@@ -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"
diff --git a/txr.c b/txr.c
index 72f1b8f5..cbc213a5 100644
--- a/txr.c
+++ b/txr.c
@@ -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"
diff --git a/unwind.c b/unwind.c
index 034303b5..f447bb07 100644
--- a/unwind.c
+++ b/unwind.c
@@ -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();
}
diff --git a/unwind.h b/unwind.h
index 358debfe..884f0451 100644
--- a/unwind.h
+++ b/unwind.h
@@ -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) \
diff --git a/utf8.c b/utf8.c
index 629d1963..36354277 100644
--- a/utf8.c
+++ b/utf8.c
@@ -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"