-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Asbjørn Sloth Tønnesen <[email protected]> Signed-off-by: Emil Renner Berthing <[email protected]>
- Loading branch information
Showing
4 changed files
with
302 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
-- | ||
-- This file is part of LEM, a Lua Event Machine. | ||
-- Copyright 2013 Asbjørn Sloth Tønnesen | ||
-- | ||
-- LEM is free software: you can redistribute it and/or modify it | ||
-- under the terms of the GNU Lesser General Public License as | ||
-- published by the Free Software Foundation, either version 3 of | ||
-- the License, or (at your option) any later version. | ||
-- | ||
-- LEM is distributed in the hope that it will be useful, but | ||
-- WITHOUT ANY WARRANTY; without even the implied warranty of | ||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
-- GNU Lesser General Public License for more details. | ||
-- | ||
-- You should have received a copy of the GNU Lesser General Public | ||
-- License along with LEM. If not, see <http://www.gnu.org/licenses/>. | ||
-- | ||
|
||
local core = require 'lem.signal.core' | ||
|
||
local queues = {} | ||
|
||
local function fire(signal, ...) | ||
local queue = queues[signal] | ||
for i = 1, #queue do | ||
queue[i](signal, ...) | ||
end | ||
end | ||
|
||
local install_signal_handler | ||
do | ||
local installed = false | ||
function install_signal_handler() | ||
if not installed then | ||
core.sethandler(function(signal, ...) | ||
fire(signal, ...) | ||
end) | ||
installed = true | ||
end | ||
end | ||
end | ||
|
||
local signal_install, signal_uninstall | ||
do | ||
local installed = {} | ||
|
||
function signal_install(sig) | ||
if installed[sig] then | ||
return true | ||
end | ||
|
||
install_signal_handler() | ||
|
||
local ret, err = core.watch(sig) | ||
if not ret then return nil, err end | ||
|
||
installed[sig] = true | ||
return true | ||
end | ||
|
||
function signal_uninstall(sig) | ||
if not installed[sig] then | ||
return true | ||
end | ||
|
||
local ret, err = core.unwatch(sig) | ||
if not ret then return nil, err end | ||
|
||
installed[sig] = nil | ||
return true | ||
end | ||
end | ||
|
||
local M = {} | ||
|
||
function M.register(signum, func) | ||
if not signum then return nil, 'unknown signal' end | ||
|
||
local queue = queues[signum] | ||
if queue == nil then | ||
queue = {} | ||
queues[signum] = queue | ||
end | ||
table.insert(queue, func) | ||
return signal_install(signum) | ||
end | ||
|
||
function M.unregister(signum, func) | ||
if not signum then return nil, 'unknown signal' end | ||
|
||
local queue = queues[signum] | ||
if queue then | ||
for i = 1, #queue do | ||
if queue[i] == func then | ||
table.remove(queue, i) | ||
end | ||
end | ||
if #queue == 0 then | ||
return signal_uninstall(signum) | ||
end | ||
end | ||
return true | ||
end | ||
|
||
return M | ||
|
||
-- vim: ts=2 sw=2 noet: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* | ||
* This file is part of LEM, a Lua Event Machine. | ||
* Copyright 2013 Asbjørn Sloth Tønnesen | ||
* Copyright 2013 Emil Renner Berthing | ||
* | ||
* LEM is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU Lesser General Public License as | ||
* published by the Free Software Foundation, either version 3 of | ||
* the License, or (at your option) any later version. | ||
* | ||
* LEM is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with LEM. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <lem.h> | ||
#include <sys/types.h> | ||
#include <sys/wait.h> | ||
#include <assert.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
static int signal_sethandler(lua_State *T); | ||
|
||
#if EV_SIGNAL_ENABLE | ||
struct sigwatcher { | ||
struct sigwatcher *next; | ||
struct ev_signal w; | ||
}; | ||
|
||
static sigset_t signal_sigset; | ||
static struct sigwatcher *signal_watchers; | ||
|
||
static void | ||
signal_os_handler(EV_P_ struct ev_signal *w, int revents) | ||
{ | ||
lua_State *S; | ||
|
||
(void)revents; | ||
|
||
S = lem_newthread(); | ||
lua_pushlightuserdata(S, &signal_sethandler); | ||
lua_rawget(S, LUA_REGISTRYINDEX); | ||
if (lua_type(S, 1) != LUA_TFUNCTION) { | ||
lem_forgetthread(S); | ||
return; | ||
} | ||
|
||
lua_pushinteger(S, w->signum); | ||
lem_queue(S, 1); | ||
} | ||
|
||
static int | ||
signal_os_watch(lua_State *T, int sig) | ||
{ | ||
struct sigwatcher *s; | ||
|
||
if (sigismember(&signal_sigset, sig)) | ||
goto out; /* already watched */ | ||
|
||
s = lem_xmalloc(sizeof(struct sigwatcher)); | ||
|
||
ev_signal_init(&s->w, signal_os_handler, sig); | ||
ev_set_priority(&s->w, EV_MAXPRI); | ||
ev_signal_start(LEM_ &s->w); | ||
ev_unref(LEM); /* watcher shouldn't keep loop alive */ | ||
|
||
sigaddset(&signal_sigset, sig); | ||
pthread_sigmask(SIG_UNBLOCK, &signal_sigset, NULL); | ||
|
||
s->next = signal_watchers; | ||
signal_watchers = s; | ||
out: | ||
lua_pushboolean(T, 1); | ||
return 1; | ||
} | ||
|
||
static int | ||
signal_os_unwatch(lua_State *T, int sig) | ||
{ | ||
struct sigwatcher **prevp; | ||
struct sigwatcher *s; | ||
|
||
for (prevp = &signal_watchers, s = signal_watchers; | ||
s != NULL; | ||
prevp = &s->next, s = s->next) { | ||
if (s->w.signum == sig) | ||
break; | ||
} | ||
if (s != NULL) { | ||
ev_ref(LEM); | ||
ev_signal_stop(LEM_ &s->w); | ||
|
||
sigdelset(&signal_sigset, sig); | ||
|
||
*prevp = s->next; | ||
free(s); | ||
} | ||
lua_pushboolean(T, 1); | ||
return 1; | ||
} | ||
#else /* EV_SIGNAL_ENABLE */ | ||
static int | ||
signal_os_unsupported(lua_State *T) | ||
{ | ||
lua_pushnil(T); | ||
lua_pushliteral(T, "Your libev is compiled without signal support."); | ||
return 2 | ||
} | ||
|
||
static inline int | ||
signal_os_watch(lua_State *T) | ||
{ | ||
return signal_os_unsupported(T); | ||
} | ||
|
||
static inline int | ||
signal_os_unwatch(lua_State *T) | ||
{ | ||
return signal_os_unsupported(T); | ||
} | ||
#endif | ||
|
||
static int | ||
signal_sethandler(lua_State *T) | ||
{ | ||
int type; | ||
|
||
if (lua_gettop(T) < 1) | ||
lua_pushnil(T); | ||
|
||
type = lua_type(T, 1); | ||
if (type != LUA_TNIL && type != LUA_TFUNCTION) | ||
return luaL_argerror(T, 1, "expected nil or a function"); | ||
|
||
lua_settop(T, 1); | ||
lua_pushlightuserdata(T, &signal_sethandler); | ||
lua_insert(T, 1); | ||
lua_rawset(T, LUA_REGISTRYINDEX); | ||
return 0; | ||
} | ||
|
||
static int | ||
signal_watch(lua_State *T) | ||
{ | ||
int sig = luaL_checkint(T, 1); | ||
|
||
lua_settop(T, 1); | ||
lua_pushlightuserdata(T, &signal_sethandler); | ||
lua_rawget(T, LUA_REGISTRYINDEX); | ||
if (lua_isnil(T, 2)) | ||
return luaL_error(T, "You must set a signal handler first"); | ||
|
||
return signal_os_watch(T, sig); | ||
} | ||
|
||
static int | ||
signal_unwatch(lua_State *T) | ||
{ | ||
int sig = luaL_checkint(T, 1); | ||
return signal_os_unwatch(T, sig); | ||
} | ||
|
||
int | ||
luaopen_lem_signal_core(lua_State *T) | ||
{ | ||
#if EV_SIGNAL_ENABLE | ||
sigemptyset(&signal_sigset); | ||
/* signal_watchers = NULL; globals are zero initalized */ | ||
#endif | ||
|
||
/* create module table */ | ||
lua_newtable(T); | ||
|
||
/* set sethandler function */ | ||
lua_pushcfunction(T, signal_sethandler); | ||
lua_setfield(T, -2, "sethandler"); | ||
/* set watch function */ | ||
lua_pushcfunction(T, signal_watch); | ||
lua_setfield(T, -2, "watch"); | ||
/* set unwatch function */ | ||
lua_pushcfunction(T, signal_unwatch); | ||
lua_setfield(T, -2, "unwatch"); | ||
|
||
return 1; | ||
} |