mirror of
https://github.com/troglobit/libuev.git
synced 2026-10-09 16:50:26 +07:00
Lua binding, done coding
This commit is contained in:
@@ -12,13 +12,14 @@ CROSS_COMPILE=
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
AR=$(CROSS_COMPILE)ar
|
||||
|
||||
INCLUDE += -I /usr/include/lua5.1/
|
||||
LDFLAGS=-s
|
||||
CFLAGS=-fPIC -g -Os
|
||||
CFLAGS=-fPIC -g -Os $(INCLUDE)
|
||||
|
||||
MAJOR = 1
|
||||
|
||||
all: libuevent.a libuevent.so.$(MAJOR)
|
||||
lua: luauevent.so
|
||||
lua: luevent.so
|
||||
|
||||
libuevent.a: libuevent.o
|
||||
$(AR) r $@ $^
|
||||
@@ -27,8 +28,8 @@ libuevent.a: libuevent.o
|
||||
libuevent.so.$(MAJOR): libuevent.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname=libuevent
|
||||
|
||||
luauevent.so: luauevent.o all
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ -L . -l uevent -Wl,-soname=uevent
|
||||
luevent.so: luevent.o all
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ -L . -l uevent -Wl,-soname=luevent
|
||||
|
||||
test: all
|
||||
$(CC) -g -o test -D NO_DEBUG test.c libuevent.c && ./test
|
||||
@@ -37,7 +38,7 @@ luatest: lua
|
||||
lua test.lua
|
||||
|
||||
clean:
|
||||
rm -f libuevent.o luauevent.o libuevent.so.$(MAJOR) luauevent.so test
|
||||
rm -f libuevent.o luauevent.o libuevent.so.$(MAJOR) luevent.so test
|
||||
|
||||
|
||||
.PHONY: all test clean luatest lua
|
||||
|
||||
@@ -33,7 +33,6 @@ Installation
|
||||
------------
|
||||
Is purely manual, but would be something along the lines of:
|
||||
sudo install -m 444 libuevent.so.1 /usr/lib/libuevent.so.1
|
||||
sudo install -m 444 lualue.so /usr/lib/lua/5.1/lue.so
|
||||
|
||||
sudo install -m 444 luevent.so /usr/lib/lua/5.1/luevent.so
|
||||
|
||||
<!-- vim: set syntax=mkd textwidth=79: -->
|
||||
|
||||
+105
-88
@@ -310,121 +310,138 @@ void lueTimeAdvance(struct LUECtxt *ctxt, int mSecs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application
|
||||
* Process pending events
|
||||
*/
|
||||
void lueRun(struct LUECtxt *ctxt)
|
||||
static int _lueProcessPending(struct LUECtxt *ctxt, int immediate)
|
||||
{
|
||||
struct LUETimerH *timer;
|
||||
int pollRet;
|
||||
clock_t curTime;
|
||||
int curPeriod = 0;
|
||||
|
||||
do
|
||||
// Do due timers
|
||||
if (lListHead(&ctxt->timeoutHandlers))
|
||||
{
|
||||
clock_t curTime;
|
||||
int curPeriod = 0;
|
||||
|
||||
// Do due timers
|
||||
if (lListHead(&ctxt->timeoutHandlers))
|
||||
curTime = ctxt->timeSet ? ctxt->setTime : times(NULL);
|
||||
curPeriod = (curTime - ctxt->baseTime) / clock_tick * 1000
|
||||
+ ((curTime - ctxt->baseTime) % clock_tick) * 1000 / clock_tick;
|
||||
Debug("Period for timer execution %d", curPeriod);
|
||||
while((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
||||
timer->dueTime <= curPeriod)
|
||||
{
|
||||
curTime = ctxt->timeSet ? ctxt->setTime : times(NULL);
|
||||
timer->handler(ctxt, timer, timer->data);
|
||||
lueRemTimer(ctxt, timer);
|
||||
|
||||
// baseTime changes for every lueAddTimer
|
||||
curPeriod = (curTime - ctxt->baseTime) / clock_tick * 1000
|
||||
+ ((curTime - ctxt->baseTime) % clock_tick) * 1000 / clock_tick;
|
||||
Debug("Period for timer execution %d", curPeriod);
|
||||
while((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
||||
timer->dueTime <= curPeriod)
|
||||
{
|
||||
timer->handler(ctxt, timer, timer->data);
|
||||
lueRemTimer(ctxt, timer);
|
||||
|
||||
// baseTime changes for every lueAddTimer
|
||||
curPeriod = (curTime - ctxt->baseTime) / clock_tick * 1000
|
||||
+ ((curTime - ctxt->baseTime) % clock_tick) * 1000 / clock_tick;
|
||||
}
|
||||
lListPurge(&ctxt->timeRem); // Reap timer zombies
|
||||
+ ((curTime - ctxt->baseTime) % clock_tick) * 1000 / clock_tick;
|
||||
}
|
||||
lListPurge(&ctxt->timeRem); // Reap timer zombies
|
||||
}
|
||||
|
||||
// Calculate waiting time
|
||||
if (ctxt->exiting)
|
||||
curPeriod = 0;
|
||||
else if ((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
||||
timer->dueTime > curPeriod)
|
||||
// Calculate waiting time
|
||||
if (ctxt->exiting)
|
||||
curPeriod = 0;
|
||||
else if ((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
||||
timer->dueTime > curPeriod)
|
||||
{
|
||||
Debug("Period from timer head %d - %d -> %d",
|
||||
timer->dueTime, curPeriod, timer->dueTime - curPeriod);
|
||||
curPeriod = timer->dueTime - curPeriod;
|
||||
}
|
||||
else if (NULL != timer)
|
||||
curPeriod = 0;
|
||||
else
|
||||
curPeriod = -1;
|
||||
|
||||
// Do pipe handlers
|
||||
if (lListHead(&ctxt->fileHandlers) && !ctxt->exiting)
|
||||
{
|
||||
struct pollfd polls[lListLength(&ctxt->fileHandlers)];
|
||||
struct LUEFileEventH *ent;
|
||||
|
||||
int ix = 0;
|
||||
lListForeachIn(ent, &ctxt->fileHandlers)
|
||||
{
|
||||
Debug("Period from timer head %d - %d -> %d",
|
||||
timer->dueTime, curPeriod, timer->dueTime - curPeriod);
|
||||
curPeriod = timer->dueTime - curPeriod;
|
||||
ent->pollIx = ix;
|
||||
polls[ix].fd = ent->fd;
|
||||
polls[ix].events = LUE_FHIN == ent->direction ? POLLIN : POLLOUT;
|
||||
polls[ix].revents = 0;
|
||||
ix++;
|
||||
}
|
||||
else if (NULL != timer)
|
||||
curPeriod = 0;
|
||||
else
|
||||
curPeriod = -1;
|
||||
|
||||
// Do pipe handlers
|
||||
pollRet = 0;
|
||||
if (lListHead(&ctxt->fileHandlers) && !ctxt->exiting)
|
||||
Debug("Polling %d fds in %d ms", ix, curPeriod);
|
||||
pollRet = poll(polls, ix, immediate ? 0 : curPeriod);
|
||||
if (pollRet < 0)
|
||||
{
|
||||
struct pollfd polls[lListLength(&ctxt->fileHandlers)];
|
||||
struct LUEFileEventH *ent;
|
||||
|
||||
int ix = 0;
|
||||
lListForeachIn(ent, &ctxt->fileHandlers)
|
||||
{
|
||||
ent->pollIx = ix;
|
||||
polls[ix].fd = ent->fd;
|
||||
polls[ix].events = LUE_FHIN == ent->direction ? POLLIN : POLLOUT;
|
||||
polls[ix].revents = 0;
|
||||
ix++;
|
||||
}
|
||||
Debug("Polling %d fds in %d ms", ix, curPeriod);
|
||||
pollRet = poll(polls, ix, curPeriod);
|
||||
if (pollRet < 0)
|
||||
{
|
||||
if (EINTR == errno)
|
||||
continue;
|
||||
else if (EBADF == errno)
|
||||
{
|
||||
lListForeachIn(ent, &ctxt->fileHandlers)
|
||||
{
|
||||
if (fcntl(ent->fd, F_GETFD) == -1 && EBADF == errno)
|
||||
{
|
||||
ent->handler(ctxt, ent, ent->fd, ent->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error in poll. Cannot continue
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (pollRet > 0)
|
||||
if (EINTR == errno)
|
||||
return 0;
|
||||
else if (EBADF == errno)
|
||||
{
|
||||
lListForeachIn(ent, &ctxt->fileHandlers)
|
||||
{
|
||||
if (ent->handler && ent->pollIx >= 0 && polls[ent->pollIx].revents)
|
||||
if (fcntl(ent->fd, F_GETFD) == -1 && EBADF == errno)
|
||||
{
|
||||
ent->handler(ctxt, ent, ent->fd, ent->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lListHead(&ctxt->fileRem))
|
||||
else
|
||||
{
|
||||
struct LUEFileEventH *ent;
|
||||
|
||||
while (NULL != (ent = lListHead(&ctxt->fileRem)))
|
||||
// Error in poll. Cannot continue
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (pollRet > 0)
|
||||
{
|
||||
lListForeachIn(ent, &ctxt->fileHandlers)
|
||||
{
|
||||
if (ent->handler && ent->pollIx >= 0 && polls[ent->pollIx].revents)
|
||||
{
|
||||
lListRemove(&ctxt->fileHandlers, ent);
|
||||
free(ent);
|
||||
ent->handler(ctxt, ent, ent->fd, ent->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (curPeriod > 0)
|
||||
if (lListHead(&ctxt->fileRem))
|
||||
{
|
||||
struct LUEFileEventH *ent;
|
||||
|
||||
while (NULL != (ent = lListHead(&ctxt->fileRem)))
|
||||
{
|
||||
lListRemove(&ctxt->fileHandlers, ent);
|
||||
free(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (curPeriod > 0)
|
||||
{
|
||||
if (!immediate)
|
||||
poll(NULL, 0, curPeriod);
|
||||
else
|
||||
break; // LUEarently were out of work!
|
||||
} while (!ctxt->exiting);
|
||||
// Wont exit while there is due timers or files
|
||||
//((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
||||
//timer->dueTime <= 0) || pollRet > 0);
|
||||
}
|
||||
else if (curPeriod == -1)
|
||||
curPeriod = -2; // Nothing more to do
|
||||
|
||||
return curPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process pending events
|
||||
*/
|
||||
int lueProcessPending(struct LUECtxt *ctxt)
|
||||
{
|
||||
return _lueProcessPending(ctxt, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application
|
||||
*/
|
||||
void lueRun(struct LUECtxt *ctxt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = _lueProcessPending(ctxt, 0);
|
||||
} while (!ctxt->exiting && ret != -2);
|
||||
Debug("LUE exiting - bye");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ struct LUECtxt *lueCtxtCreate();
|
||||
void lueCtxtDestroy(struct LUECtxt *lue);
|
||||
void lueTimeAdvance(struct LUECtxt *ctxt, int mSecs);
|
||||
void lueRun(struct LUECtxt *ctxt);
|
||||
void lueProcessEvents(struct LUECtxt *ctxt);
|
||||
int lueProcessPending(struct LUECtxt *ctxt);
|
||||
void lueExit(struct LUECtxt *ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/mple**
|
||||
* @file
|
||||
* Lua binding to libuevent
|
||||
* $Id:$
|
||||
*
|
||||
* (C) Copyright 2012 flemming.madsen at madsensoft.dk. See libuevent.h
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <lua.h>
|
||||
#include "libuevent.h"
|
||||
|
||||
static char * LUA_LTIMER_MT = "libuevent-timer";
|
||||
static char * LUA_LFILEH_MT = "libuevent-fileh";
|
||||
static char * LUA_LUEOBJ = "libuevent-objects";
|
||||
|
||||
typedef struct lue_data
|
||||
{
|
||||
lua_State *L; // Index to our world
|
||||
struct LUETimerH *timer;
|
||||
struct LUEFileEventH *file;
|
||||
} lue_data;
|
||||
#define toptimer(L) ((struct lue_data *)luaL_checkudata(L, 1, LUA_LTIMER_MT))
|
||||
#define topfileh(L) ((struct lue_data *)luaL_checkudata(L, 1, LUA_LFILEH_MT))
|
||||
|
||||
static struct LUECtxt *getCtxt(lua_State *L)
|
||||
{
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
lua_rawgeti(L, -1, 1);
|
||||
struct LUECtxt *ret = lua_touserdata(L, -1);
|
||||
lua_pop(L, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int l_traceback (lua_State *L)
|
||||
{
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
lua_getfield(L, -1, "traceback");
|
||||
if (!lua_isfunction(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
return 1;
|
||||
}
|
||||
lua_pushvalue(L, 1); /* pass error message */
|
||||
lua_pushinteger(L, 2); /* skip this function and traceback */
|
||||
lua_call(L, 2, 1); /* call debug.traceback */
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Top half
|
||||
static int _lueHandler(lua_State *L, void *data, bool remObj)
|
||||
{
|
||||
lua_pushcfunction(L, l_traceback); /* push traceback function */
|
||||
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
lua_pushlightuserdata(L, data);
|
||||
lua_rawget(L, -2); // objects[object_p] => The object
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawget(L, -3); // object[object] => closure
|
||||
|
||||
if (remObj)
|
||||
{
|
||||
lua_pushlightuserdata(L, data);
|
||||
lua_pushnil(L);
|
||||
lua_rawset(L, -5); // objects[object_p] = nil -> GC
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushnil(L);
|
||||
lua_rawset(L, -5); // objects[object] = nil -> GC
|
||||
}
|
||||
lua_remove(L, -3); // objects table
|
||||
|
||||
int ret;
|
||||
lua_insert(L, -2); // exch: closure <-> obj
|
||||
if ((ret = lua_pcall(L, 1, 0, -3))) // Call closure(object)
|
||||
{
|
||||
fprintf(stderr, "luevent: Error: %d:\n%s\n",
|
||||
ret, lua_isnil(L, -1) ? "(nil)" : lua_tostring(L, -1));
|
||||
exit(1);
|
||||
}
|
||||
lua_pop(L, 1); // Error handler, metatable
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ltimerHandler(struct LUECtxt *ctxt, struct LUETimerH *handle, void *data)
|
||||
{
|
||||
lue_data *self = (lue_data *) data;
|
||||
if (!self || !self->timer)
|
||||
return 0;
|
||||
|
||||
int ret = _lueHandler(self->L, data, true);
|
||||
self->timer = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lfileHandler(struct LUECtxt *ctxt, struct LUEFileEventH *handle, int fd, void *data)
|
||||
{
|
||||
lue_data *self = (lue_data *) data;
|
||||
bool remObj = false;
|
||||
if (!self || !self->file)
|
||||
return 0;
|
||||
|
||||
if (fcntl(fd, F_GETFD) == -1 && EBADF == errno)
|
||||
{
|
||||
remObj = true;
|
||||
lueRemInput(getCtxt(self->L), self->file); // Works on both types
|
||||
self->file = NULL;
|
||||
}
|
||||
|
||||
return _lueHandler(self->L, data, remObj);
|
||||
}
|
||||
|
||||
// Bottom half
|
||||
static void lueAddObj(lua_State *L, lue_data *self, int cbix)
|
||||
{
|
||||
self->L = L;
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
|
||||
lua_pushlightuserdata(L, self);
|
||||
lua_pushvalue(L, -3);
|
||||
lua_rawset(L, -3); // objects[self_p] = obj
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushvalue(L, cbix);
|
||||
lua_rawset(L, -3); // objects[obj] = callback
|
||||
lua_pop(L, 1); // objects
|
||||
}
|
||||
|
||||
/* LUADOC
|
||||
* Add a handler on a stream.
|
||||
* The handler will sustain itself GC wise. Use <:object>:clear() to unregister the handler
|
||||
* @param fdesc The posix file descriptor "small integer".
|
||||
* <br> Use the ":getfd()" method on a "normal" lua stream or socket to obtain fdesc.
|
||||
* @param handler A function object. No paramaeter supplied when called.
|
||||
* @param mode [Optional] Input ("r") or output ("w") event. Default is input
|
||||
* @return A new filehandler object
|
||||
function luevent.addFileIO(fdesc, handler, mode)
|
||||
*/
|
||||
static int lfileh_add(lua_State *L)
|
||||
{
|
||||
int fd = luaL_checkint(L, 1);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
const char *mode = luaL_optstring(L, 3, "r");
|
||||
|
||||
lue_data *self = (lue_data *) lua_newuserdata(L, sizeof(lue_data));
|
||||
struct LUEFileEventH *h = *mode == 'r' ?
|
||||
lueAddInput(getCtxt(L), fd, _lfileHandler, self) :
|
||||
lueAddOutput(getCtxt(L), fd, _lfileHandler, self);
|
||||
if (!h) luaL_error(L, "lueAddFileIO error");
|
||||
self->file = h;
|
||||
|
||||
luaL_getmetatable(L, LUA_LFILEH_MT);
|
||||
lua_setmetatable(L, -2);
|
||||
lueAddObj(L, self, 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* LUADOC
|
||||
* Create a new timer object. Implicitly cleared when handler is called.
|
||||
* @usage <pre>
|
||||
* local hdl<br>
|
||||
* hdl = luevent.addTimer(50, function() hdl = nil xxx end)<br>
|
||||
* ......<br>
|
||||
* if hdl then hdl:clear() hdl = nil end<br>
|
||||
* </pre>
|
||||
* Here <tt>hdl</tt> is used to keep track of whether the timer is active.
|
||||
* @param msecs The number of milliseconds until the timer expires
|
||||
* @param handler A function object
|
||||
* @return A new timer object
|
||||
function luevent.addTimer(msecs, handler)
|
||||
*/
|
||||
static int ltimer_add(lua_State *L)
|
||||
{
|
||||
int mSecs = luaL_checkint(L, 1);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
lue_data *self = (lue_data *) lua_newuserdata(L, sizeof(lue_data));
|
||||
struct LUETimerH *h = self ? lueAddTimer(getCtxt(L), mSecs, _ltimerHandler, self) : NULL;
|
||||
if (!h)
|
||||
luaL_error(L, "lueAddTimer error");
|
||||
self->timer = h;
|
||||
|
||||
luaL_getmetatable(L, LUA_LTIMER_MT);
|
||||
lua_setmetatable(L, 3);
|
||||
lueAddObj(L, self, 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void lobj_clear(lua_State *L, lue_data *self)
|
||||
{
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
lua_pushlightuserdata(L, self);
|
||||
lua_rawget(L, -2); // objects[object_p] => The object
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_rawset(L, -3); // objects[object] = nil -> GC
|
||||
lua_pushlightuserdata(L, self);
|
||||
lua_pushnil(L);
|
||||
lua_rawset(L, -3); // objects[object_p] = nil -> GC
|
||||
lua_pop(L, 1); // pop objects
|
||||
}
|
||||
|
||||
/* LUADOC
|
||||
* Cancel a timer callback. Renders the object ready for GC.
|
||||
function timer:clear()
|
||||
*/
|
||||
static int ltimer_clear(lua_State *L)
|
||||
{
|
||||
lue_data *self = toptimer(L);
|
||||
|
||||
if (self->timer)
|
||||
{
|
||||
lueRemTimer(getCtxt(L), self->timer);
|
||||
self->timer = NULL;
|
||||
}
|
||||
lobj_clear(L, self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LUADOC
|
||||
* Cancel a fileio callback. Renders the object ready for GC.
|
||||
function fileio:clear()
|
||||
*/
|
||||
static int lfileh_clear(lua_State *L)
|
||||
{
|
||||
lue_data *self = topfileh(L);
|
||||
|
||||
if (self->file)
|
||||
{
|
||||
lueRemInput(getCtxt(L), self->file); // Works on both types
|
||||
self->file = NULL;
|
||||
}
|
||||
lobj_clear(L, self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LUADOC
|
||||
* Obtain the registered handler on the object
|
||||
* @return The handler
|
||||
function luevent_object:handler()
|
||||
*/
|
||||
static int luevent_handler(lua_State *L)
|
||||
{
|
||||
lue_data *self = lua_touserdata(L, 1);
|
||||
|
||||
if (self)
|
||||
{
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
|
||||
lua_getfield(L, -1, "_objects");
|
||||
lua_getfield(L, -2, "_callbacks");
|
||||
if (lua_istable(L, -1) && lua_istable(L, -2))
|
||||
{
|
||||
lua_pushlightuserdata(L, self);
|
||||
lua_rawget(L, -2); // The object
|
||||
lua_rawget(L, -2); // callbacks[obj] -> closure
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltimer_gc(lua_State *L)
|
||||
{
|
||||
//STACKDUMP(L);
|
||||
lue_data *self = toptimer(L);
|
||||
|
||||
if (self->timer)
|
||||
{
|
||||
lueRemTimer(getCtxt(L), self->timer);
|
||||
self->timer = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfileh_gc(lua_State *L)
|
||||
{
|
||||
lue_data *self = topfileh(L);
|
||||
|
||||
if (self->file)
|
||||
{
|
||||
lueRemInput(getCtxt(L), self->file);
|
||||
self->file = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luevent_tostring(lua_State *L)
|
||||
{
|
||||
lue_data *self = lua_touserdata(L, 1);
|
||||
|
||||
lua_getmetatable(L, 1);
|
||||
lua_getfield(L, -1, "_typename");
|
||||
const char *t = lua_tostring(L, -1);
|
||||
|
||||
if (!self->timer && !self->file)
|
||||
lua_pushfstring(L, "%s (cleared)", t);
|
||||
else
|
||||
lua_pushfstring(L, "%s (%p)", t, self);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* LUADOC
|
||||
* Get the system time in hight resolution
|
||||
* @return two numbers: seconds and milliseconds since the epoch
|
||||
function luevent.systemTime()
|
||||
*/
|
||||
static int l_systemTime (lua_State *L)
|
||||
{
|
||||
struct timeval v;
|
||||
|
||||
gettimeofday(&v, (struct timezone *) NULL);
|
||||
lua_pushinteger(L, t.tv_sec);
|
||||
lua_pushinteger(L, v.tv_usec / 1000);
|
||||
return 2; // num of results
|
||||
}
|
||||
|
||||
static int l_cleanup(lua_State * L)
|
||||
{
|
||||
struct LUECtxt *ctxt = getCtxt(L);
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
lua_gc(L, LUA_GCCOLLECT, 0); // Make sure all timers & schedules & callbacks are gone before context
|
||||
|
||||
lueCtxtDestroy(ctxt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg lueventlib[] = {
|
||||
{"addFileIO", lfileh_add},
|
||||
{"clearFileIO", lfileh_clear},
|
||||
{"addTimer", ltimer_add},
|
||||
{"clearTimer", ltimer_clear},
|
||||
{"systemTime", l_systemTime},
|
||||
{"__gc", l_cleanup},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
static const luaL_Reg ltimermeta[] = {
|
||||
{"clear", ltimer_clear},
|
||||
{"handler", luevent_handler},
|
||||
{"__gc", ltimer_gc},
|
||||
{"__tostring", luevent_tostring},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
static const luaL_Reg lfilehmeta[] = {
|
||||
{"clear", lfileh_clear},
|
||||
{"handler", luevent_handler},
|
||||
{"__gc", lfileh_gc},
|
||||
{"__tostring", luevent_tostring},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
int luaopen_luevent(lua_State * L)
|
||||
{
|
||||
struct LUECtxt *lueContext = lueCtxtCreate();
|
||||
assert(ctxt);
|
||||
|
||||
luaL_register(L, lua_tostring(L, 1), lueventlib); // calls
|
||||
lua_setmetatable(L, -1); // Call GC at module cleanup. Pops it too
|
||||
|
||||
l_newType(L, LUA_LTIMER_MT); // create metatable for timers
|
||||
luaL_register(L, NULL, ltimermeta); // methods
|
||||
lua_pop(L, 1);
|
||||
|
||||
l_newType(L, LUA_LFILEH_MT); // create metatable for file handlers
|
||||
luaL_register(L, NULL, lfilehmeta); // methods
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_newtable(L); // Table[obj] -> Callback-closure
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, LUA_LUEOBJ);
|
||||
lua_pushlightuserdata(L, lueContext);// Table[1] = lueContext
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// vim: set sw=3 sts=3 et:
|
||||
Reference in New Issue
Block a user