chibi-scheme/lib/chibi/signal.c
2010-07-14 11:41:03 +00:00

62 lines
2.5 KiB
C

/* signal.c -- process signals interface */
/* Copyright (c) 2009 Alex Shinn. All rights reserved. */
/* BSD-style license: http://synthcode.com/license.txt */
#define SEXP_MAX_SIGNUM 32
static sexp sexp_signal_contexts[SEXP_MAX_SIGNUM];
static void sexp_call_sigaction (int signum, siginfo_t *info, void *uctx) {
sexp ctx, sigctx, handler;
sexp_gc_var1(args);
ctx = sexp_signal_contexts[signum];
if (ctx) {
handler = sexp_vector_ref(sexp_global(ctx, SEXP_G_SIGNAL_HANDLERS),
sexp_make_fixnum(signum));
if (sexp_truep(handler)) {
sigctx = sexp_make_child_context(ctx, NULL);
sexp_gc_preserve1(sigctx, args);
args = sexp_cons(sigctx, SEXP_FALSE, SEXP_NULL);
sexp_car(args)
= sexp_make_cpointer(sigctx, sexp_siginfo_t_type_id, info, SEXP_FALSE, 0);
args = sexp_cons(sigctx, SEXP_FALSE, args);
sexp_car(args) = sexp_make_fixnum(signum);
sexp_apply(sigctx, handler, args);
sexp_gc_release1(sigctx);
}
}
}
static struct sigaction call_sigaction = {
.sa_sigaction = sexp_call_sigaction,
.sa_flags = SA_SIGINFO | SA_NODEFER
};
static struct sigaction call_sigdefault = {.sa_handler = SIG_DFL};
static struct sigaction call_sigignore = {.sa_handler = SIG_IGN};
static sexp sexp_set_signal_action (sexp ctx, sexp self, sexp signum, sexp newaction) {
int res;
sexp oldaction;
if (! (sexp_fixnump(signum) && sexp_unbox_fixnum(signum) > 0
&& sexp_unbox_fixnum(signum) < SEXP_MAX_SIGNUM))
return sexp_xtype_exception(ctx, self, "not a valid signal number", signum);
if (! (sexp_procedurep(newaction) || sexp_opcodep(newaction)
|| sexp_booleanp(newaction)))
return sexp_type_exception(ctx, self, SEXP_PROCEDURE, newaction);
if (! sexp_vectorp(sexp_global(ctx, SEXP_G_SIGNAL_HANDLERS)))
sexp_global(ctx, SEXP_G_SIGNAL_HANDLERS)
= sexp_make_vector(ctx, sexp_make_fixnum(SEXP_MAX_SIGNUM), SEXP_FALSE);
oldaction = sexp_vector_ref(sexp_global(ctx, SEXP_G_SIGNAL_HANDLERS), signum);
res = sigaction(sexp_unbox_fixnum(signum),
(sexp_booleanp(newaction) ?
(sexp_truep(newaction) ? &call_sigdefault : &call_sigignore)
: &call_sigaction),
NULL);
if (res)
return sexp_user_exception(ctx, self, "couldn't set signal", signum);
sexp_vector_set(sexp_global(ctx, SEXP_G_SIGNAL_HANDLERS), signum, newaction);
sexp_signal_contexts[sexp_unbox_fixnum(signum)] = ctx;
return oldaction;
}