8 |
8 |
9 #define EVENT_BASE_MT "EVENT_BASE_MT" |
9 #define EVENT_BASE_MT "EVENT_BASE_MT" |
10 #define EVENT_CALLBACK_ARG_MT "EVENT_CALLBACK_ARG_MT" |
10 #define EVENT_CALLBACK_ARG_MT "EVENT_CALLBACK_ARG_MT" |
11 #define EVENT_BASE_LOCATION 1 |
11 #define EVENT_BASE_LOCATION 1 |
12 |
12 |
13 void setEventBase(lua_State* L, struct event_base* base) { |
13 static void setEventBase(lua_State* L, struct event_base* base) { |
14 struct event_base** pbase = lua_newuserdata(L, sizeof(base)); |
14 struct event_base** pbase = lua_newuserdata(L, sizeof(base)); |
15 *pbase = base; |
15 *pbase = base; |
16 luaL_getmetatable(L, EVENT_BASE_MT); |
16 luaL_getmetatable(L, EVENT_BASE_MT); |
17 lua_setmetatable(L, -2); |
17 lua_setmetatable(L, -2); |
18 lua_rawseti(L, LUA_ENVIRONINDEX, EVENT_BASE_LOCATION); |
18 lua_rawseti(L, LUA_ENVIRONINDEX, EVENT_BASE_LOCATION); |
23 base = *(struct event_base**)lua_topointer(L, -1); |
23 base = *(struct event_base**)lua_topointer(L, -1); |
24 lua_pop(L, 1); |
24 lua_pop(L, 1); |
25 return base; |
25 return base; |
26 } |
26 } |
27 |
27 |
28 void freeCallbackArgs(le_callback* arg) { |
28 static void freeCallbackArgs(le_callback* arg) { |
29 if(arg->L) { |
29 if(arg->L) { |
30 lua_State* L = arg->L; |
30 lua_State* L = arg->L; |
31 arg->L = NULL; |
31 arg->L = NULL; |
32 event_del(&arg->ev); |
32 event_del(&arg->ev); |
33 luaL_unref(L, LUA_REGISTRYINDEX, arg->callbackRef); |
33 luaL_unref(L, LUA_REGISTRYINDEX, arg->callbackRef); |
34 } |
34 } |
35 } |
35 } |
|
36 |
|
37 static int call_callback_function(lua_State* L, int argCount) { |
|
38 int ret; |
|
39 if(lua_pcall(L, argCount, 1, 0) || !(lua_isnil(L, -1) || lua_isnumber(L, -1))) { |
|
40 printf("ERROR IN INIT: %s\n", lua_tostring(L, -1)); |
|
41 lua_pop(L, 1); |
|
42 return 0; |
|
43 } |
|
44 /* Lua_isnil returns 1 if the value is nil... */ |
|
45 ret = lua_tointeger(L, -1) | -lua_isnil(L, -1); |
|
46 lua_pop(L, 1); |
|
47 if(ret < 0) { /* Done, no need to setup event */ |
|
48 return 0; |
|
49 } |
|
50 if(ret != EV_READ && ret != EV_WRITE) { |
|
51 printf("BAD RET_VAL IN INIT: %i\n", ret); |
|
52 } |
|
53 return 1; |
|
54 } |
|
55 |
|
56 static void luaevent_callback(int fd, short event, void* p); |
|
57 |
|
58 static void setup_event(le_callback* arg, int fd, short event, int resetEvent) { |
|
59 /* Setup event... */ |
|
60 if(resetEvent) event_del(&arg->ev); |
|
61 event_set(&arg->ev, fd, event| EV_PERSIST, luaevent_callback, arg); |
|
62 if(!resetEvent) event_base_set(getEventBase(arg->L), &arg->ev); |
|
63 event_add(&arg->ev, NULL); |
|
64 } |
|
65 |
36 /* le_callback is allocated at the beginning of the coroutine in which it |
66 /* le_callback is allocated at the beginning of the coroutine in which it |
37 is used, no need to manually de-allocate */ |
67 is used, no need to manually de-allocate */ |
38 |
68 |
39 /* Index for coroutine is fd as integer for *nix, as lightuserdata for Win */ |
69 /* Index for coroutine is fd as integer for *nix, as lightuserdata for Win */ |
40 static void luaevent_callback(int fd, short event, void* p) { |
70 static void luaevent_callback(int fd, short event, void* p) { |
41 le_callback* arg = p; |
71 le_callback* arg = p; |
42 lua_State* L = arg->L; |
72 lua_State* L = arg->L; |
43 int ret; |
73 int ret; |
44 lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callbackRef); |
74 lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callbackRef); |
45 lua_pushinteger(L, event); |
75 lua_pushinteger(L, event); |
46 if(lua_pcall(L, 1, 1, 0) || !(lua_isnil(L, -1) || lua_isnumber(L, -1))) { |
76 |
47 printf("ERROR IN CB: %s\n", lua_tostring(L, -1)); |
77 if(0 == call_callback_function(L, 1)) { |
48 lua_pop(L, 1); |
|
49 freeCallbackArgs(arg); |
78 freeCallbackArgs(arg); |
50 return; |
79 return; |
51 } |
80 } |
52 ret = lua_tointeger(L, -1) | -1lua_isnil(L, -1); |
81 |
53 lua_pop(L, 1); |
|
54 if(ret < 0) { |
|
55 freeCallbackArgs(arg); |
|
56 return; |
|
57 } |
|
58 if(ret != EV_READ && ret != EV_WRITE) { |
|
59 printf("BAD RET_VAL: %i\n", ret); |
|
60 } |
|
61 printf("RET VAL: %i\n", ret); |
82 printf("RET VAL: %i\n", ret); |
62 struct event *ev = &arg->ev; |
83 if(event != ret) |
63 int newEvent = ret; |
84 setup_event(arg, fd, ret, 1); |
64 if(newEvent != event) { // Need to hook up new event... |
|
65 event_del(ev); |
|
66 event_set(ev, fd, EV_PERSIST | newEvent, luaevent_callback, arg); |
|
67 event_add(ev, NULL); |
|
68 } |
|
69 } |
85 } |
70 |
86 |
71 static int luaevent_base_gc(lua_State* L) { |
87 static int luaevent_base_gc(lua_State* L) { |
72 struct event_base** pbase = luaL_checkudata(L, 1, EVENT_BASE_MT); |
88 struct event_base** pbase = luaL_checkudata(L, 1, EVENT_BASE_MT); |
73 if(*pbase) { |
89 if(*pbase) { |
87 le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT); |
103 le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT); |
88 lua_pushinteger(L, arg->ev.ev_fd); |
104 lua_pushinteger(L, arg->ev.ev_fd); |
89 return 1; |
105 return 1; |
90 } |
106 } |
91 |
107 |
92 int getSocketFd(lua_State* L, int idx) { |
108 static int getSocketFd(lua_State* L, int idx) { |
93 int fd; |
109 int fd; |
94 luaL_checktype(L, idx, LUA_TUSERDATA); |
110 luaL_checktype(L, idx, LUA_TUSERDATA); |
95 lua_getfield(L, idx, "getfd"); |
111 lua_getfield(L, idx, "getfd"); |
96 if(lua_isnil(L, -1)) |
112 if(lua_isnil(L, -1)) |
97 return luaL_error(L, "Socket type missing 'getfd' method"); |
113 return luaL_error(L, "Socket type missing 'getfd' method"); |
100 fd = lua_tointeger(L, -1); |
116 fd = lua_tointeger(L, -1); |
101 lua_pop(L, 1); |
117 lua_pop(L, 1); |
102 return fd; |
118 return fd; |
103 } |
119 } |
104 |
120 |
|
121 static void push_new_callback(lua_State* L, int callbackRef, int fd, short event) { |
|
122 le_callback* arg = lua_newuserdata(L, sizeof(*arg)); |
|
123 luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT); |
|
124 lua_setmetatable(L, -2); |
|
125 |
|
126 arg->L = L; |
|
127 arg->callbackRef = callbackRef; |
|
128 |
|
129 setup_event(arg, fd, event, 0); |
|
130 } |
105 /* Expected to be called at the beginning of the coro that uses it.. |
131 /* Expected to be called at the beginning of the coro that uses it.. |
106 Value must be kept until coro is complete.... |
132 Value must be kept until coro is complete.... |
107 */ |
133 */ |
108 /* sock, callback */ |
134 /* sock, callback */ |
109 static int luaevent_addevent(lua_State* L) { |
135 static int luaevent_addevent(lua_State* L) { |
110 int fd, callbackRef; |
136 int fd, callbackRef; |
111 int top, ret; |
137 int top, ret; |
112 le_callback* arg; |
|
113 fd = getSocketFd(L, 1); |
138 fd = getSocketFd(L, 1); |
114 luaL_checktype(L, 2, LUA_TFUNCTION); |
139 luaL_checktype(L, 2, LUA_TFUNCTION); |
115 top = lua_gettop(L); |
140 top = lua_gettop(L); |
116 /* Preserve the callback function */ |
141 /* Preserve the callback function */ |
117 lua_pushvalue(L, 2); |
142 lua_pushvalue(L, 2); |
118 callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); |
143 callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); |
119 |
|
120 /* Call the callback with all arguments after it to get the loop primed.. */ |
144 /* Call the callback with all arguments after it to get the loop primed.. */ |
121 if(lua_pcall(L, top - 2, 1, 0) || !(lua_isnil(L, -1) || lua_isnumber(L, -1))) { |
145 if(0 == call_callback_function(L, top - 2)) { |
122 printf("ERROR IN INIT: %s\n", lua_tostring(L, -1)); |
|
123 lua_pop(L, 1); |
|
124 return 0; |
|
125 } |
|
126 /* Lua_isnil returns 1 if the value is nil... */ |
|
127 ret = lua_tointeger(L, -1) | -lua_isnil(L, -1); |
|
128 lua_pop(L, 1); |
|
129 if(ret < 0) { /* Done, no need to setup event */ |
|
130 luaL_unref(L, LUA_REGISTRYINDEX, callbackRef); |
146 luaL_unref(L, LUA_REGISTRYINDEX, callbackRef); |
131 return 0; |
147 return 0; |
132 } |
148 } |
133 if(ret != EV_READ && ret != EV_WRITE) { |
149 |
134 printf("BAD RET_VAL IN INIT: %i\n", ret); |
150 push_new_callback(L, callbackRef, fd, ret); |
135 } |
|
136 arg = lua_newuserdata(L, sizeof(*arg)); |
|
137 luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT); |
|
138 lua_setmetatable(L, -2); |
|
139 |
|
140 arg->L = L; |
|
141 arg->callbackRef = callbackRef; |
|
142 |
|
143 /* Setup event... */ |
|
144 event_set(&arg->ev, fd, ret | EV_PERSIST, luaevent_callback, arg); |
|
145 event_base_set(getEventBase(L), &arg->ev); |
|
146 event_add(&arg->ev, NULL); |
|
147 return 1; |
151 return 1; |
148 } |
152 } |
149 |
153 |
150 static int luaevent_loop(lua_State* L) { |
154 static int luaevent_loop(lua_State* L) { |
151 int ret = event_base_loop(getEventBase(L), 0); |
155 int ret = event_base_loop(getEventBase(L), 0); |