/*
- * Catching of signals and calling callback functions
+ * UCW Library -- Catching of signals and calling callback functions
*
* (c) 2004, Robert Spalek <robert@ucw.cz>
+ * (c) 2006 Martin Mares <mj@ucw.cz>
*/
#include "lib/lib.h"
+#include "lib/threads.h"
#include <stdlib.h>
+#include <string.h>
#include <signal.h>
-my_sighandler_t signal_handler[_NSIG];
+static int sig_handler_nest[NSIG];
+static struct sigaction sig_handler_old[NSIG];
static void
signal_handler_internal(int sig)
{
- signal(sig, signal_handler_internal);
- if (signal_handler[sig])
- signal_handler[sig]();
- abort();
+ struct ucwlib_context *ctx = ucwlib_thread_context();
+ if (!ctx->signal_handlers || !ctx->signal_handlers[sig] || ctx->signal_handlers[sig](sig))
+ abort();
}
-void *
+void
handle_signal(int signum)
{
- return signal(signum, signal_handler_internal);
+ ucwlib_lock();
+ if (!sig_handler_nest[signum]++)
+ {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = signal_handler_internal;
+ act.sa_flags = SA_NODEFER;
+ if (sigaction(signum, &act, &sig_handler_old[signum]) < 0)
+ die("sigaction: %m");
+ }
+ ucwlib_unlock();
+}
+
+void
+unhandle_signal(int signum)
+{
+ ucwlib_lock();
+ ASSERT(sig_handler_nest[signum]);
+ if (!--sig_handler_nest[signum])
+ {
+ if (sigaction(signum, &sig_handler_old[signum], NULL) < 0)
+ die("sigaction: %m");
+ }
+ ucwlib_unlock();
+}
+
+sh_sighandler_t
+set_signal_handler(int signum, sh_sighandler_t new)
+{
+ struct ucwlib_context *ctx = ucwlib_thread_context();
+ if (!ctx->signal_handlers)
+ ctx->signal_handlers = xmalloc_zero(NSIG * sizeof(sh_sighandler_t));
+ sh_sighandler_t old = ctx->signal_handlers[signum];
+ ctx->signal_handlers[signum] = new;
+ return old;
}