summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Ahern <[email protected]>2016-02-26 22:14:29 -0800
committerWilliam Ahern <[email protected]>2016-02-26 22:14:29 -0800
commita8a62b4f356f6c67ead7bcbd1ecb8202c4f6af6f (patch)
tree73aaa706c9f375f906c650454481168d9d39af2a
parent26392eee636964ac7ddd9c4f694dcf934981a04d (diff)
add Lua module, move noise into subdirectories, and make build portable by only using POSIX make syntax and semantics
-rw-r--r--.gitignore8
-rw-r--r--Makefile136
-rw-r--r--Rules.shrc40
-rw-r--r--bench/Rules.mk49
-rwxr-xr-xbench/bench-add.lua (renamed from bench-add.lua)0
-rw-r--r--bench/bench-aux.lua (renamed from bench-aux.lua)0
-rwxr-xr-xbench/bench-del.lua (renamed from bench-del.lua)0
-rwxr-xr-xbench/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.mk20
-rw-r--r--lua/timeout-lua.c396
-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.c14
-rw-r--r--timeout.h5
20 files changed, 606 insertions, 119 deletions
diff --git a/.gitignore b/.gitignore
index 70abe09..970fa92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,9 +3,5 @@
*.gcov
*.gcno
*~
-/test-timeout
-/bench
-/bench-heap.so
-/bench-llrb.so
-/bench-wheel.so
-/bench.so
+*.so
+*.dSYM
diff --git a/Makefile b/Makefile
index 591ce8e..554ebb9 100644
--- a/Makefile
+++ b/Makefile
@@ -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]
+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]
+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]
+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]
+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
+
+$(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
+
+$(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
+
+$(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
+
+$(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
diff --git a/bench.c b/bench/bench.c
index 4501383..0d4cee4 100644
--- a/bench.c
+++ b/bench/bench.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.h b/bench/bench.h
index bc1f7cf..bc1f7cf 100644
--- a/bench.h
+++ b/bench/bench.h
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
diff --git a/timeout.c b/timeout.c
index ad2373d..596949c 100644
--- a/timeout.c
+++ b/timeout.c
@@ -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);
+ }
}
}
diff --git a/timeout.h b/timeout.h
index 906c133..3ef76e9 100644
--- a/timeout.h
+++ b/timeout.h
@@ -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 }