mirror of
https://github.com/troglobit/libuev.git
synced 2026-11-10 16:31:08 +00:00
Lua binding, done coding
This commit is contained in:
1 parent
c3f9d0dc8d
commit
5c817c20ed
6 files changed
+507
-97
No files matched your search
@@ -12,13 +12,14 @@ CROSS_COMPILE=
|
|||||||
CC=$(CROSS_COMPILE)gcc
|
CC=$(CROSS_COMPILE)gcc
|
||||||
AR=$(CROSS_COMPILE)ar
|
AR=$(CROSS_COMPILE)ar
|
||||||
|
|
||||||
|
INCLUDE += -I /usr/include/lua5.1/
|
||||||
LDFLAGS=-s
|
LDFLAGS=-s
|
||||||
CFLAGS=-fPIC -g -Os
|
CFLAGS=-fPIC -g -Os $(INCLUDE)
|
||||||
|
|
||||||
MAJOR = 1
|
MAJOR = 1
|
||||||
|
|
||||||
all: libuevent.a libuevent.so.$(MAJOR)
|
all: libuevent.a libuevent.so.$(MAJOR)
|
||||||
lua: luauevent.so
|
lua: luevent.so
|
||||||
|
|
||||||
libuevent.a: libuevent.o
|
libuevent.a: libuevent.o
|
||||||
$(AR) r $@ $^
|
$(AR) r $@ $^
|
||||||
@@ -27,8 +28,8 @@ libuevent.a: libuevent.o
|
|||||||
libuevent.so.$(MAJOR): libuevent.o
|
libuevent.so.$(MAJOR): libuevent.o
|
||||||
$(CC) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname=libuevent
|
$(CC) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname=libuevent
|
||||||
|
|
||||||
luauevent.so: luauevent.o all
|
luevent.so: luevent.o all
|
||||||
$(CC) $(LDFLAGS) -shared -o $@ $^ -L . -l uevent -Wl,-soname=uevent
|
$(CC) $(LDFLAGS) -shared -o $@ $^ -L . -l uevent -Wl,-soname=luevent
|
||||||
|
|
||||||
test: all
|
test: all
|
||||||
$(CC) -g -o test -D NO_DEBUG test.c libuevent.c && ./test
|
$(CC) -g -o test -D NO_DEBUG test.c libuevent.c && ./test
|
||||||
@@ -37,7 +38,7 @@ luatest: lua
|
|||||||
lua test.lua
|
lua test.lua
|
||||||
|
|
||||||
clean:
|
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
|
.PHONY: all test clean luatest lua
|
||||||
@@ -33,7 +33,6 @@ Installation
|
|||||||
------------
|
------------
|
||||||
Is purely manual, but would be something along the lines of:
|
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 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: -->
|
<!-- 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;
|
struct LUETimerH *timer;
|
||||||
int pollRet;
|
int pollRet;
|
||||||
|
clock_t curTime;
|
||||||
|
int curPeriod = 0;
|
||||||
|
|
||||||
do
|
// Do due timers
|
||||||
|
if (lListHead(&ctxt->timeoutHandlers))
|
||||||
{
|
{
|
||||||
clock_t curTime;
|
curTime = ctxt->timeSet ? ctxt->setTime : times(NULL);
|
||||||
int curPeriod = 0;
|
curPeriod = (curTime - ctxt->baseTime) / clock_tick * 1000
|
||||||
|
+ ((curTime - ctxt->baseTime) % clock_tick) * 1000 / clock_tick;
|
||||||
// Do due timers
|
Debug("Period for timer execution %d", curPeriod);
|
||||||
if (lListHead(&ctxt->timeoutHandlers))
|
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
|
curPeriod = (curTime - ctxt->baseTime) / clock_tick * 1000
|
||||||
+ ((curTime - ctxt->baseTime) % clock_tick) * 1000 / clock_tick;
|
+ ((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
|
|
||||||
}
|
}
|
||||||
|
lListPurge(&ctxt->timeRem); // Reap timer zombies
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate waiting time
|
// Calculate waiting time
|
||||||
if (ctxt->exiting)
|
if (ctxt->exiting)
|
||||||
curPeriod = 0;
|
curPeriod = 0;
|
||||||
else if ((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
else if ((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
||||||
timer->dueTime > curPeriod)
|
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",
|
ent->pollIx = ix;
|
||||||
timer->dueTime, curPeriod, timer->dueTime - curPeriod);
|
polls[ix].fd = ent->fd;
|
||||||
curPeriod = timer->dueTime - curPeriod;
|
polls[ix].events = LUE_FHIN == ent->direction ? POLLIN : POLLOUT;
|
||||||
|
polls[ix].revents = 0;
|
||||||
|
ix++;
|
||||||
}
|
}
|
||||||
else if (NULL != timer)
|
Debug("Polling %d fds in %d ms", ix, curPeriod);
|
||||||
curPeriod = 0;
|
pollRet = poll(polls, ix, immediate ? 0 : curPeriod);
|
||||||
else
|
if (pollRet < 0)
|
||||||
curPeriod = -1;
|
|
||||||
|
|
||||||
// Do pipe handlers
|
|
||||||
pollRet = 0;
|
|
||||||
if (lListHead(&ctxt->fileHandlers) && !ctxt->exiting)
|
|
||||||
{
|
{
|
||||||
struct pollfd polls[lListLength(&ctxt->fileHandlers)];
|
if (EINTR == errno)
|
||||||
struct LUEFileEventH *ent;
|
return 0;
|
||||||
|
else if (EBADF == errno)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
lListForeachIn(ent, &ctxt->fileHandlers)
|
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);
|
ent->handler(ctxt, ent, ent->fd, ent->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lListHead(&ctxt->fileRem))
|
else
|
||||||
{
|
{
|
||||||
struct LUEFileEventH *ent;
|
// Error in poll. Cannot continue
|
||||||
|
assert(false);
|
||||||
while (NULL != (ent = lListHead(&ctxt->fileRem)))
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pollRet > 0)
|
||||||
|
{
|
||||||
|
lListForeachIn(ent, &ctxt->fileHandlers)
|
||||||
|
{
|
||||||
|
if (ent->handler && ent->pollIx >= 0 && polls[ent->pollIx].revents)
|
||||||
{
|
{
|
||||||
lListRemove(&ctxt->fileHandlers, ent);
|
ent->handler(ctxt, ent, ent->fd, ent->data);
|
||||||
free(ent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
poll(NULL, 0, curPeriod);
|
||||||
else
|
}
|
||||||
break; // LUEarently were out of work!
|
else if (curPeriod == -1)
|
||||||
} while (!ctxt->exiting);
|
curPeriod = -2; // Nothing more to do
|
||||||
// Wont exit while there is due timers or files
|
|
||||||
//((timer = lListHead(&ctxt->timeoutHandlers)) &&
|
return curPeriod;
|
||||||
//timer->dueTime <= 0) || pollRet > 0);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
Debug("LUE exiting - bye");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ struct LUECtxt *lueCtxtCreate();
|
|||||||
void lueCtxtDestroy(struct LUECtxt *lue);
|
void lueCtxtDestroy(struct LUECtxt *lue);
|
||||||
void lueTimeAdvance(struct LUECtxt *ctxt, int mSecs);
|
void lueTimeAdvance(struct LUECtxt *ctxt, int mSecs);
|
||||||
void lueRun(struct LUECtxt *ctxt);
|
void lueRun(struct LUECtxt *ctxt);
|
||||||
void lueProcessEvents(struct LUECtxt *ctxt);
|
int lueProcessPending(struct LUECtxt *ctxt);
|
||||||
void lueExit(struct LUECtxt *ctxt);
|
void lueExit(struct LUECtxt *ctxt);
|
||||||
|
|
||||||
#endif
|
#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:
|
||||||
@@ -73,7 +73,7 @@ main()
|
|||||||
lueRun(ctxt);
|
lueRun(ctxt);
|
||||||
lueCtxtDestroy(ctxt);
|
lueCtxtDestroy(ctxt);
|
||||||
|
|
||||||
printf("Period is %d must be 10\n", period);
|
printf("Period is %d must be 10: %s\n", period, 10 == period ? "OK" : "ERROR!");
|
||||||
exit(10 == period ? 0 : 1);
|
exit(10 == period ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user