* Committing what will be version 0.1.2
[luaevent.git] / luaevent / src / luaevent.c
blob38f19ceaf08510529d52992e6264cfb3ae92035b
1 /* LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com>
2 * Licensed as LGPL - See doc/COPYING for details */
3 #include "luaevent.h"
5 #include <lua.h>
6 #include <lauxlib.h>
7 #include <assert.h>
9 #define EVENT_BASE_MT "EVENT_BASE_MT"
10 #define EVENT_CALLBACK_ARG_MT "EVENT_CALLBACK_ARG_MT"
11 #define MAIN_THREAD_LOCATION 1
13 void setMainThread(lua_State* L) {
14 lua_pushthread(L);
15 lua_rawseti(L, LUA_ENVIRONINDEX, MAIN_THREAD_LOCATION);
17 lua_State* getMainThread(lua_State* L) {
18 lua_State* g_L;
19 lua_rawgeti(L, LUA_ENVIRONINDEX, MAIN_THREAD_LOCATION);
20 g_L = lua_tothread(L, -1);
21 lua_pop(L, 1);
22 return g_L;
25 int luaevent_newbase(lua_State* L) {
26 le_base *base = (le_base*)lua_newuserdata(L, sizeof(le_base));
27 base->loop_L = NULL; /* No running loop */
28 base->base = event_init();
29 luaL_getmetatable(L, EVENT_BASE_MT);
30 lua_setmetatable(L, -2);
31 return 1;
34 void freeCallbackArgs(le_callback* arg, lua_State* L) {
35 if(arg->base) {
36 arg->base = NULL;
37 event_del(&arg->ev);
38 luaL_unref(L, LUA_REGISTRYINDEX, arg->callbackRef);
41 /* le_callback is allocated at the beginning of the coroutine in which it
42 is used, no need to manually de-allocate */
44 /* Index for coroutine is fd as integer for *nix, as lightuserdata for Win */
45 static void luaevent_callback(int fd, short event, void* p) {
46 le_callback* arg = p;
47 lua_State* L;
48 int ret;
49 assert(arg && arg->base && arg->base->loop_L);
50 L = arg->base->loop_L;
51 lua_rawgeti(L, LUA_REGISTRYINDEX, arg->callbackRef);
52 lua_pushinteger(L, event);
53 lua_call(L, 1, 1);
54 ret = lua_tointeger(L, -1);
55 lua_pop(L, 1);
56 if(ret == -1) {
57 freeCallbackArgs(arg, L);
58 } else {
59 struct event *ev = &arg->ev;
60 int newEvent = ret;
61 if(newEvent != event) { // Need to hook up new event...
62 event_del(ev);
63 event_set(ev, fd, EV_PERSIST | newEvent, luaevent_callback, arg);
64 event_add(ev, NULL);
69 static int luaevent_base_gc(lua_State* L) {
70 le_base *base = luaL_checkudata(L, 1, EVENT_BASE_MT);
71 if(base->base) {
72 event_base_free(base->base);
73 base->base = NULL;
75 return 0;
78 static int luaevent_cb_gc(lua_State* L) {
79 le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT);
80 freeCallbackArgs(arg, L);
81 return 0;
84 int getSocketFd(lua_State* L, int idx) {
85 int fd;
86 luaL_checktype(L, idx, LUA_TUSERDATA);
87 lua_getfield(L, idx, "getfd");
88 if(lua_isnil(L, -1))
89 return luaL_error(L, "Socket type missing 'getfd' method");
90 lua_pushvalue(L, idx);
91 lua_call(L, 1, 1);
92 fd = lua_tointeger(L, -1);
93 lua_pop(L, 1);
94 return fd;
97 /* sock, event, callback */
98 static int luaevent_addevent(lua_State* L) {
99 int fd, event, callbackRef;
100 le_callback* arg;
101 le_base *base = luaL_checkudata(L, 1, EVENT_BASE_MT);
102 fd = getSocketFd(L, 2);
103 event = luaL_checkinteger(L, 3);
104 luaL_checktype(L, 4, LUA_TFUNCTION);
105 lua_pushvalue(L, 4);
106 callbackRef = luaL_ref(L, LUA_REGISTRYINDEX);
107 arg = lua_newuserdata(L, sizeof(*arg));
108 luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT);
109 lua_setmetatable(L, -2);
111 arg->base = base;
112 arg->callbackRef = callbackRef;
113 /* Setup event... */
114 event_set(&arg->ev, fd, event | EV_PERSIST, luaevent_callback, arg);
115 event_base_set(base->base, &arg->ev);
116 event_add(&arg->ev, NULL);
117 return 1;
120 static int luaevent_loop(lua_State* L) {
121 le_base *base = luaL_checkudata(L, 1, EVENT_BASE_MT);
122 base->loop_L = L;
123 int ret = event_base_loop(base->base, 0);
124 lua_pushinteger(L, ret);
125 return 1;
128 static luaL_Reg base_funcs[] = {
129 { "addevent", luaevent_addevent },
130 { "loop", luaevent_loop },
131 { NULL, NULL }
134 static luaL_Reg funcs[] = {
135 { "new", luaevent_newbase },
136 { NULL, NULL }
139 typedef struct {
140 const char* name;
141 int value;
142 } namedInteger;
144 static namedInteger consts[] = {
145 {"LEAVE", -1},
146 {"EV_READ", EV_READ},
147 {"EV_WRITE", EV_WRITE},
148 {NULL, 0}
151 void setNamedIntegers(lua_State* L, namedInteger* p) {
152 while(p->name) {
153 lua_pushinteger(L, p->value);
154 lua_setfield(L, -2, p->name);
155 p++;
159 /* Verified ok */
160 int luaopen_luaevent_core(lua_State* L) {
161 /* Setup environ table */
162 lua_createtable(L, 1, 0);
163 lua_replace(L, LUA_ENVIRONINDEX);
164 /* Setup metatable */
165 luaL_newmetatable(L, EVENT_BASE_MT);
166 lua_newtable(L);
167 luaL_register(L, NULL, base_funcs);
168 lua_setfield(L, -2, "__index");
169 lua_pushcfunction(L, luaevent_base_gc);
170 lua_setfield(L, -2, "__gc");
171 lua_pop(L, 1);
172 luaL_newmetatable(L, EVENT_CALLBACK_ARG_MT);
173 lua_pushcfunction(L, luaevent_cb_gc);
174 lua_setfield(L, -2, "__gc");
175 lua_newtable(L);
176 lua_pushcfunction(L, luaevent_cb_gc);
177 lua_setfield(L, -2, "close");
178 lua_setfield(L, -2, "__index");
179 lua_pop(L, 1);
181 luaL_register(L, "luaevent.core", funcs);
182 setNamedIntegers(L, consts);
183 return 1;