1 
  2 /*
  3 -- C-Event.c
  4 --
  5 -- This file is part of the source package that accompanies the article
  6 -- "Writing C modules for Lua" from the book "Lua Programming Gems."
  7 --
  8 -- Copyright (c) 2008
  9 -- Wim Couwenberg, Ralph Steggink
 10 --
 11 -- Both Lua and libevent must be available on your system to compile this
 12 -- module.  To create the C-Event bundle on OSX use:
 13 --
 14 --     gcc -O2 -Wall -bundle -llua -levent -o C-Event.so C-Event.c
 15 */
 16 
 17 #include <sys/types.h>
 18 #include <sys/time.h>
 19 #include "event.h"
 20 
 21 #include "lua.h"
 22 #include "lauxlib.h"
 23 
 24 /* export entry point */
 25 #ifdef _WIN32
 26 #   define EVENT_API __declspec(dllexport)
 27 #else
 28 #   define EVENT_API
 29 #endif
 30 
 31 /* event wrapper to pack into userdata */
 32 struct levent {
 33     struct event event;
 34     lua_State *L;
 35 };
 36 
 37 /* The libevent callback handler */
 38 static void handler(int fd, short event_type, void *arg) {
 39     struct levent *ev = (struct levent *)arg;
 40     lua_getfield(ev->L, LUA_ENVIRONINDEX, "handle_event");
 41     lua_pushlightuserdata(ev->L, ev);
 42     lua_pushnumber(ev->L, fd);
 43     lua_pushnumber(ev->L, event_type);
 44     lua_call(ev->L, 3, 0);
 45 }
 46 
 47 /* bind the lua dispatch function to the libevent dispatch function */
 48 static int dispatch(lua_State *L) {
 49     event_dispatch();
 50     return 0;
 51 }
 52 
 53 /* create an Event userdata */
 54 static int create(lua_State *L) {
 55     /* Lua stack:  fd, event_mask */
 56     int fd = lua_tonumber(L, 1);
 57     int event_type = lua_tonumber(L, 2);
 58 
 59     /* pack levent structure in userdata */
 60     struct levent *ev = (struct levent *)lua_newuserdata(L, sizeof(*ev));
 61     ev->L = L;
 62     event_set(&ev->event, fd, event_type, handler, ev);
 63 
 64     /* set userdata metatable (from aux table) */
 65     lua_getfield(L, LUA_ENVIRONINDEX, "metatable");
 66     lua_setmetatable(L, -2);
 67 
 68     /* return userdata and address of levent (to index event objects) */
 69     lua_pushlightuserdata(L, ev);
 70     return 2;
 71 }
 72 
 73 /* bind the lua add function to the libevent add function */
 74 static int add(lua_State *L) {
 75     /* Lua stack:  userdata [, seconds, useconds] */
 76     int res;
 77     struct timeval t, *pt = NULL;
 78     struct levent *ev = (struct levent *)lua_touserdata(L, 1);
 79 
 80     /* timeout specified? */
 81     if (lua_type(L, 2) == LUA_TNUMBER) {
 82         t.tv_sec = lua_tointeger(L, 2);
 83         t.tv_usec = lua_tointeger(L, 3);
 84         pt = &t;
 85     }
 86 
 87     res = event_add(&ev->event, pt);
 88     lua_pushinteger(L, res);
 89     return 1;
 90 }
 91 
 92 /* delete event.  doubles as garbage collection function */
 93 static int del(lua_State *L) {
 94     /* Lua stack:  userdata */
 95     struct levent *ev = (struct levent*)lua_touserdata(L, 1);
 96     int res = event_del(&ev->event);
 97     lua_pushinteger(L, res);
 98     return 1;
 99 }
100 
101 /* definition of a constant name/value pair */
102 struct constant {
103     const char * name;
104     int value;
105 };
106 
107 /* constants */
108 static const struct constant constants[] = {
109     {"EV_TIMEOUT", EV_TIMEOUT},
110     {"EV_READ", EV_READ},
111     {"EV_WRITE", EV_WRITE},
112     {"EV_SIGNAL", EV_SIGNAL},
113     {"EV_PERSIST", EV_PERSIST},
114     {NULL, 0}
115 };
116 
117 /* private functions */
118 static const luaL_Reg prv[] = {
119     {"dispatch", dispatch},
120     {"create", create},
121     {"add", add},
122     {"del", del},
123     {NULL, NULL}
124 };
125 
126 /* initialize the Event module */
127 static int initialize(lua_State *L) {
128     /* Lua stack:  aux table, prv table, module table */
129 
130     /* define constants in module namespace */
131     int index;
132     for (index = 0; constants[index].name != NULL; ++index) {
133         lua_pushinteger(L, constants[index].value);
134         lua_setfield(L, 3, constants[index].name);
135     }
136 
137     /* set the "aux" table as environment */
138     lua_pushvalue(L, 1);
139     lua_replace(L, LUA_ENVIRONINDEX);
140 
141     /* register prv functions */
142     lua_pushvalue(L, 2);
143     luaL_register(L, NULL, prv);
144 
145     /* initialize event library */
146     event_init();
147 
148     return 0;
149 }
150 
151 /* entry point for C-Event module */
152 EVENT_API int luaopen_Event(lua_State *L) {
153     lua_pushcfunction(L, initialize);
154     return 1;
155 }