Tor 0.4.9.0-alpha-dev
timeout-lua.c
1#include <assert.h>
2#include <string.h>
3
4#include <lua.h>
5#include <lualib.h>
6#include <lauxlib.h>
7
8#if LUA_VERSION_NUM != 503
9#error only Lua 5.3 supported
10#endif
11
12#define TIMEOUT_PUBLIC static
13#include "timeout.h"
14#include "timeout.c"
15
16#define TIMEOUT_METANAME "struct timeout"
17#define TIMEOUTS_METANAME "struct timeouts*"
18
19static struct timeout *
20to_checkudata(lua_State *L, int index)
21{
22 return luaL_checkudata(L, index, TIMEOUT_METANAME);
23}
24
25static struct timeouts *
26tos_checkudata(lua_State *L, int index)
27{
28 return *(struct timeouts **)luaL_checkudata(L, index, TIMEOUTS_METANAME);
29}
30
31static void
32tos_bind(lua_State *L, int tos_index, int to_index)
33{
34 lua_getuservalue(L, tos_index);
35 lua_pushlightuserdata(L, to_checkudata(L, to_index));
36 lua_pushvalue(L, to_index);
37 lua_rawset(L, -3);
38 lua_pop(L, 1);
39}
40
41static void
42tos_unbind(lua_State *L, int tos_index, int to_index)
43{
44 lua_getuservalue(L, tos_index);
45 lua_pushlightuserdata(L, to_checkudata(L, to_index));
46 lua_pushnil(L);
47 lua_rawset(L, -3);
48 lua_pop(L, 1);
49}
50
51static int
52to__index(lua_State *L)
53{
54 struct timeout *to = to_checkudata(L, 1);
55
56 if (lua_type(L, 2 == LUA_TSTRING)) {
57 const char *key = lua_tostring(L, 2);
58
59 if (!strcmp(key, "flags")) {
60 lua_pushinteger(L, to->flags);
61
62 return 1;
63 } else if (!strcmp(key, "expires")) {
64 lua_pushinteger(L, to->expires);
65
66 return 1;
67 }
68 }
69
70 if (LUA_TNIL != lua_getuservalue(L, 1)) {
71 lua_pushvalue(L, 2);
72 if (LUA_TNIL != lua_rawget(L, -2))
73 return 1;
74 }
75
76 lua_pushvalue(L, 2);
77 if (LUA_TNIL != lua_rawget(L, lua_upvalueindex(1)))
78 return 1;
79
80 return 0;
81}
82
83static int
84to__newindex(lua_State *L)
85{
86 if (LUA_TNIL == lua_getuservalue(L, 1)) {
87 lua_newtable(L);
88 lua_pushvalue(L, -1);
89 lua_setuservalue(L, 1);
90 }
91
92 lua_pushvalue(L, 2);
93 lua_pushvalue(L, 3);
94 lua_rawset(L, -3);
95
96 return 0;
97}
98
99static int
100to__gc(lua_State *L)
101{
102 struct timeout *to = to_checkudata(L, 1);
103
104 /*
105 * NB: On script exit it's possible for a timeout to still be
106 * associated with a timeouts object, particularly when the timeouts
107 * object was created first.
108 */
109 timeout_del(to);
110
111 return 0;
112}
113
114static int
115to_new(lua_State *L)
116{
117 int flags = luaL_optinteger(L, 1, 0);
118 struct timeout *to;
119
120 to = lua_newuserdata(L, sizeof *to);
121 timeout_init(to, flags);
122 luaL_setmetatable(L, TIMEOUT_METANAME);
123
124 return 1;
125}
126
127static const luaL_Reg to_methods[] = {
128 { NULL, NULL },
129};
130
131static const luaL_Reg to_metatable[] = {
132 { "__index", &to__index },
133 { "__newindex", &to__newindex },
134 { "__gc", &to__gc },
135 { NULL, NULL },
136};
137
138static const luaL_Reg to_globals[] = {
139 { "new", &to_new },
140 { NULL, NULL },
141};
142
143static void
144to_newmetatable(lua_State *L)
145{
146 if (luaL_newmetatable(L, TIMEOUT_METANAME)) {
147 /*
148 * fill metamethod table, capturing the methods table as an
149 * upvalue for use by __index metamethod
150 */
151 luaL_newlib(L, to_methods);
152 luaL_setfuncs(L, to_metatable, 1);
153 }
154}
155
156int
157luaopen_timeout(lua_State *L)
158{
159 to_newmetatable(L);
160
161 luaL_newlib(L, to_globals);
162 lua_pushinteger(L, TIMEOUT_INT);
163 lua_setfield(L, -2, "INT");
164 lua_pushinteger(L, TIMEOUT_ABS);
165 lua_setfield(L, -2, "ABS");
166
167 return 1;
168}
169
170static int
171tos_update(lua_State *L)
172{
173 struct timeouts *T = tos_checkudata(L, 1);
174 lua_Number n = luaL_checknumber(L, 2);
175
176 timeouts_update(T, timeouts_f2i(T, n));
177
178 lua_pushvalue(L, 1);
179
180 return 1;
181}
182
183static int
184tos_step(lua_State *L)
185{
186 struct timeouts *T = tos_checkudata(L, 1);
187 lua_Number n = luaL_checknumber(L, 2);
188
189 timeouts_step(T, timeouts_f2i(T, n));
190
191 lua_pushvalue(L, 1);
192
193 return 1;
194}
195
196static int
197tos_timeout(lua_State *L)
198{
199 struct timeouts *T = tos_checkudata(L, 1);
200
201 lua_pushnumber(L, timeouts_i2f(T, timeouts_timeout(T)));
202
203 return 1;
204}
205
206static int
207tos_add(lua_State *L)
208{
209 struct timeouts *T = tos_checkudata(L, 1);
210 struct timeout *to = to_checkudata(L, 2);
211 lua_Number timeout = luaL_checknumber(L, 3);
212
213 tos_bind(L, 1, 2);
214 timeouts_addf(T, to, timeout);
215
216 return lua_pushvalue(L, 1), 1;
217}
218
219static int
220tos_del(lua_State *L)
221{
222 struct timeouts *T = tos_checkudata(L, 1);
223 struct timeout *to = to_checkudata(L, 2);
224
225 timeouts_del(T, to);
226 tos_unbind(L, 1, 2);
227
228 return lua_pushvalue(L, 1), 1;
229}
230
231static int
232tos_get(lua_State *L)
233{
234 struct timeouts *T = tos_checkudata(L, 1);
235 struct timeout *to;
236
237 if (!(to = timeouts_get(T)))
238 return 0;
239
240 lua_getuservalue(L, 1);
241 lua_rawgetp(L, -1, to);
242
243 if (!timeout_pending(to))
244 tos_unbind(L, 1, lua_absindex(L, -1));
245
246 return 1;
247}
248
249static int
250tos_pending(lua_State *L)
251{
252 struct timeouts *T = tos_checkudata(L, 1);
253
254 lua_pushboolean(L, timeouts_pending(T));
255
256 return 1;
257}
258
259static int
260tos_expired(lua_State *L)
261{
262 struct timeouts *T = tos_checkudata(L, 1);
263
264 lua_pushboolean(L, timeouts_expired(T));
265
266 return 1;
267}
268
269static int
270tos_check(lua_State *L)
271{
272 struct timeouts *T = tos_checkudata(L, 1);
273
274 lua_pushboolean(L, timeouts_check(T, NULL));
275
276 return 1;
277}
278
279static int
280tos__next(lua_State *L)
281{
282 struct timeouts *T = tos_checkudata(L, lua_upvalueindex(1));
283 struct timeouts_it *it = lua_touserdata(L, lua_upvalueindex(2));
284 struct timeout *to;
285
286 if (!(to = timeouts_next(T, it)))
287 return 0;
288
289 lua_getuservalue(L, lua_upvalueindex(1));
290 lua_rawgetp(L, -1, to);
291
292 return 1;
293}
294
295static int
296tos_timeouts(lua_State *L)
297{
298 int flags = luaL_checkinteger(L, 2);
299 struct timeouts_it *it;
300
301 tos_checkudata(L, 1);
302 lua_pushvalue(L, 1);
303 it = lua_newuserdata(L, sizeof *it);
304 TIMEOUTS_IT_INIT(it, flags);
305 lua_pushcclosure(L, &tos__next, 2);
306
307 return 1;
308}
309
310static int
311tos__gc(lua_State *L)
312{
313 struct timeouts **tos = luaL_checkudata(L, 1, TIMEOUTS_METANAME);
314 struct timeout *to;
315
316 TIMEOUTS_FOREACH(to, *tos, TIMEOUTS_ALL) {
317 timeouts_del(*tos, to);
318 }
319
320 timeouts_close(*tos);
321 *tos = NULL;
322
323 return 0;
324}
325
326static int
327tos_new(lua_State *L)
328{
329 timeout_t hz = luaL_optinteger(L, 1, 0);
330 struct timeouts **T;
331 int error;
332
333 T = lua_newuserdata(L, sizeof *T);
334 luaL_setmetatable(L, TIMEOUTS_METANAME);
335
336 lua_newtable(L);
337 lua_setuservalue(L, -2);
338
339 if (!(*T = timeouts_open(hz, &error)))
340 return luaL_error(L, "%s", strerror(error));
341
342 return 1;
343}
344
345static const luaL_Reg tos_methods[] = {
346 { "update", &tos_update },
347 { "step", &tos_step },
348 { "timeout", &tos_timeout },
349 { "add", &tos_add },
350 { "del", &tos_del },
351 { "get", &tos_get },
352 { "pending", &tos_pending },
353 { "expired", &tos_expired },
354 { "check", &tos_check },
355 { "timeouts", &tos_timeouts },
356 { NULL, NULL },
357};
358
359static const luaL_Reg tos_metatable[] = {
360 { "__gc", &tos__gc },
361 { NULL, NULL },
362};
363
364static const luaL_Reg tos_globals[] = {
365 { "new", &tos_new },
366 { NULL, NULL },
367};
368
369static void
370tos_newmetatable(lua_State *L)
371{
372 if (luaL_newmetatable(L, TIMEOUTS_METANAME)) {
373 luaL_setfuncs(L, tos_metatable, 0);
374 luaL_newlib(L, tos_methods);
375 lua_setfield(L, -2, "__index");
376 }
377}
378
379int
380luaopen_timeouts(lua_State *L)
381{
382 to_newmetatable(L);
383 tos_newmetatable(L);
384
385 luaL_newlib(L, tos_globals);
386 lua_pushinteger(L, TIMEOUTS_PENDING);
387 lua_setfield(L, -2, "PENDING");
388 lua_pushinteger(L, TIMEOUTS_EXPIRED);
389 lua_setfield(L, -2, "EXPIRED");
390 lua_pushinteger(L, TIMEOUTS_ALL);
391 lua_setfield(L, -2, "ALL");
392 lua_pushinteger(L, TIMEOUTS_CLEAR);
393 lua_setfield(L, -2, "CLEAR");
394
395 return 1;
396}
#define T(s, t, a, o)
Definition: parsecommon.h:247