aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjluehrs2 <jluehrs2@uiuc.edu>2007-10-09 00:01:26 -0500
committerjluehrs2 <jluehrs2@uiuc.edu>2007-10-09 00:01:26 -0500
commit47f828f11b985fec6c92818378a1bfbb51e1bc6c (patch)
tree4589445ed5e3fc2e2fe55537bd92a7a4dcf350d5
parent2f1d9b3dff79e17dc5f277b5df0bb29e54d218f2 (diff)
downloadluasignal-47f828f11b985fec6c92818378a1bfbb51e1bc6c.tar.gz
luasignal-47f828f11b985fec6c92818378a1bfbb51e1bc6c.zip
initial working implementation of installing signal handlers
-rw-r--r--src/queue.c80
-rw-r--r--src/queue.h17
-rw-r--r--src/signal.c131
-rw-r--r--src/signames.c48
-rw-r--r--src/signames.h132
5 files changed, 408 insertions, 0 deletions
diff --git a/src/queue.c b/src/queue.c
new file mode 100644
index 0000000..012e986
--- /dev/null
+++ b/src/queue.c
@@ -0,0 +1,80 @@
+#include "queue.h"
+#include <stdlib.h>
+
+static int _queue_resize(queue* q, int new_cap)
+{
+ int* new_queue;
+ int i;
+
+ if (new_cap <= q->cap) {
+ return 0;
+ }
+ if ((new_queue = (int*)malloc(new_cap * sizeof(int))) == NULL) {
+ return 0;
+ }
+ if (q->front <= q->back) {
+ q->front = q->front + q->cap;
+ }
+ for (i = q->back; i < q->front; ++i) {
+ new_queue[i - q->back] = q->queue[i % q->cap];
+ }
+ free(q->queue);
+ q->queue = new_queue;
+ q->cap = new_cap;
+ q->front = q->size;
+ q->back = 0;
+
+ return 1;
+}
+
+int queue_init(queue* q, int cap)
+{
+ if (cap < 1) {
+ return 0;
+ }
+ if ((q->queue = (int*)malloc(cap * sizeof(int))) == NULL) {
+ return 0;
+ }
+ q->size = 0;
+ q->cap = cap;
+ q->front = 0;
+ q->back = 0;
+
+ return 1;
+}
+
+int enqueue(queue* q, int item)
+{
+ if (q->size == q->cap) {
+ if (!_queue_resize(q, 2 * q->cap)) {
+ return 0;
+ }
+ }
+ q->queue[q->front++] = item;
+ q->front %= q->cap;
+ ++q->size;
+
+ return 1;
+}
+
+int dequeue(queue* q)
+{
+ int ret;
+
+ if (q->size == 0) {
+ return -1;
+ }
+ ret = q->queue[q->back++];
+ q->back %= q->cap;
+ --q->size;
+
+ return ret;
+}
+
+void queue_delete(queue* q)
+{
+ free(q->queue);
+ q->queue = NULL;
+ q->size = 0;
+ q->cap = 0;
+}
diff --git a/src/queue.h b/src/queue.h
new file mode 100644
index 0000000..54c3179
--- /dev/null
+++ b/src/queue.h
@@ -0,0 +1,17 @@
+#ifndef QUEUE_H
+#define QUEUE_H
+
+typedef struct _queue {
+ int* queue;
+ int size;
+ int cap;
+ int front;
+ int back;
+} queue;
+
+int queue_init(queue* q, int cap);
+int enqueue(queue* q, int item);
+int dequeue(queue* q);
+void queue_delete(queue* q);
+
+#endif
diff --git a/src/signal.c b/src/signal.c
new file mode 100644
index 0000000..018ad63
--- /dev/null
+++ b/src/signal.c
@@ -0,0 +1,131 @@
+#include "queue.h"
+#include "signames.h"
+#include <lua.h>
+#include <lauxlib.h>
+#include <signal.h>
+#include <string.h>
+
+#define REG_TABLE "luasignal"
+
+static lua_State* gL = NULL;
+static lua_Hook old_hook = NULL;
+static int old_mask = 0;
+static int old_count = 0;
+static queue q;
+static struct sigaction lua_handlers[256];
+
+static void lua_signal_handler(lua_State* L, lua_Debug* D)
+{
+ sigset_t sset, oldset;
+ int sig;
+
+ lua_sethook(gL, old_hook, old_mask, old_count);
+
+ sigfillset(&sset);
+ sigprocmask(SIG_BLOCK, &sset, &oldset);
+
+ while ((sig = dequeue(&q)) != -1) {
+ const char* signame;
+
+ signame = sig_to_name(sig);
+ lua_getfield(gL, LUA_REGISTRYINDEX, REG_TABLE);
+ lua_getfield(gL, -1, signame);
+ lua_pushstring(gL, signame);
+ lua_call(gL, 1, 0);
+ }
+
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+}
+
+static void signal_handler(int sig)
+{
+ if (q.size == 0) {
+ old_hook = lua_gethook(gL);
+ old_mask = lua_gethookmask(gL);
+ old_count = lua_gethookcount(gL);
+ lua_sethook(gL, lua_signal_handler,
+ LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+ }
+
+ enqueue(&q, sig);
+}
+
+static int l_signal(lua_State* L)
+{
+ const char* signame;
+ int sig;
+ struct sigaction sa;
+ sigset_t sset;
+ void (*handler)(int) = NULL;
+
+ gL = L;
+
+ signame = luaL_checklstring(gL, 1, NULL);
+ sig = name_to_sig(signame);
+ if (sig == -1) {
+ lua_pushfstring(gL, "signal() called with invalid signal name: %s", signame);
+ lua_error(gL);
+ }
+
+ if (lua_isfunction(gL, 2)) {
+ handler = signal_handler;
+ lua_getfield(gL, LUA_REGISTRYINDEX, REG_TABLE);
+ lua_pushvalue(gL, 2);
+ lua_setfield(gL, -2, signame);
+ }
+ else if (lua_isstring(gL, 2)) {
+ const char* pseudo_handler;
+
+ pseudo_handler = lua_tostring(gL, 2);
+ if (strcmp(pseudo_handler, "ignore") == 0) {
+ handler = SIG_IGN;
+ }
+ else if (strcmp(pseudo_handler, "default") == 0) {
+ handler = SIG_DFL;
+ }
+ else if (strcmp(pseudo_handler, "luadefault") == 0) {
+ if (lua_handlers[sig].sa_handler != NULL) {
+ handler = lua_handlers[sig].sa_handler;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ lua_pushstring(gL, "Must pass a valid handler to signal()");
+ lua_error(gL);
+ }
+ }
+ else {
+ lua_pushstring(gL, "Must pass a handler to signal()");
+ lua_error(gL);
+ }
+ sa.sa_handler = handler;
+ sigfillset(&sset);
+ sa.sa_mask = sset;
+ if (lua_handlers[sig].sa_handler == NULL) {
+ sigaction(sig, &sa, &(lua_handlers[sig]));
+ }
+ else {
+ sigaction(sig, &sa, NULL);
+ }
+
+ return 0;
+}
+
+const luaL_Reg reg[] = {
+ { "signal", l_signal },
+ { NULL, NULL },
+};
+
+int luaopen_signal(lua_State* L)
+{
+ queue_init(&q, 4);
+
+ lua_newtable(L);
+ lua_setfield(L, LUA_REGISTRYINDEX, REG_TABLE);
+
+ luaL_register(L, "signal", reg);
+
+ return 1;
+}
diff --git a/src/signames.c b/src/signames.c
new file mode 100644
index 0000000..d3bf82c
--- /dev/null
+++ b/src/signames.c
@@ -0,0 +1,48 @@
+#include "signames.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char* sig_to_name(int sig)
+{
+ static char signame[7];
+
+ if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
+ snprintf(signame, 7, "RT%d", sig - SIGRTMIN);
+
+ return signame;
+ }
+ else {
+ int i;
+
+ for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); ++i) {
+ if (sigs[i].sig == sig) {
+ return sigs[i].name;
+ }
+ }
+
+ return NULL;
+ }
+}
+
+int name_to_sig(const char* name)
+{
+ if (strncmp(name, "RT", 2) == 0) {
+ int rtsig;
+
+ rtsig = atoi(name + 2);
+
+ return rtsig + SIGRTMIN;
+ }
+ else {
+ int i;
+
+ for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); ++i) {
+ if (strcmp(sigs[i].name, name) == 0) {
+ return sigs[i].sig;
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/src/signames.h b/src/signames.h
new file mode 100644
index 0000000..3850df6
--- /dev/null
+++ b/src/signames.h
@@ -0,0 +1,132 @@
+#ifndef SIGNAMES_H
+#define SIGNAMES_H
+
+#include <signal.h>
+
+struct signame {
+ int sig;
+ const char* name;
+};
+
+static const struct signame sigs[] =
+{
+#ifdef SIGABRT
+ {SIGABRT, "ABRT"},
+#endif
+#ifdef SIGALRM
+ {SIGALRM, "ALRM"},
+#endif
+#ifdef SIGBUS
+ {SIGBUS, "BUS"},
+#endif
+#ifdef SIGCHLD
+ {SIGCHLD, "CHLD"},
+#endif
+#ifdef SIGCLD
+ {SIGCLD, "CLD"},
+#endif
+#ifdef SIGCONT
+ {SIGCONT, "CONT"},
+#endif
+#ifdef SIGEMT
+ {SIGEMT, "EMT"},
+#endif
+#ifdef SIGFPE
+ {SIGFPE, "FPE"},
+#endif
+#ifdef SIGHUP
+ {SIGHUP, "HUP"},
+#endif
+#ifdef SIGILL
+ {SIGILL, "ILL"},
+#endif
+#ifdef SIGINFO
+ {SIGINFO, "INFO"},
+#endif
+#ifdef SIGINT
+ {SIGINT, "INT"},
+#endif
+#ifdef SIGIO
+ {SIGIO, "IO"},
+#endif
+#ifdef SIGIOT
+ {SIGIOT, "IOT"},
+#endif
+#ifdef SIGKILL
+ {SIGKILL, "KILL"},
+#endif
+#ifdef SIGLOST
+ {SIGLOST, "LOST"},
+#endif
+#ifdef SIGPIPE
+ {SIGPIPE, "PIPE"},
+#endif
+#ifdef SIGPOLL
+ {SIGPOLL, "POLL"},
+#endif
+#ifdef SIGPROF
+ {SIGPROF, "PROF"},
+#endif
+#ifdef SIGPWR
+ {SIGPWR, "PWR"},
+#endif
+#ifdef SIGQUIT
+ {SIGQUIT, "QUIT"},
+#endif
+#ifdef SIGSEGV
+ {SIGSEGV, "SEGV"},
+#endif
+#ifdef SIGSTKFLT
+ {SIGSTKFLT, "STKFLT"},
+#endif
+#ifdef SIGSTOP
+ {SIGSTOP, "STOP"},
+#endif
+#ifdef SIGSYS
+ {SIGSYS, "SYS"},
+#endif
+#ifdef SIGTERM
+ {SIGTERM, "TERM"},
+#endif
+#ifdef SIGTRAP
+ {SIGTRAP, "TRAP"},
+#endif
+#ifdef SIGTSTP
+ {SIGTSTP, "TSTP"},
+#endif
+#ifdef SIGTTIN
+ {SIGTTIN, "TTIN"},
+#endif
+#ifdef SIGTTOU
+ {SIGTTOU, "TTOU"},
+#endif
+#ifdef SIGUNUSED
+ {SIGUNUSED, "UNUSED"},
+#endif
+#ifdef SIGURG
+ {SIGURG, "URG"},
+#endif
+#ifdef SIGUSR1
+ {SIGUSR1, "USR1"},
+#endif
+#ifdef SIGUSR2
+ {SIGUSR2, "USR2"},
+#endif
+#ifdef SIGVTALRM
+ {SIGVTALRM, "VTALRM"},
+#endif
+#ifdef SIGWINCH
+ {SIGWINCH, "WINCH"},
+#endif
+#ifdef SIGXCPU
+ {SIGXCPU, "XCPU"},
+#endif
+#ifdef SIGXFSZ
+ {SIGXFSZ, "XFSZ"},
+#endif
+};
+
+int name_to_sig(const char* name);
+const char* sig_to_name(int sig);
+
+#endif