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 /signal.c | |
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.
Diffstat (limited to 'signal.c')
-rw-r--r-- | signal.c | 135 |
1 files changed, 135 insertions, 0 deletions
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; +} |