1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/* LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com>
* Licensed as LGPL - See doc/COPYING for details */
#include "event_callback.h"
#include <assert.h>
#include <lauxlib.h>
#include <string.h>
#define EVENT_CALLBACK_ARG_MT "EVENT_CALLBACK_ARG_MT"
void freeCallbackArgs(le_callback* arg, lua_State* L) {
if(arg->base) {
arg->base = NULL;
event_del(&arg->ev);
luaL_unref(L, LUA_REGISTRYINDEX, arg->callbackRef);
}
}
/* le_callback is allocated at the beginning of the coroutine in which it
is used, no need to manually de-allocate */
/* Index for coroutine is fd as integer for *nix, as lightuserdata for Win */
void luaevent_callback(int fd, short event, void* p) {
le_callback* cb = p;
lua_State* L;
int ret;
double newTimeout = -1;
assert(cb);
if(!cb->base) {
/* Callback has been collected... die */
/* TODO: What should really be done here... */
return;
}
assert(cb->base->loop_L);
L = cb->base->loop_L;
lua_rawgeti(L, LUA_REGISTRYINDEX, cb->callbackRef);
lua_pushinteger(L, event);
lua_call(L, 1, 2);
ret = lua_tointeger(L, -2);
if(lua_isnumber(L, -1)) {
newTimeout = lua_tonumber(L, -1);
if(newTimeout <= 0) {
memset(&cb->timeout, 0, sizeof(cb->timeout));
} else {
load_timeval(newTimeout, &cb->timeout);
}
}
lua_pop(L, 1);
if(ret == -1) {
freeCallbackArgs(cb, L);
} else {
struct event *ev = &cb->ev;
int newEvent = ret;
/* NOTE: Currently, even if new timeout is the same as the old, a new event is setup regardless... */
if(newEvent != event || newTimeout != -1) { // Need to hook up new event...
struct timeval *ptv = &cb->timeout;
if(!cb->timeout.tv_sec && !cb->timeout.tv_usec)
ptv = NULL;
event_del(ev);
event_set(ev, fd, EV_PERSIST | newEvent, luaevent_callback, cb);
/* Assume cannot set a new timeout.. */
event_add(ev, ptv);
}
}
}
static int luaevent_cb_gc(lua_State* L) {
le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT);
freeCallbackArgs(arg, L);
return 0;
}
le_callback* event_callback_push(lua_State* L, int baseIdx, int callbackIdx) {
le_callback* cb;
le_base *base = event_base_get(L, baseIdx);
luaL_checktype(L, callbackIdx, LUA_TFUNCTION);
cb = lua_newuserdata(L, sizeof(*cb));
luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT);
lua_setmetatable(L, -2);
lua_pushvalue(L, callbackIdx);
cb->callbackRef = luaL_ref(L, LUA_REGISTRYINDEX);
cb->base = base;
memset(&cb->timeout, 0, sizeof(cb->timeout));
return cb;
}
int event_callback_register(lua_State* L) {
luaL_newmetatable(L, EVENT_CALLBACK_ARG_MT);
lua_pushcfunction(L, luaevent_cb_gc);
lua_setfield(L, -2, "__gc");
lua_newtable(L);
lua_pushcfunction(L, luaevent_cb_gc);
lua_setfield(L, -2, "close");
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
return 0;
}
|