Wed, 13 Jun 2007 04:32:12 +0000
Setup management of socket create/close.
Recognized new bug: cannot create threads within threads... C contains reference to closed thread, not
global.
1
31c782cfe7fe
* Adjusted licensing and added README.
Thomas Harning Jr <harningt@gmail.com>
parents:
0
diff
changeset
|
1 | /* LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com> |
31c782cfe7fe
* Adjusted licensing and added README.
Thomas Harning Jr <harningt@gmail.com>
parents:
0
diff
changeset
|
2 | * Licensed as LGPL - See doc/COPYING for details */ |
31c782cfe7fe
* Adjusted licensing and added README.
Thomas Harning Jr <harningt@gmail.com>
parents:
0
diff
changeset
|
3 | |
0 | 4 | #include "luaevent.h" |
5 | ||
6 | #include <lua.h> | |
7 | #include <lauxlib.h> | |
8 | ||
9 | #define EVENT_BASE_MT "EVENT_BASE_MT" | |
10 | #define EVENT_CALLBACK_ARG_MT "EVENT_CALLBACK_ARG_MT" | |
11 | #define EVENT_BASE_LOCATION 1 | |
12 | ||
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
13 | static void setEventBase(lua_State* L, struct event_base* base) { |
0 | 14 | struct event_base** pbase = lua_newuserdata(L, sizeof(base)); |
15 | *pbase = base; | |
16 | luaL_getmetatable(L, EVENT_BASE_MT); | |
17 | lua_setmetatable(L, -2); | |
18 | lua_rawseti(L, LUA_ENVIRONINDEX, EVENT_BASE_LOCATION); | |
19 | } | |
20 | struct event_base* getEventBase(lua_State* L) { | |
21 | struct event_base* base; | |
22 | lua_rawgeti(L, LUA_ENVIRONINDEX, EVENT_BASE_LOCATION); | |
23 | base = *(struct event_base**)lua_topointer(L, -1); | |
24 | lua_pop(L, 1); | |
25 | return base; | |
26 | } | |
27 | ||
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
28 | static void freeCallbackArgs(le_callback* arg) { |
0 | 29 | if(arg->L) { |
30 | lua_State* L = arg->L; | |
31 | arg->L = NULL; | |
32 | event_del(&arg->ev); | |
33 | luaL_unref(L, LUA_REGISTRYINDEX, arg->callbackRef); | |
10
88ce07d62597
Setup management of socket create/close.
Thomas Harning Jr <harningt@gmail.com>
parents:
9
diff
changeset
|
34 | luaL_unref(L, LUA_REGISTRYINDEX, arg->objectRef); |
0 | 35 | } |
36 | } | |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
37 | |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
38 | static int call_callback_function(lua_State* L, int argCount) { |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
39 | int ret; |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
40 | if(lua_pcall(L, argCount, 1, 0) || !(lua_isnil(L, -1) || lua_isnumber(L, -1))) { |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
41 | printf("ERROR IN INIT: %s\n", lua_tostring(L, -1)); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
42 | lua_pop(L, 1); |
9
1f3b72ba96c9
Fixed up return-value handling.
Thomas Harning Jr <harningt@gmail.com>
parents:
8
diff
changeset
|
43 | return -1; |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
44 | } |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
45 | /* Lua_isnil returns 1 if the value is nil... */ |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
46 | ret = lua_tointeger(L, -1) | -lua_isnil(L, -1); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
47 | lua_pop(L, 1); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
48 | if(ret < 0) { /* Done, no need to setup event */ |
9
1f3b72ba96c9
Fixed up return-value handling.
Thomas Harning Jr <harningt@gmail.com>
parents:
8
diff
changeset
|
49 | return -1; |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
50 | } |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
51 | if(ret != EV_READ && ret != EV_WRITE) { |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
52 | printf("BAD RET_VAL IN INIT: %i\n", ret); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
53 | } |
9
1f3b72ba96c9
Fixed up return-value handling.
Thomas Harning Jr <harningt@gmail.com>
parents:
8
diff
changeset
|
54 | return ret; |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
55 | } |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
56 | |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
57 | static void luaevent_callback(int fd, short event, void* p); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
58 | |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
59 | static void setup_event(le_callback* arg, int fd, short event, int resetEvent) { |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
60 | /* Setup event... */ |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
61 | if(resetEvent) event_del(&arg->ev); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
62 | event_set(&arg->ev, fd, event| EV_PERSIST, luaevent_callback, arg); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
63 | if(!resetEvent) event_base_set(getEventBase(arg->L), &arg->ev); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
64 | event_add(&arg->ev, NULL); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
65 | } |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
66 | |
0 | 67 | /* le_callback is allocated at the beginning of the coroutine in which it |
68 | is used, no need to manually de-allocate */ | |
69 | ||
70 | /* Index for coroutine is fd as integer for *nix, as lightuserdata for Win */ | |
71 | static void luaevent_callback(int fd, short event, void* p) { | |
72 | le_callback* arg = p; | |
73 | lua_State* L = arg->L; | |
74 | int ret; | |
75 | lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callbackRef); | |
76 | lua_pushinteger(L, event); | |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
77 | |
9
1f3b72ba96c9
Fixed up return-value handling.
Thomas Harning Jr <harningt@gmail.com>
parents:
8
diff
changeset
|
78 | if(-1 == (ret = call_callback_function(L, 1))) { |
0 | 79 | freeCallbackArgs(arg); |
3
5999243fab1d
* Added some cheap protection code for failures in callback
Thomas Harning Jr <harningt@gmail.com>
parents:
2
diff
changeset
|
80 | return; |
5999243fab1d
* Added some cheap protection code for failures in callback
Thomas Harning Jr <harningt@gmail.com>
parents:
2
diff
changeset
|
81 | } |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
82 | |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
83 | if(event != ret) |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
84 | setup_event(arg, fd, ret, 1); |
0 | 85 | } |
86 | ||
87 | static int luaevent_base_gc(lua_State* L) { | |
88 | struct event_base** pbase = luaL_checkudata(L, 1, EVENT_BASE_MT); | |
89 | if(*pbase) { | |
90 | event_base_free(*pbase); | |
91 | *pbase = NULL; | |
92 | } | |
93 | return 0; | |
94 | } | |
95 | ||
96 | static int luaevent_cb_gc(lua_State* L) { | |
97 | le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT); | |
98 | freeCallbackArgs(arg); | |
99 | return 0; | |
100 | } | |
101 | ||
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
102 | static int luaevent_cb_getfd(lua_State* L) { |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
103 | le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT); |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
104 | lua_pushinteger(L, arg->ev.ev_fd); |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
105 | return 1; |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
106 | } |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
107 | |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
108 | static int getSocketFd(lua_State* L, int idx) { |
0 | 109 | int fd; |
110 | luaL_checktype(L, idx, LUA_TUSERDATA); | |
111 | lua_getfield(L, idx, "getfd"); | |
112 | if(lua_isnil(L, -1)) | |
113 | return luaL_error(L, "Socket type missing 'getfd' method"); | |
114 | lua_pushvalue(L, idx); | |
115 | lua_call(L, 1, 1); | |
116 | fd = lua_tointeger(L, -1); | |
117 | lua_pop(L, 1); | |
118 | return fd; | |
119 | } | |
120 | ||
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
121 | static void push_new_callback(lua_State* L, int callbackRef, int fd, short event) { |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
122 | le_callback* arg = lua_newuserdata(L, sizeof(*arg)); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
123 | luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
124 | lua_setmetatable(L, -2); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
125 | |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
126 | arg->L = L; |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
127 | arg->callbackRef = callbackRef; |
10
88ce07d62597
Setup management of socket create/close.
Thomas Harning Jr <harningt@gmail.com>
parents:
9
diff
changeset
|
128 | lua_pushvalue(L, -1); |
88ce07d62597
Setup management of socket create/close.
Thomas Harning Jr <harningt@gmail.com>
parents:
9
diff
changeset
|
129 | arg->objectRef = luaL_ref(L, LUA_REGISTRYINDEX); |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
130 | setup_event(arg, fd, event, 0); |
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
131 | } |
0 | 132 | /* Expected to be called at the beginning of the coro that uses it.. |
133 | Value must be kept until coro is complete.... | |
134 | */ | |
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
135 | /* sock, callback */ |
0 | 136 | static int luaevent_addevent(lua_State* L) { |
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
137 | int fd, callbackRef; |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
138 | int top, ret; |
0 | 139 | fd = getSocketFd(L, 1); |
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
140 | luaL_checktype(L, 2, LUA_TFUNCTION); |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
141 | top = lua_gettop(L); |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
142 | /* Preserve the callback function */ |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
143 | lua_pushvalue(L, 2); |
0 | 144 | callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); |
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
145 | /* Call the callback with all arguments after it to get the loop primed.. */ |
9
1f3b72ba96c9
Fixed up return-value handling.
Thomas Harning Jr <harningt@gmail.com>
parents:
8
diff
changeset
|
146 | if(-1 == (ret = call_callback_function(L, top - 2))) { |
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
147 | luaL_unref(L, LUA_REGISTRYINDEX, callbackRef); |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
148 | return 0; |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
149 | } |
0 | 150 | |
8
b134613f6303
Performed some refactoring...
Thomas Harning Jr <harningt@gmail.com>
parents:
7
diff
changeset
|
151 | push_new_callback(L, callbackRef, fd, ret); |
0 | 152 | return 1; |
153 | } | |
154 | ||
155 | static int luaevent_loop(lua_State* L) { | |
156 | int ret = event_base_loop(getEventBase(L), 0); | |
157 | lua_pushinteger(L, ret); | |
158 | return 1; | |
159 | } | |
160 | ||
161 | static luaL_Reg funcs[] = { | |
162 | { "addevent", luaevent_addevent }, | |
163 | { "loop", luaevent_loop }, | |
164 | { NULL, NULL } | |
165 | }; | |
166 | ||
167 | typedef struct { | |
168 | const char* name; | |
169 | int value; | |
170 | } namedInteger; | |
171 | ||
172 | static namedInteger consts[] = { | |
173 | {"LEAVE", -1}, | |
174 | {"EV_READ", EV_READ}, | |
175 | {"EV_WRITE", EV_WRITE}, | |
176 | {NULL, 0} | |
177 | }; | |
178 | ||
179 | void setNamedIntegers(lua_State* L, namedInteger* p) { | |
180 | while(p->name) { | |
181 | lua_pushinteger(L, p->value); | |
182 | lua_setfield(L, -2, p->name); | |
183 | p++; | |
184 | } | |
185 | } | |
186 | ||
187 | /* Verified ok */ | |
188 | int luaopen_luaevent_core(lua_State* L) { | |
189 | /* Setup environ table */ | |
190 | lua_createtable(L, 1, 0); | |
191 | lua_replace(L, LUA_ENVIRONINDEX); | |
192 | /* Setup metatable */ | |
193 | luaL_newmetatable(L, EVENT_BASE_MT); | |
194 | lua_pushcfunction(L, luaevent_base_gc); | |
195 | lua_setfield(L, -2, "__gc"); | |
196 | lua_pop(L, 1); | |
197 | luaL_newmetatable(L, EVENT_CALLBACK_ARG_MT); | |
198 | lua_pushcfunction(L, luaevent_cb_gc); | |
199 | lua_setfield(L, -2, "__gc"); | |
2
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
200 | lua_pushcfunction(L, luaevent_cb_getfd); |
01b3a96ae760
* Completed mostly working version
Thomas Harning Jr <harningt@gmail.com>
parents:
1
diff
changeset
|
201 | lua_setfield(L, -2, "getfd"); |
0 | 202 | lua_pop(L, 1); |
203 | ||
204 | setEventBase(L, event_init()); | |
205 | ||
206 | luaL_register(L, "luaevent.core", funcs); | |
207 | setNamedIntegers(L, consts); | |
208 | return 1; | |
209 | } |