diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/queue.c | 80 | ||||
-rw-r--r-- | src/queue.h | 17 | ||||
-rw-r--r-- | src/signal.c | 131 | ||||
-rw-r--r-- | src/signames.c | 48 | ||||
-rw-r--r-- | src/signames.h | 132 |
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 |