There are some exceptions:
- setproctitle() is not safe, it modifies global state
-- handle_signal() is not safe, it modifies global state
/* sighandler.c */
-typedef int (*sh_sighandler_t)(int);
- /* obtains signum, returns nonzero if abort() should be called */
-extern sh_sighandler_t signal_handler[];
+typedef int (*sh_sighandler_t)(int); // gets signum, returns nonzero if abort() should be called
-struct sigaction;
-void handle_signal(int signum, struct sigaction *oldact);
-void unhandle_signal(int signum, struct sigaction *oldact);
+void handle_signal(int signum);
+void unhandle_signal(int signum);
+sh_sighandler_t set_signal_handler(int signum, sh_sighandler_t new);
/* string.c */
*/
#include "lib/lib.h"
+#include "lib/threads.h"
#include "lib/lizard.h"
#include <sys/mman.h>
struct lizard_buffer {
uns len;
void *ptr;
- struct sigaction old_sigsegv_handler;
};
struct lizard_buffer *
struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
buf->len = 0;
buf->ptr = NULL;
- handle_signal(SIGSEGV, &buf->old_sigsegv_handler);
+ handle_signal(SIGSEGV);
return buf;
}
void
lizard_free(struct lizard_buffer *buf)
{
+ unhandle_signal(SIGSEGV);
if (buf->ptr)
munmap(buf->ptr, buf->len + PAGE_SIZE);
- unhandle_signal(SIGSEGV, &buf->old_sigsegv_handler);
xfree(buf);
}
buf->len = max_len;
buf->ptr = mmap(NULL, buf->len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (buf->ptr == MAP_FAILED)
- die("mmap(anonymous): %m");
+ die("mmap(anonymous, %d bytes): %m", buf->len + PAGE_SIZE);
if (mprotect(buf->ptr + buf->len, PAGE_SIZE, PROT_NONE) < 0)
die("mprotect: %m");
}
static int
sigsegv_handler(int signal UNUSED)
{
- log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
longjmp(safe_decompress_jump, 1);
return 1;
}
uns lock_offset = ALIGN_TO(expected_length + 3, PAGE_SIZE); // +3 due to the unaligned access
if (lock_offset > buf->len)
lizard_realloc(buf, lock_offset);
- volatile sh_sighandler_t old_handler = signal_handler[SIGSEGV];
- signal_handler[SIGSEGV] = sigsegv_handler;
+ volatile sh_sighandler_t old_handler = set_signal_handler(SIGSEGV, sigsegv_handler);
byte *ptr;
if (!setjmp(safe_decompress_jump))
{
}
else
{
+ log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
ptr = NULL;
errno = EFAULT;
}
- signal_handler[SIGSEGV] = old_handler;
+ set_signal_handler(SIGSEGV, old_handler);
return ptr;
}
* 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>
-sh_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)
{
- if (signal_handler[sig])
- {
- if (!signal_handler[sig](sig))
- return;
- }
- abort();
+ struct ucwlib_context *ctx = ucwlib_thread_context();
+ if (!ctx->signal_handlers[sig] || ctx->signal_handlers[sig](sig))
+ abort();
}
void
-handle_signal(int signum, struct sigaction *oldact)
+handle_signal(int signum)
{
- struct sigaction act;
- bzero(&act, sizeof(act));
- act.sa_handler = signal_handler_internal;
- act.sa_flags = SA_NODEFER;
- if (sigaction(signum, &act, oldact) < 0)
- die("sigaction: %m");
+ 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, struct sigaction *oldact)
+unhandle_signal(int signum)
{
- if (sigaction(signum, oldact, NULL) < 0)
- die("sigaction: %m");
+ 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;
}
struct ucwlib_context {
int temp_counter; // Counter for fb-temp.c
struct asio_queue *io_queue; // Async I/O queue for fb-direct.c
+ sh_sighandler_t *signal_handlers; // Signal handlers for sighandler.c
};
struct ucwlib_context *ucwlib_thread_context(void);