# HG changeset patch # User jbe # Date 1428276923 -7200 # Node ID 1a0346580e6d1d4c153ad6d10dc4df9191622dc7 # Parent 22dbb9d09f02bcb9122be8e7b6bc7e66a8ad121b Blocking :write(...) and :flush(...) methods in I/O library diff -r 22dbb9d09f02 -r 1a0346580e6d moonbridge_io.c --- a/moonbridge_io.c Sun Apr 05 18:01:31 2015 +0200 +++ b/moonbridge_io.c Mon Apr 06 01:35:23 2015 +0200 @@ -14,20 +14,128 @@ #include #include +#define MOONBR_IO_MAXSTRERRORLEN 80 +#define MOONBR_IO_WRITEBUFLEN 4096 + +#define moonbr_io_errmsg() \ + char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \ + strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN) + + #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle" #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public" typedef struct { int fd; + int writecnt; + char writebuf[MOONBR_IO_WRITEBUFLEN]; } moonbr_io_handle_t; -void moonbr_io_pushhandle(lua_State *L, int fd) { +static int moonbr_io_close(lua_State *L) { + moonbr_io_handle_t *handle; + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); + if (handle->fd < 0) luaL_error(L, "Attempt to close a closed I/O handle"); + if (close(handle->fd)) { + handle->fd = -1; + moonbr_io_errmsg(); + lua_pushnil(L); + lua_pushstring(L, errmsg); + return 2; + } + handle->fd = -1; + lua_pushboolean(L, 1); + return 1; +} + +static int moonbr_io_write(lua_State *L) { + moonbr_io_handle_t *handle; + int i, top; + const char *str; + size_t strlen; + size_t written; + ssize_t result; + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); + if (handle->writecnt < 0) { + lua_pushnil(L); + lua_pushliteral(L, "Previous write error"); + return 2; + } + top = lua_gettop(L); + for (i=2; i<=top; i++) { + str = luaL_checklstring(L, i, &strlen); + while (strlen) { + if (strlen < MOONBR_IO_WRITEBUFLEN - handle->writecnt) { + memcpy(handle->writebuf + handle->writecnt, str, strlen); + handle->writecnt += strlen; + break; + } else { + written = 0; + memcpy(handle->writebuf + handle->writecnt, str, MOONBR_IO_WRITEBUFLEN - handle->writecnt); + while (written < MOONBR_IO_WRITEBUFLEN) { + result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written); + if (result < 0) { + if (errno != EINTR) { + moonbr_io_errmsg(); + handle->writecnt = -1; + lua_pushnil(L); + lua_pushstring(L, errmsg); + return 2; + } + } else { + written += result; + } + } + str += MOONBR_IO_WRITEBUFLEN - handle->writecnt; + strlen -= MOONBR_IO_WRITEBUFLEN - handle->writecnt; + handle->writecnt = 0; + } + } + } + lua_settop(L, 1); + return 1; +} + +static int moonbr_io_flush(lua_State *L) { + moonbr_io_handle_t *handle; + size_t written; + ssize_t result; + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); + if (handle->writecnt < 0) { + lua_pushnil(L); + lua_pushliteral(L, "Previous write error"); + return 2; + } + written = 0; + while (written < handle->writecnt) { + result = write(handle->fd, handle->writebuf + written, handle->writecnt - written); + if (result < 0) { + if (errno != EINTR) { + moonbr_io_errmsg(); + handle->writecnt = -1; + lua_pushnil(L); + lua_pushstring(L, errmsg); + return 2; + } + } else { + written += result; + } + } + handle->writecnt = 0; + lua_settop(L, 1); + return 1; +} + +void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx) { moonbr_io_handle_t *handle; handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); handle->fd = fd; + handle->writecnt = 0; luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY); lua_setmetatable(L, -2); lua_newtable(L); // uservalue + if (gc_idx) lua_pushvalue(L, gc_idx); + else lua_pushcfunction(L, moonbr_io_close); + lua_setfield(L, -2, "gc"); lua_newtable(L); // public luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); lua_setmetatable(L, -2); @@ -36,6 +144,7 @@ } static int moonbr_io_handleindex(lua_State *L) { + luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); lua_getuservalue(L, 1); lua_getfield(L, -1, "public"); lua_pushvalue(L, 2); @@ -44,6 +153,7 @@ } static int moonbr_io_handlenewindex(lua_State *L) { + luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); lua_getuservalue(L, 1); lua_getfield(L, -1, "public"); lua_pushvalue(L, 2); @@ -52,24 +162,34 @@ return 0; } +static int moonbr_io_handlegc(lua_State *L) { + moonbr_io_handle_t *handle; + handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); + if (handle->fd >= 0) { + lua_getuservalue(L, 1); + lua_getfield(L, -1, "gc"); + lua_pushvalue(L, 1); + lua_call(L, 1, 0); + } + return 0; +} + static int moonbr_io_getdummy(lua_State *L) { - moonbr_io_pushhandle(L, 1); + moonbr_io_pushhandle(L, 2, 0); return 1; } -static int moonbr_io_testmethod(lua_State *L) { - fprintf(stderr, "DEBUG\n"); - return 0; -} - static const struct luaL_Reg moonbr_io_handle_methods[] = { - {"testmethod", moonbr_io_testmethod}, + {"close", moonbr_io_close}, + {"write", moonbr_io_write}, + {"flush", moonbr_io_flush}, {NULL, NULL} }; static const struct luaL_Reg moonbr_io_handle_metamethods[] = { {"__index", moonbr_io_handleindex}, {"__newindex", moonbr_io_handlenewindex}, + {"__gc", moonbr_io_handlegc}, {NULL, NULL} }; @@ -80,9 +200,13 @@ int luaopen_moonbridge_io(lua_State *L) { + lua_newtable(L); // module + lua_newtable(L); // public metatable lua_newtable(L); // handle methods luaL_setfuncs(L, moonbr_io_handle_methods, 0); + lua_pushvalue(L, -1); + lua_setfield(L, -4, "handle"); lua_setfield(L, -2, "__index"); lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY); @@ -90,7 +214,6 @@ luaL_setfuncs(L, moonbr_io_handle_metamethods, 0); lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY); - lua_newtable(L); // module luaL_setfuncs(L, moonbr_io_module_funcs, 0); return 1; diff -r 22dbb9d09f02 -r 1a0346580e6d moonbridge_io.h --- a/moonbridge_io.h Sun Apr 05 18:01:31 2015 +0200 +++ b/moonbridge_io.h Mon Apr 06 01:35:23 2015 +0200 @@ -1,4 +1,4 @@ -void moonbr_io_pushhandle(lua_State *L, int fd); +void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx); int luaopen_moonbridge_io(lua_State *L);