Sun, 10 Jun 2007 16:01:26 +0000
Initial commit:
* Created tree structure
* Committed current version
0 | 1 | #include "luaevent.h" |
2 | ||
3 | #include <lua.h> | |
4 | #include <lauxlib.h> | |
5 | ||
6 | #define EVENT_BASE_MT "EVENT_BASE_MT" | |
7 | #define EVENT_CALLBACK_ARG_MT "EVENT_CALLBACK_ARG_MT" | |
8 | #define EVENT_BASE_LOCATION 1 | |
9 | ||
10 | void setEventBase(lua_State* L, struct event_base* base) { | |
11 | struct event_base** pbase = lua_newuserdata(L, sizeof(base)); | |
12 | *pbase = base; | |
13 | luaL_getmetatable(L, EVENT_BASE_MT); | |
14 | lua_setmetatable(L, -2); | |
15 | lua_rawseti(L, LUA_ENVIRONINDEX, EVENT_BASE_LOCATION); | |
16 | } | |
17 | struct event_base* getEventBase(lua_State* L) { | |
18 | struct event_base* base; | |
19 | lua_rawgeti(L, LUA_ENVIRONINDEX, EVENT_BASE_LOCATION); | |
20 | base = *(struct event_base**)lua_topointer(L, -1); | |
21 | lua_pop(L, 1); | |
22 | return base; | |
23 | } | |
24 | ||
25 | void freeCallbackArgs(le_callback* arg) { | |
26 | if(arg->L) { | |
27 | lua_State* L = arg->L; | |
28 | arg->L = NULL; | |
29 | event_del(&arg->ev); | |
30 | luaL_unref(L, LUA_REGISTRYINDEX, arg->callbackRef); | |
31 | } | |
32 | } | |
33 | /* le_callback is allocated at the beginning of the coroutine in which it | |
34 | is used, no need to manually de-allocate */ | |
35 | ||
36 | /* Index for coroutine is fd as integer for *nix, as lightuserdata for Win */ | |
37 | static void luaevent_callback(int fd, short event, void* p) { | |
38 | le_callback* arg = p; | |
39 | lua_State* L = arg->L; | |
40 | int ret; | |
41 | lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callbackRef); | |
42 | lua_pushinteger(L, event); | |
43 | lua_call(L, 1, 1); | |
44 | ret = lua_tointeger(L, -1); | |
45 | lua_pop(L, 1); | |
46 | if(ret == -1) { | |
47 | freeCallbackArgs(arg); | |
48 | } else { | |
49 | struct event *ev = &arg->ev; | |
50 | int newEvent = ret; | |
51 | if(newEvent != event) { // Need to hook up new event... | |
52 | event_del(ev); | |
53 | event_set(ev, fd, EV_PERSIST | newEvent, luaevent_callback, arg); | |
54 | event_add(ev, NULL); | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
59 | static int luaevent_base_gc(lua_State* L) { | |
60 | struct event_base** pbase = luaL_checkudata(L, 1, EVENT_BASE_MT); | |
61 | if(*pbase) { | |
62 | event_base_free(*pbase); | |
63 | *pbase = NULL; | |
64 | } | |
65 | return 0; | |
66 | } | |
67 | ||
68 | static int luaevent_cb_gc(lua_State* L) { | |
69 | le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT); | |
70 | freeCallbackArgs(arg); | |
71 | return 0; | |
72 | } | |
73 | ||
74 | int getSocketFd(lua_State* L, int idx) { | |
75 | int fd; | |
76 | luaL_checktype(L, idx, LUA_TUSERDATA); | |
77 | lua_getfield(L, idx, "getfd"); | |
78 | if(lua_isnil(L, -1)) | |
79 | return luaL_error(L, "Socket type missing 'getfd' method"); | |
80 | lua_pushvalue(L, idx); | |
81 | lua_call(L, 1, 1); | |
82 | fd = lua_tointeger(L, -1); | |
83 | lua_pop(L, 1); | |
84 | return fd; | |
85 | } | |
86 | ||
87 | /* Expected to be called at the beginning of the coro that uses it.. | |
88 | Value must be kept until coro is complete.... | |
89 | */ | |
90 | /* sock, event, callback */ | |
91 | static int luaevent_addevent(lua_State* L) { | |
92 | int fd, event, callbackRef; | |
93 | le_callback* arg; | |
94 | fd = getSocketFd(L, 1); | |
95 | event = luaL_checkinteger(L, 2); | |
96 | luaL_checktype(L, 3, LUA_TFUNCTION); | |
97 | lua_pushvalue(L, 3); | |
98 | callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); | |
99 | arg = lua_newuserdata(L, sizeof(*arg)); | |
100 | luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT); | |
101 | lua_setmetatable(L, -2); | |
102 | ||
103 | arg->L = L; | |
104 | arg->callbackRef = callbackRef; | |
105 | /* Setup event... */ | |
106 | event_set(&arg->ev, fd, event | EV_PERSIST, luaevent_callback, arg); | |
107 | event_base_set(getEventBase(L), &arg->ev); | |
108 | event_add(&arg->ev, NULL); | |
109 | return 1; | |
110 | } | |
111 | ||
112 | static int luaevent_loop(lua_State* L) { | |
113 | int ret = event_base_loop(getEventBase(L), 0); | |
114 | lua_pushinteger(L, ret); | |
115 | return 1; | |
116 | } | |
117 | ||
118 | static luaL_Reg funcs[] = { | |
119 | { "addevent", luaevent_addevent }, | |
120 | { "loop", luaevent_loop }, | |
121 | { NULL, NULL } | |
122 | }; | |
123 | ||
124 | typedef struct { | |
125 | const char* name; | |
126 | int value; | |
127 | } namedInteger; | |
128 | ||
129 | static namedInteger consts[] = { | |
130 | {"LEAVE", -1}, | |
131 | {"EV_READ", EV_READ}, | |
132 | {"EV_WRITE", EV_WRITE}, | |
133 | {NULL, 0} | |
134 | }; | |
135 | ||
136 | void setNamedIntegers(lua_State* L, namedInteger* p) { | |
137 | while(p->name) { | |
138 | lua_pushinteger(L, p->value); | |
139 | lua_setfield(L, -2, p->name); | |
140 | p++; | |
141 | } | |
142 | } | |
143 | ||
144 | /* Verified ok */ | |
145 | int luaopen_luaevent_core(lua_State* L) { | |
146 | /* Setup environ table */ | |
147 | lua_createtable(L, 1, 0); | |
148 | lua_replace(L, LUA_ENVIRONINDEX); | |
149 | /* Setup metatable */ | |
150 | luaL_newmetatable(L, EVENT_BASE_MT); | |
151 | lua_pushcfunction(L, luaevent_base_gc); | |
152 | lua_setfield(L, -2, "__gc"); | |
153 | lua_pop(L, 1); | |
154 | luaL_newmetatable(L, EVENT_CALLBACK_ARG_MT); | |
155 | lua_pushcfunction(L, luaevent_cb_gc); | |
156 | lua_setfield(L, -2, "__gc"); | |
157 | lua_pop(L, 1); | |
158 | ||
159 | setEventBase(L, event_init()); | |
160 | ||
161 | luaL_register(L, "luaevent.core", funcs); | |
162 | setNamedIntegers(L, consts); | |
163 | return 1; | |
164 | } |