Commit a8a62b4f authored by William Ahern's avatar William Ahern

add Lua module, move noise into subdirectories, and make build portable by...

add Lua module, move noise into subdirectories, and make build portable by only using POSIX make syntax and semantics
parent 26392eee
......@@ -3,9 +3,5 @@
*.gcov
*.gcno
*~
/test-timeout
/bench
/bench-heap.so
/bench-llrb.so
/bench-wheel.so
/bench.so
*.so
*.dSYM
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 $< > $@.tmp
mv $@.tmp $@
LUA_APIS = 5.1 5.2 5.3
%-del.dat: bench-%.so bench-del.lua bench-aux.lua bench.so
$(LUA) bench-del.lua $< > $@.tmp
mv $@.tmp $@
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 $< > $@.tmp
mv $@.tmp $@
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 > $@.tmp
mv $@.tmp $@
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) -- {} "+"
# 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
}
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 $@.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
mv $@.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
mv $@.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
mv $@.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}
......@@ -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
......
......@@ -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() */
......
$(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
#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;
}
......@@ -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,10 +655,16 @@ TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts
ENTER;
if (it->flags & TIMEOUTS_EXPIRED) {
if (it->flags & TIMEOUTS_CLEAR) {
while ((to = timeouts_get(T))) {
YIELD(to);
}
} else {
TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to) {
YIELD(to);
}
}
}
if (it->flags & TIMEOUTS_PENDING) {
for (it->i = 0; it->i < countof(T->wheel); it->i++) {
......
......@@ -46,9 +46,9 @@
#define TIMEOUT_VERSION TIMEOUT_V_REL
#define TIMEOUT_VENDOR "william@25thandClement.com"
#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 }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment