123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- #include <assert.h>
- #include <string.h>
- #include <lua.h>
- #include <lualib.h>
- #include <lauxlib.h>
- #if LUA_VERSION_NUM != 503
- #error only Lua 5.3 supported
- #endif
- #define TIMEOUT_PUBLIC static
- #include "timeout.h"
- #include "timeout.c"
- #define TIMEOUT_METANAME "struct timeout"
- #define TIMEOUTS_METANAME "struct timeouts*"
- static struct timeout *
- to_checkudata(lua_State *L, int index)
- {
- return luaL_checkudata(L, index, TIMEOUT_METANAME);
- }
- static struct timeouts *
- tos_checkudata(lua_State *L, int index)
- {
- return *(struct timeouts **)luaL_checkudata(L, index, TIMEOUTS_METANAME);
- }
- static void
- tos_bind(lua_State *L, int tos_index, int to_index)
- {
- lua_getuservalue(L, tos_index);
- lua_pushlightuserdata(L, to_checkudata(L, to_index));
- lua_pushvalue(L, to_index);
- lua_rawset(L, -3);
- lua_pop(L, 1);
- }
- static void
- tos_unbind(lua_State *L, int tos_index, int to_index)
- {
- lua_getuservalue(L, tos_index);
- lua_pushlightuserdata(L, to_checkudata(L, to_index));
- lua_pushnil(L);
- lua_rawset(L, -3);
- lua_pop(L, 1);
- }
- static int
- to__index(lua_State *L)
- {
- struct timeout *to = to_checkudata(L, 1);
- if (lua_type(L, 2 == LUA_TSTRING)) {
- const char *key = lua_tostring(L, 2);
- if (!strcmp(key, "flags")) {
- lua_pushinteger(L, to->flags);
- return 1;
- } else if (!strcmp(key, "expires")) {
- lua_pushinteger(L, to->expires);
- return 1;
- }
- }
- if (LUA_TNIL != lua_getuservalue(L, 1)) {
- lua_pushvalue(L, 2);
- if (LUA_TNIL != lua_rawget(L, -2))
- return 1;
- }
- lua_pushvalue(L, 2);
- if (LUA_TNIL != lua_rawget(L, lua_upvalueindex(1)))
- return 1;
- return 0;
- }
- static int
- to__newindex(lua_State *L)
- {
- if (LUA_TNIL == lua_getuservalue(L, 1)) {
- lua_newtable(L);
- lua_pushvalue(L, -1);
- lua_setuservalue(L, 1);
- }
- lua_pushvalue(L, 2);
- lua_pushvalue(L, 3);
- lua_rawset(L, -3);
- return 0;
- }
- static int
- to__gc(lua_State *L)
- {
- struct timeout *to = to_checkudata(L, 1);
- /*
- * NB: On script exit it's possible for a timeout to still be
- * associated with a timeouts object, particularly when the timeouts
- * object was created first.
- */
- timeout_del(to);
- return 0;
- }
- static int
- to_new(lua_State *L)
- {
- int flags = luaL_optinteger(L, 1, 0);
- struct timeout *to;
- to = lua_newuserdata(L, sizeof *to);
- timeout_init(to, flags);
- luaL_setmetatable(L, TIMEOUT_METANAME);
- return 1;
- }
- static const luaL_Reg to_methods[] = {
- { NULL, NULL },
- };
- static const luaL_Reg to_metatable[] = {
- { "__index", &to__index },
- { "__newindex", &to__newindex },
- { "__gc", &to__gc },
- { NULL, NULL },
- };
- static const luaL_Reg to_globals[] = {
- { "new", &to_new },
- { NULL, NULL },
- };
- static void
- to_newmetatable(lua_State *L)
- {
- if (luaL_newmetatable(L, TIMEOUT_METANAME)) {
- /*
- * fill metamethod table, capturing the methods table as an
- * upvalue for use by __index metamethod
- */
- luaL_newlib(L, to_methods);
- luaL_setfuncs(L, to_metatable, 1);
- }
- }
- int
- luaopen_timeout(lua_State *L)
- {
- to_newmetatable(L);
- luaL_newlib(L, to_globals);
- lua_pushinteger(L, TIMEOUT_INT);
- lua_setfield(L, -2, "INT");
- lua_pushinteger(L, TIMEOUT_ABS);
- lua_setfield(L, -2, "ABS");
- return 1;
- }
- static int
- tos_update(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- lua_Number n = luaL_checknumber(L, 2);
- timeouts_update(T, timeouts_f2i(T, n));
- lua_pushvalue(L, 1);
- return 1;
- }
- static int
- tos_step(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- lua_Number n = luaL_checknumber(L, 2);
- timeouts_step(T, timeouts_f2i(T, n));
- lua_pushvalue(L, 1);
- return 1;
- }
- static int
- tos_timeout(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- lua_pushnumber(L, timeouts_i2f(T, timeouts_timeout(T)));
- return 1;
- }
- static int
- tos_add(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- struct timeout *to = to_checkudata(L, 2);
- lua_Number timeout = luaL_checknumber(L, 3);
- tos_bind(L, 1, 2);
- timeouts_addf(T, to, timeout);
- return lua_pushvalue(L, 1), 1;
- }
- static int
- tos_del(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- struct timeout *to = to_checkudata(L, 2);
- timeouts_del(T, to);
- tos_unbind(L, 1, 2);
- return lua_pushvalue(L, 1), 1;
- }
- static int
- tos_get(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- struct timeout *to;
- if (!(to = timeouts_get(T)))
- return 0;
- lua_getuservalue(L, 1);
- lua_rawgetp(L, -1, to);
- if (!timeout_pending(to))
- tos_unbind(L, 1, lua_absindex(L, -1));
- return 1;
- }
- static int
- tos_pending(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- lua_pushboolean(L, timeouts_pending(T));
- return 1;
- }
- static int
- tos_expired(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- lua_pushboolean(L, timeouts_expired(T));
- return 1;
- }
- static int
- tos_check(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, 1);
- lua_pushboolean(L, timeouts_check(T, NULL));
- return 1;
- }
- static int
- tos__next(lua_State *L)
- {
- struct timeouts *T = tos_checkudata(L, lua_upvalueindex(1));
- struct timeouts_it *it = lua_touserdata(L, lua_upvalueindex(2));
- struct timeout *to;
- if (!(to = timeouts_next(T, it)))
- return 0;
- lua_getuservalue(L, lua_upvalueindex(1));
- lua_rawgetp(L, -1, to);
- return 1;
- }
- static int
- tos_timeouts(lua_State *L)
- {
- int flags = luaL_checkinteger(L, 2);
- struct timeouts_it *it;
- tos_checkudata(L, 1);
- lua_pushvalue(L, 1);
- it = lua_newuserdata(L, sizeof *it);
- TIMEOUTS_IT_INIT(it, flags);
- lua_pushcclosure(L, &tos__next, 2);
- return 1;
- }
- static int
- tos__gc(lua_State *L)
- {
- struct timeouts **tos = luaL_checkudata(L, 1, TIMEOUTS_METANAME);
- struct timeout *to;
- TIMEOUTS_FOREACH(to, *tos, TIMEOUTS_ALL) {
- timeouts_del(*tos, to);
- }
- timeouts_close(*tos);
- *tos = NULL;
- return 0;
- }
- static int
- tos_new(lua_State *L)
- {
- timeout_t hz = luaL_optinteger(L, 1, 0);
- struct timeouts **T;
- int error;
-
- T = lua_newuserdata(L, sizeof *T);
- luaL_setmetatable(L, TIMEOUTS_METANAME);
- lua_newtable(L);
- lua_setuservalue(L, -2);
- if (!(*T = timeouts_open(hz, &error)))
- return luaL_error(L, "%s", strerror(error));
- return 1;
- }
- static const luaL_Reg tos_methods[] = {
- { "update", &tos_update },
- { "step", &tos_step },
- { "timeout", &tos_timeout },
- { "add", &tos_add },
- { "del", &tos_del },
- { "get", &tos_get },
- { "pending", &tos_pending },
- { "expired", &tos_expired },
- { "check", &tos_check },
- { "timeouts", &tos_timeouts },
- { NULL, NULL },
- };
- static const luaL_Reg tos_metatable[] = {
- { "__gc", &tos__gc },
- { NULL, NULL },
- };
- static const luaL_Reg tos_globals[] = {
- { "new", &tos_new },
- { NULL, NULL },
- };
- static void
- tos_newmetatable(lua_State *L)
- {
- if (luaL_newmetatable(L, TIMEOUTS_METANAME)) {
- luaL_setfuncs(L, tos_metatable, 0);
- luaL_newlib(L, tos_methods);
- lua_setfield(L, -2, "__index");
- }
- }
- int
- luaopen_timeouts(lua_State *L)
- {
- to_newmetatable(L);
- tos_newmetatable(L);
- luaL_newlib(L, tos_globals);
- lua_pushinteger(L, TIMEOUTS_PENDING);
- lua_setfield(L, -2, "PENDING");
- lua_pushinteger(L, TIMEOUTS_EXPIRED);
- lua_setfield(L, -2, "EXPIRED");
- lua_pushinteger(L, TIMEOUTS_ALL);
- lua_setfield(L, -2, "ALL");
- lua_pushinteger(L, TIMEOUTS_CLEAR);
- lua_setfield(L, -2, "CLEAR");
- return 1;
- }
|