diff options
| author | William Ahern <[email protected]> | 2016-02-26 22:14:29 -0800 |
|---|---|---|
| committer | William Ahern <[email protected]> | 2016-02-26 22:14:29 -0800 |
| commit | a8a62b4f356f6c67ead7bcbd1ecb8202c4f6af6f (patch) | |
| tree | 73aaa706c9f375f906c650454481168d9d39af2a | |
| parent | 26392eee636964ac7ddd9c4f694dcf934981a04d (diff) | |
add Lua module, move noise into subdirectories, and make build portable by only using POSIX make syntax and semantics
| -rw-r--r-- | .gitignore | 8 | ||||
| -rw-r--r-- | Makefile | 136 | ||||
| -rw-r--r-- | Rules.shrc | 40 | ||||
| -rw-r--r-- | bench/Rules.mk | 49 | ||||
| -rwxr-xr-x | bench/bench-add.lua (renamed from bench-add.lua) | 0 | ||||
| -rw-r--r-- | bench/bench-aux.lua (renamed from bench-aux.lua) | 0 | ||||
| -rwxr-xr-x | bench/bench-del.lua (renamed from bench-del.lua) | 0 | ||||
| -rwxr-xr-x | bench/bench-expire.lua (renamed from bench-expire.lua) | 2 | ||||
| -rw-r--r-- | bench/bench-heap.c (renamed from bench-heap.c) | 0 | ||||
| -rw-r--r-- | bench/bench-llrb.c (renamed from bench-llrb.c) | 0 | ||||
| -rw-r--r-- | bench/bench-wheel.c (renamed from bench-wheel.c) | 0 | ||||
| -rw-r--r-- | bench/bench.c (renamed from bench.c) | 55 | ||||
| -rw-r--r-- | bench/bench.h (renamed from bench.h) | 0 | ||||
| -rw-r--r-- | bench/bench.plt (renamed from bench.plt) | 0 | ||||
| -rw-r--r-- | lua/Rules.mk | 20 | ||||
| -rw-r--r-- | lua/timeout-lua.c | 396 | ||||
| -rw-r--r-- | timeout-bitops.c (renamed from bitops.c) | 0 | ||||
| -rw-r--r-- | timeout-debug.h (renamed from debug.h) | 0 | ||||
| -rw-r--r-- | timeout.c | 14 | ||||
| -rw-r--r-- | timeout.h | 5 |
20 files changed, 606 insertions, 119 deletions
@@ -3,9 +3,5 @@ *.gcov *.gcno *~ -/test-timeout -/bench -/bench-heap.so -/bench-llrb.so -/bench-wheel.so -/bench.so +*.so +*.dSYM @@ -1,110 +1,68 @@ -CPPFLAGS = -DTIMEOUT_DEBUG -CFLAGS = -O2 -march=native -g -Wall -Wextra -Wno-unused-parameter -LUA = lua - -all: bench.so bench-wheel.so bench-heap.so bench-llrb.so test-timeout - -WHEEL_BIT = 6 -WHEEL_NUM = 4 - -timeout: CPPFLAGS+=-DWHEEL_BIT=$(WHEEL_BIT) -DWHEEL_NUM=$(WHEEL_NUM) - -timeout8: CPPFLAGS+=-DWHEEL_BIT=3 -DWHEEL_NUM=$(WHEEL_NUM) - -timeout16: CPPFLAGS+=-DWHEEL_BIT=4 -DWHEEL_NUM=$(WHEEL_NUM) - -timeout32: CPPFLAGS+=-DWHEEL_BIT=5 -DWHEEL_NUM=$(WHEEL_NUM) - -timeout64: CPPFLAGS+=-DWHEEL_BIT=6 -DWHEEL_NUM=$(WHEEL_NUM) - -timeout64 timeout32 timeout16 timeout8 timeout: timeout.c - $(CC) $(CFLAGS) -o $@ $^ $(CPPFLAGS) - -timeout.o: CPPFLAGS=-DWHEEL_BIT=$(WHEEL_BIT) -DWHEEL_NUM=$(WHEEL_NUM) - -timeout.o: timeout.c - $(CC) $(CFLAGS) -c -o $@ $^ $(CPPFLAGS) - -bench: bench.c timeout.h - $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -ldl +# NOTE: GNU Make 3.81 won't export MAKEFLAGS if .POSIX is specified, but +# Solaris make won't export MAKEFLAGS unless .POSIX is specified. +$(firstword ignore).POSIX: -test-timeout: timeout.o test-timeout.o - $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ timeout.o test-timeout.o - -ifeq ($(shell uname -s), Darwin) -SOFLAGS = -bundle -undefined dynamic_lookup -else -SOFLAGS = -fPIC -shared -endif - -# so bench.so can load implementation module from CWD -LDFLAGS = -Wl,-rpath,. - -# clock_gettime in librt.so -ifeq ($(shell uname -s), Linux) -LIBS = -lrt -endif - - -bench.so: bench.c - $(CC) -o $@ $< $(CPPFLAGS) -DLUA_COMPAT_ALL $(CFLAGS) -Wno-unused-function $(SOFLAGS) $(LDFLAGS) $(LIBS) - -bench-wheel8.so: CPPFLAGS+=-DWHEEL_BIT=3 -DWHEEL_NUM=$(WHEEL_NUM) +.DEFAULT_GOAL = all -bench-wheel8.so: timeout.c +.SUFFIXES: -bench-wheel16.so: CPPFLAGS+=-DWHEEL_BIT=4 -DWHEEL_NUM=$(WHEEL_NUM) +all: -bench-wheel16.so: timeout.c +# +# USER-MODIFIABLE MACROS +# +top_srcdir = . +top_builddir = . -bench-wheel32.so: CPPFLAGS+=-DWHEEL_BIT=5 -DWHEEL_NUM=$(WHEEL_NUM) +CFLAGS = -O2 -march=native -g -Wall -Wextra -Wno-unused-parameter -Wno-unused-function +SOFLAGS = $$(auto_soflags) +LIBS = $$(auto_libs) -bench-wheel32.so: timeout.c +ALL_CPPFLAGS = -I$(top_srcdir) -DWHEEL_BIT=$(WHEEL_BIT) -DWHEEL_NUM=$(WHEEL_NUM) $(CPPFLAGS) +ALL_CFLAGS = $(CFLAGS) +ALL_SOFLAGS = $(SOFLAGS) +ALL_LDFLAGS = $(LDFLAGS) +ALL_LIBS = $(LIBS) -bench-wheel64.so: CPPFLAGS+=-DWHEEL_BIT=6 -DWHEEL_NUM=$(WHEEL_NUM) - -bench-wheel64.so: timeout.c - -bench-wheel%.so: bench-wheel.c timeout.h - $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) -Wno-unused-function $(SOFLAGS) +LUA_API = 5.3 +LUA = lua +LUA51_CPPFLAGS = $(LUA_CPPFLAGS) +LUA52_CPPFLAGS = $(LUA_CPPFLAGS) +LUA53_CPPFLAGS = $(LUA_CPPFLAGS) +WHEEL_BIT = 6 +WHEEL_NUM = 4 -bench-wheel.so: CPPFLAGS+=-DWHEEL_BIT=$(WHEEL_BIT) -DWHEEL_NUM=$(WHEEL_NUM) +RM = rm -f -bench-wheel.so: timeout.c +# END MACROS -bench-%.so: bench-%.c timeout.h - $(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) -Wno-unused-function $(SOFLAGS) +SHRC = \ + top_srcdir="$(top_srcdir)"; \ + top_builddir="$(top_builddir)"; \ + . "$${top_srcdir}/Rules.shrc" -%-add.dat: bench-%.so bench-add.lua bench-aux.lua bench.so - $(LUA) bench-add.lua $< > [email protected] - mv [email protected] $@ +LUA_APIS = 5.1 5.2 5.3 -%-del.dat: bench-%.so bench-del.lua bench-aux.lua bench.so - $(LUA) bench-del.lua $< > [email protected] - mv [email protected] $@ +include $(top_srcdir)/lua/Rules.mk +include $(top_srcdir)/bench/Rules.mk -%-expire.dat: bench-%.so bench-expire.lua bench-aux.lua bench.so - $(LUA) bench-expire.lua $< > [email protected] - mv [email protected] $@ +all: test-timeout -DATS = $(foreach OP, add del expire, wheel-$(OP).dat heap-$(OP).dat) +timeout.o: $(top_srcdir)/timeout.c +test-timeout.o: $(top_srcdir)/test-timeout.c -bench.eps: bench.plt $(DATS) - gnuplot bench.plt > [email protected] - mv [email protected] $@ +timeout.o test-timeout.o: + @$(SHRC); echo_cmd $(CC) $(ALL_CFLAGS) -c -o $@ $${top_srcdir}/$(@F:%.o=%.c) $(ALL_CPPFLAGS) -bench.pdf: bench.eps - ps2pdf $< $@ +test-timeout: timeout.o test-timeout.o + @$(SHRC); echo_cmd $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -o $@ timeout.o test-timeout.o .PHONY: clean clean~ clean: - $(RM) timeout timeout8 timeout16 timeout32 timeout64 - $(RM) test-timeout *.o - $(RM) bench.so bench-*.so - $(RM) -r *.dSYM - $(RM) $(DATS) bench.eps bench.pdf - -clean~: clean - $(RM) *~ + $(RM) $(top_builddir)/test-timeout $(top_builddir)/*.o + $(RM) -r $(top_builddir)/*.dSYM + +clean~: + find $(top_builddir) $(top_srcdir) -name "*~" -exec $(RM) -- {} "+" diff --git a/Rules.shrc b/Rules.shrc new file mode 100644 index 0000000..ece75d4 --- /dev/null +++ b/Rules.shrc @@ -0,0 +1,40 @@ +# convert to absolute paths +top_srcdir="$(cd "${top_srcdir}" && pwd -L)" +top_builddir="$(cd "${top_builddir}" && pwd -L)" + +# Paths for Lua modules (benchmarks and installed modules) +export LUA_CPATH="${top_builddir}/lua/5.1/?.so;${top_builddir}/bench/?.so;;" +export LUA_PATH="${top_srcdir}/lua/?.lua;${top_srcdir}/bench/?.lua;;" +export LUA_CPATH_5_2="${top_builddir}/lua/5.2/?.so;${top_builddir}/bench/?.so;;" +export LUA_PATH_5_2="${top_srcdir}/lua/?.lua;${top_srcdir}/bench/?.lua;;" +export LUA_CPATH_5_3="${top_builddir}/lua/5.3/?.so;${top_builddir}/bench/?.so;;" +export LUA_PATH_5_3="${top_srcdir}/lua/?.lua;${top_srcdir}/bench/?.lua;;" + +# preserve stdout so we can print commands to terminal +exec 9>&1; +echo_cmd() { + printf "%s\n" "$*" >&9; + "$@"; +} + +auto_soflags() { + case "$(uname -s)" in + Darwin) + printf -- "-bundle -undefined dynamic_lookup" + ;; + *) + printf -- "-fPIC -shared" + ;; + esac +} + +auto_libs() { + case "$(uname -s)" in + Linux) + printf -- "-lrt" + ;; + *) + ;; + esac +} + diff --git a/bench/Rules.mk b/bench/Rules.mk new file mode 100644 index 0000000..3ee72f3 --- /dev/null +++ b/bench/Rules.mk @@ -0,0 +1,49 @@ +BENCH_MODS = bench.so $(BENCH_ALGOS:%=bench-%.so) +BENCH_ALGOS = wheel heap llrb +BENCH_OPS = add del expire + +$(top_builddir)/bench/bench.so: $(top_srcdir)/bench/bench.c +$(top_builddir)/bench/bench-wheel.so: $(top_srcdir)/bench/bench-wheel.c +$(top_builddir)/bench/bench-heap.so: $(top_srcdir)/bench/bench-heap.c +$(top_builddir)/bench/bench-llrb.so: $(top_srcdir)/bench/bench-llrb.c + +$(BENCH_MODS:%=$(top_builddir)/bench/%): $(top_srcdir)/timeout.h $(top_srcdir)/timeout.c $(top_srcdir)/bench/bench.h + mkdir -p $(@D) + @$(SHRC); echo_cmd $(CC) -o $@ $(top_srcdir)/bench/$(@F:%.so=%.c) $(ALL_CPPFLAGS) $(ALL_CFLAGS) $(ALL_SOFLAGS) $(ALL_LDFLAGS) $(ALL_LIBS) + +$(BENCH_OPS:%=$(top_builddir)/bench/wheel-%.dat): $(top_builddir)/bench/bench-wheel.so $(top_builddir)/bench/bench.so $(top_srcdir)/bench/bench-aux.lua +$(BENCH_OPS:%=$(top_builddir)/bench/heap-%.dat): $(top_builddir)/bench/bench-heap.so $(top_builddir)/bench/bench.so $(top_srcdir)/bench/bench-aux.lua +$(BENCH_OPS:%=$(top_builddir)/bench/llrb-%.dat): $(top_builddir)/bench/bench-llrb.so $(top_builddir)/bench/bench.so $(top_srcdir)/bench/bench-aux.lua + +$(BENCH_ALGOS:%=$(top_builddir)/bench/%-add.dat): $(top_srcdir)/bench/bench-add.lua + @$(SHRC); echo_cmd cd $(@D) && echo_cmd $(LUA) $${top_srcdir}/bench/bench-add.lua $${top_builddir}/bench/bench-$(@F:%-add.dat=%).so > $(@F).tmp + mv [email protected] $@ + +$(BENCH_ALGOS:%=$(top_builddir)/bench/%-del.dat): $(top_srcdir)/bench/bench-del.lua + @$(SHRC); echo_cmd cd $(@D) && echo_cmd $(LUA) $${top_srcdir}/bench/bench-del.lua $${top_builddir}/bench/bench-$(@F:%-del.dat=%).so > $(@F).tmp + mv [email protected] $@ + +$(BENCH_ALGOS:%=$(top_builddir)/bench/%-expire.dat): $(top_srcdir)/bench/bench-expire.lua + @$(SHRC); echo_cmd cd $(@D) && echo_cmd $(LUA) $${top_srcdir}/bench/bench-expire.lua $${top_builddir}/bench/bench-$(@F:%-expire.dat=%).so > $(@F).tmp + mv [email protected] $@ + +$(top_builddir)/bench/bench.eps: \ + $(BENCH_OPS:%=$(top_builddir)/bench/wheel-%.dat) \ + $(BENCH_OPS:%=$(top_builddir)/bench/heap-%.dat) +# $(BENCH_OPS:%=$(top_builddir)/bench/llrb-%.dat) + +$(top_builddir)/bench/bench.eps: $(top_srcdir)/bench/bench.plt + @$(SHRC); echo_cmd cd $(@D) && echo_cmd gnuplot $${top_srcdir}/bench/bench.plt > $(@F).tmp + mv [email protected] $@ + +$(top_builddir)/bench/bench.pdf: $(top_builddir)/bench/bench.eps + @$(SHRC); echo_cmd ps2pdf $${top_builddir}/bench/bench.eps $@ + +bench-mods: $(BENCH_MODS:%=$(top_builddir)/bench/%) + +bench-all: $(top_builddir)/bench/bench.pdf + +bench-clean: + $(RM) -r $(top_builddir)/bench/*.so $(top_builddir)/bench/*.dSYM + $(RM) $(top_builddir)/bench/*.dat $(top_builddir)/bench/*.tmp + $(RM) $(top_builddir)/bench/bench.{eps,pdf} diff --git a/bench-add.lua b/bench/bench-add.lua index 64a921d..64a921d 100755 --- a/bench-add.lua +++ b/bench/bench-add.lua diff --git a/bench-aux.lua b/bench/bench-aux.lua index 6321247..6321247 100644 --- a/bench-aux.lua +++ b/bench/bench-aux.lua diff --git a/bench-del.lua b/bench/bench-del.lua index 4306745..4306745 100755 --- a/bench-del.lua +++ b/bench/bench-del.lua diff --git a/bench-expire.lua b/bench/bench-expire.lua index 8e7f7cd..3e6374e 100755 --- a/bench-expire.lua +++ b/bench/bench-expire.lua @@ -19,7 +19,7 @@ for i=0,limit,step do -- expire timeouts by iteratively updating clock. exp_step is the -- approximate number of timeouts (as a fraction of the total number -- of timeouts) that will expire per update. - local exp_elapsed, exp_count = aux.time(B.expire, B, fill_count, fill_last * exp_step) + local exp_elapsed, exp_count = aux.time(B.expire, B, fill_count, math.floor(fill_last * exp_step)) assert(exp_count == i) assert(B:empty()) local exp_rate = i > 0 and i / exp_elapsed or 0 diff --git a/bench-heap.c b/bench/bench-heap.c index f1166a4..f1166a4 100644 --- a/bench-heap.c +++ b/bench/bench-heap.c diff --git a/bench-llrb.c b/bench/bench-llrb.c index bdb02f0..bdb02f0 100644 --- a/bench-llrb.c +++ b/bench/bench-llrb.c diff --git a/bench-wheel.c b/bench/bench-wheel.c index 0cba1af..0cba1af 100644 --- a/bench-wheel.c +++ b/bench/bench-wheel.c @@ -16,6 +16,31 @@ #include "timeout.h" #include "bench.h" +#if LUA_VERSION_NUM < 502 +static int lua_absindex(lua_State *L, int idx) { + return (idx > 0 || idx <= LUA_REGISTRYINDEX)? idx : lua_gettop(L) + idx + 1; +} /* lua_absindex() */ + +static void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { + int i, t = lua_absindex(L, -1 - nup); + + for (; l->name; l++) { + for (i = 0; i < nup; i++) + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); + lua_setfield(L, t, l->name); + } + + lua_pop(L, nup); +} /* luaL_setfuncs() */ + +#define luaL_newlibtable(L, l) \ + lua_createtable(L, 0, (sizeof (l) / sizeof *(l)) - 1) + +#define luaL_newlib(L, l) \ + (luaL_newlibtable((L), (l)), luaL_setfuncs((L), (l), 0)) +#endif + #ifndef MAX #define MAX(a, b) (((a) > (b))? (a) : (b)) #endif @@ -67,8 +92,8 @@ static int bench_clock(lua_State *L) { static int bench_new(lua_State *L) { const char *path = luaL_checkstring(L, 1); - size_t count = luaL_optlong(L, 2, 1000000); - timeout_t timeout_max = luaL_optlong(L, 3, 300 * 1000000L); + size_t count = luaL_optinteger(L, 2, 1000000); + timeout_t timeout_max = luaL_optinteger(L, 3, 300 * 1000000L); int verbose = (lua_isnone(L, 4))? 0 : lua_toboolean(L, 4); struct bench *B; struct benchops *ops; @@ -104,8 +129,8 @@ static int bench_add(lua_State *L) { unsigned i; timeout_t t; - i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checklong(L, 2); - t = (lua_isnoneornil(L, 3))? random() % B->timeout_max : (unsigned)luaL_checklong(L, 3); + i = (lua_isnoneornil(L, 2))? random() % B->count : (unsigned)luaL_checkinteger(L, 2); + t = (lua_isnoneornil(L, 3))? random() % B->timeout_max : (unsigned)luaL_checkinteger(L, 3); B->ops.add(B->state, &B->timeout[i], t); @@ -115,8 +140,8 @@ static int bench_add(lua_State *L) { static int bench_del(lua_State *L) { struct bench *B = lua_touserdata(L, 1); - size_t i = luaL_optlong(L, 2, random() % B->count); - size_t j = luaL_optlong(L, 3, i); + size_t i = luaL_optinteger(L, 2, random() % B->count); + size_t j = luaL_optinteger(L, 3, i); while (i <= j && i < B->count) { B->ops.del(B->state, &B->timeout[i]); @@ -129,8 +154,8 @@ static int bench_del(lua_State *L) { static int bench_fill(lua_State *L) { struct bench *B = lua_touserdata(L, 1); - size_t count = luaL_optlong(L, 2, B->count); - long timeout_inc = luaL_optlong(L, 3, -1), timeout_max = 0, timeout; + size_t count = luaL_optinteger(L, 2, B->count); + long timeout_inc = luaL_optinteger(L, 3, -1), timeout_max = 0, timeout; size_t i; if (timeout_inc < 0) { @@ -156,8 +181,8 @@ static int bench_fill(lua_State *L) { static int bench_expire(lua_State *L) { struct bench *B = lua_touserdata(L, 1); - unsigned count = luaL_optlong(L, 2, B->count); - unsigned step = luaL_optlong(L, 3, 300000); + unsigned count = luaL_optinteger(L, 2, B->count); + unsigned step = luaL_optinteger(L, 3, 300000); size_t i = 0; while (i < count && !B->ops.empty(B->state)) { @@ -256,16 +281,12 @@ int luaopen_bench(lua_State *L) { #endif if (luaL_newmetatable(L, "BENCH*")) { - luaL_register(L, NULL, bench_metatable); - lua_newtable(L); - luaL_register(L, NULL, bench_methods); + luaL_setfuncs(L, bench_metatable, 0); + luaL_newlib(L, bench_methods); lua_setfield(L, -2, "__index"); } - lua_pop(L, 1); - - lua_newtable(L); - luaL_register(L, NULL, bench_globals); + luaL_newlib(L, bench_globals); return 1; } /* luaopen_bench() */ diff --git a/bench.plt b/bench/bench.plt index 6e143c6..6e143c6 100644 --- a/bench.plt +++ b/bench/bench.plt diff --git a/lua/Rules.mk b/lua/Rules.mk new file mode 100644 index 0000000..0f06fce --- /dev/null +++ b/lua/Rules.mk @@ -0,0 +1,20 @@ +$(LUA_APIS:%=$(top_builddir)/lua/%/timeout.so): $(top_srcdir)/lua/timeout-lua.c $(top_srcdir)/timeout.h $(top_srcdir)/timeout.c + mkdir -p $(@D) + @$(SHRC); echo_cmd $(CC) -o $@ $(top_srcdir)/lua/timeout-lua.c -I$(top_srcdir) -DWHEEL_BIT=$(WHEEL_BIT) -DWHEEL_NUM=$(WHEEL_NUM) $(LUA53_CPPFLAGS) $(ALL_CPPFLAGS) $(ALL_CFLAGS) $(ALL_SOFLAGS) $(ALL_LDFLAGS) $(ALL_LIBS) + +$(top_builddir)/lua/5.1/timeouts.so: $(top_builddir)/lua/5.1/timeout.so +$(top_builddir)/lua/5.2/timeouts.so: $(top_builddir)/lua/5.2/timeout.so +$(top_builddir)/lua/5.3/timeouts.so: $(top_builddir)/lua/5.3/timeout.so + +$(LUA_APIS:%=$(top_builddir)/lua/%/timeouts.so): + cd $(@D) && ln -fs timeout.so timeouts.so + +lua-5.1: $(top_builddir)/lua/5.1/timeout.so $(top_builddir)/lua/5.1/timeouts.so +lua-5.2: $(top_builddir)/lua/5.2/timeout.so $(top_builddir)/lua/5.2/timeouts.so +lua-5.3: $(top_builddir)/lua/5.3/timeout.so $(top_builddir)/lua/5.3/timeouts.so + +lua-clean: + $(RM) -r $(top_builddir)/lua/5.? + +clean: lua-clean + diff --git a/lua/timeout-lua.c b/lua/timeout-lua.c new file mode 100644 index 0000000..4d4e54c --- /dev/null +++ b/lua/timeout-lua.c @@ -0,0 +1,396 @@ +#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; +} diff --git a/bitops.c b/timeout-bitops.c index d8325db..d8325db 100644 --- a/bitops.c +++ b/timeout-bitops.c diff --git a/debug.h b/timeout-debug.h index fc727a6..fc727a6 100644 --- a/debug.h +++ b/timeout-debug.h @@ -40,7 +40,7 @@ #include "timeout.h" #if TIMEOUT_DEBUG - 0 -#include "debug.h" +#include "timeout-debug.h" #endif #ifdef TIMEOUT_DISABLE_RELATIVE_ACCESS @@ -134,7 +134,7 @@ #define WHEEL_MASK (WHEEL_LEN - 1) #define TIMEOUT_MAX ((TIMEOUT_C(1) << (WHEEL_BIT * WHEEL_NUM)) - 1) -#include "bitops.c" +#include "timeout-bitops.c" #if WHEEL_BIT == 6 #define ctz(n) ctz64(n) @@ -655,8 +655,14 @@ TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts ENTER; if (it->flags & TIMEOUTS_EXPIRED) { - TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to) { - YIELD(to); + if (it->flags & TIMEOUTS_CLEAR) { + while ((to = timeouts_get(T))) { + YIELD(to); + } + } else { + TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to) { + YIELD(to); + } } } @@ -46,9 +46,9 @@ #define TIMEOUT_VERSION TIMEOUT_V_REL #define TIMEOUT_VENDOR "[email protected]" -#define TIMEOUT_V_REL 0x20160224 +#define TIMEOUT_V_REL 0x20160226 #define TIMEOUT_V_ABI 0x20160224 -#define TIMEOUT_V_API 0x20160224 +#define TIMEOUT_V_API 0x20160226 TIMEOUT_PUBLIC int timeout_version(void); @@ -201,6 +201,7 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *, FILE *); #define TIMEOUTS_PENDING 0x10 #define TIMEOUTS_EXPIRED 0x20 #define TIMEOUTS_ALL (TIMEOUTS_PENDING|TIMEOUTS_EXPIRED) +#define TIMEOUTS_CLEAR 0x40 #define TIMEOUTS_IT_INITIALIZER(flags) { (flags), 0, 0, 0, 0 } |
