moonbridge
changeset 81:e1aec772a6ab
Implementation of write, write_nb, flush, flush_nb with double buffering technique
author | jbe |
---|---|
date | Mon Apr 06 03:36:37 2015 +0200 (2015-04-06) |
parents | 1a0346580e6d |
children | 069ee3f5ab17 |
files | moonbridge_io.c |
line diff
1.1 --- a/moonbridge_io.c Mon Apr 06 01:35:23 2015 +0200 1.2 +++ b/moonbridge_io.c Mon Apr 06 03:36:37 2015 +0200 1.3 @@ -9,6 +9,7 @@ 1.4 #include <sys/time.h> 1.5 #include <sys/socket.h> 1.6 #include <sys/select.h> 1.7 +#include <fcntl.h> 1.8 1.9 #include <lua.h> 1.10 #include <lauxlib.h> 1.11 @@ -27,10 +28,31 @@ 1.12 1.13 typedef struct { 1.14 int fd; 1.15 - int writecnt; 1.16 + int nonblocking; 1.17 + int writeerr; 1.18 + int writeleft; 1.19 + int writeqoff; 1.20 + int writebufcnt; 1.21 char writebuf[MOONBR_IO_WRITEBUFLEN]; 1.22 } moonbr_io_handle_t; 1.23 1.24 +static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) { 1.25 + if (handle->nonblocking != nonblocking) { 1.26 + int flags; 1.27 + flags = fcntl(handle->fd, F_GETFL, 0); 1.28 + if (flags == -1) { 1.29 + moonbr_io_errmsg(); 1.30 + luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); 1.31 + } 1.32 + if (nonblocking) flags |= O_NONBLOCK; 1.33 + else flags &= ~O_NONBLOCK; 1.34 + if (fcntl(handle->fd, F_SETFL, flags) == -1) { 1.35 + moonbr_io_errmsg(); 1.36 + luaL_error(L, "Unexpected error in fcntl call: %s", errmsg); 1.37 + } 1.38 + } 1.39 +} 1.40 + 1.41 static int moonbr_io_close(lua_State *L) { 1.42 moonbr_io_handle_t *handle; 1.43 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 1.44 @@ -47,92 +69,148 @@ 1.45 return 1; 1.46 } 1.47 1.48 -static int moonbr_io_write(lua_State *L) { 1.49 +static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) { 1.50 moonbr_io_handle_t *handle; 1.51 int i, top; 1.52 + lua_Integer qlen, qpos, qpos2; 1.53 const char *str; 1.54 - size_t strlen; 1.55 + size_t strlen, strpos; 1.56 size_t written; 1.57 ssize_t result; 1.58 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 1.59 - if (handle->writecnt < 0) { 1.60 + if (handle->writeerr) { 1.61 lua_pushnil(L); 1.62 lua_pushliteral(L, "Previous write error"); 1.63 return 2; 1.64 } 1.65 - top = lua_gettop(L); 1.66 - for (i=2; i<=top; i++) { 1.67 - str = luaL_checklstring(L, i, &strlen); 1.68 - while (strlen) { 1.69 - if (strlen < MOONBR_IO_WRITEBUFLEN - handle->writecnt) { 1.70 - memcpy(handle->writebuf + handle->writecnt, str, strlen); 1.71 - handle->writecnt += strlen; 1.72 + moonbr_io_handle_set_nonblocking(L, handle, nonblocking); 1.73 + if (!flush) top = lua_gettop(L); 1.74 + lua_getuservalue(L, 1); 1.75 + lua_getfield(L, -1, "writebuf"); 1.76 + qlen = lua_rawlen(L, -1); 1.77 + if (!flush) { 1.78 + for (i=2; i<=top; i++) { 1.79 + luaL_checklstring(L, i, &strlen); 1.80 + lua_pushvalue(L, i); 1.81 + lua_rawseti(L, -2, ++qlen); 1.82 + handle->writeleft += strlen; 1.83 + } 1.84 + } 1.85 + for (qpos=1; qpos<=qlen; qpos++) { 1.86 + lua_rawgeti(L, -1, qpos); 1.87 + str = lua_tolstring(L, -1, &strlen); 1.88 + strpos = handle->writeqoff; 1.89 + while (strpos < strlen) { 1.90 + if (strlen - strpos < MOONBR_IO_WRITEBUFLEN - handle->writebufcnt) { 1.91 + memcpy(handle->writebuf + handle->writebufcnt, str + strpos, strlen - strpos); 1.92 + handle->writebufcnt += strlen - strpos; 1.93 break; 1.94 } else { 1.95 written = 0; 1.96 - memcpy(handle->writebuf + handle->writecnt, str, MOONBR_IO_WRITEBUFLEN - handle->writecnt); 1.97 + memcpy(handle->writebuf + handle->writebufcnt, str + strpos, MOONBR_IO_WRITEBUFLEN - handle->writebufcnt); 1.98 + strpos += MOONBR_IO_WRITEBUFLEN - handle->writebufcnt; 1.99 while (written < MOONBR_IO_WRITEBUFLEN) { 1.100 result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written); 1.101 if (result < 0) { 1.102 - if (errno != EINTR) { 1.103 + if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { 1.104 + if (written) { 1.105 + handle->writebufcnt -= written; 1.106 + memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt); 1.107 + } 1.108 + if (i > 1) { 1.109 + for (qpos2=1; qpos2<=qlen; qpos2++) { 1.110 + if (qpos2+qpos-1 <= qlen) lua_rawgeti(L, -1, qpos2+qpos-1); 1.111 + else lua_pushnil(L); 1.112 + lua_rawseti(L, -2, qpos2); 1.113 + } 1.114 + } 1.115 + handle->writeqoff = strpos; 1.116 + goto moonbr_io_write_impl_block; 1.117 + } else if (errno != EINTR) { 1.118 moonbr_io_errmsg(); 1.119 - handle->writecnt = -1; 1.120 + handle->writeerr = 1; 1.121 lua_pushnil(L); 1.122 lua_pushstring(L, errmsg); 1.123 return 2; 1.124 } 1.125 } else { 1.126 written += result; 1.127 + handle->writeleft -= result; 1.128 } 1.129 } 1.130 - str += MOONBR_IO_WRITEBUFLEN - handle->writecnt; 1.131 - strlen -= MOONBR_IO_WRITEBUFLEN - handle->writecnt; 1.132 - handle->writecnt = 0; 1.133 + handle->writebufcnt = 0; 1.134 } 1.135 } 1.136 + handle->writeqoff = 0; 1.137 + lua_pop(L, 1); 1.138 + lua_pushnil(L); 1.139 + lua_rawseti(L, -2, qpos); 1.140 } 1.141 - lua_settop(L, 1); 1.142 + if (flush) { 1.143 + written = 0; 1.144 + while (written < handle->writebufcnt) { 1.145 + result = write(handle->fd, handle->writebuf + written, handle->writebufcnt - written); 1.146 + if (result < 0) { 1.147 + if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) { 1.148 + if (written) { 1.149 + handle->writebufcnt -= written; 1.150 + memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt); 1.151 + } 1.152 + goto moonbr_io_write_impl_block; 1.153 + } else if (errno != EINTR) { 1.154 + moonbr_io_errmsg(); 1.155 + handle->writeerr = -1; 1.156 + lua_pushnil(L); 1.157 + lua_pushstring(L, errmsg); 1.158 + return 2; 1.159 + } 1.160 + } else { 1.161 + written += result; 1.162 + handle->writeleft -= result; 1.163 + } 1.164 + } 1.165 + handle->writebufcnt = 0; 1.166 + lua_pushinteger(L, 0); 1.167 + } else { 1.168 + lua_pushinteger(L, handle->writeleft - handle->writebufcnt); 1.169 + } 1.170 return 1; 1.171 + moonbr_io_write_impl_block: 1.172 + if (flush) lua_pushinteger(L, handle->writeleft); 1.173 + else lua_pushinteger(L, handle->writeleft - handle->writebufcnt); 1.174 + return 1; 1.175 +} 1.176 + 1.177 +static int moonbr_io_write(lua_State *L) { 1.178 + return moonbr_io_write_impl(L, 0, 0); 1.179 +} 1.180 + 1.181 +static int moonbr_io_write_nb(lua_State *L) { 1.182 + return moonbr_io_write_impl(L, 1, 0); 1.183 } 1.184 1.185 static int moonbr_io_flush(lua_State *L) { 1.186 - moonbr_io_handle_t *handle; 1.187 - size_t written; 1.188 - ssize_t result; 1.189 - handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY); 1.190 - if (handle->writecnt < 0) { 1.191 - lua_pushnil(L); 1.192 - lua_pushliteral(L, "Previous write error"); 1.193 - return 2; 1.194 - } 1.195 - written = 0; 1.196 - while (written < handle->writecnt) { 1.197 - result = write(handle->fd, handle->writebuf + written, handle->writecnt - written); 1.198 - if (result < 0) { 1.199 - if (errno != EINTR) { 1.200 - moonbr_io_errmsg(); 1.201 - handle->writecnt = -1; 1.202 - lua_pushnil(L); 1.203 - lua_pushstring(L, errmsg); 1.204 - return 2; 1.205 - } 1.206 - } else { 1.207 - written += result; 1.208 - } 1.209 - } 1.210 - handle->writecnt = 0; 1.211 - lua_settop(L, 1); 1.212 - return 1; 1.213 + return moonbr_io_write_impl(L, 0, 1); 1.214 +} 1.215 + 1.216 +static int moonbr_io_flush_nb(lua_State *L) { 1.217 + return moonbr_io_write_impl(L, 1, 1); 1.218 } 1.219 1.220 void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx) { 1.221 moonbr_io_handle_t *handle; 1.222 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t)); 1.223 handle->fd = fd; 1.224 - handle->writecnt = 0; 1.225 + handle->nonblocking = -1; 1.226 + handle->writeerr = 0; 1.227 + handle->writeleft = 0; 1.228 + handle->writeqoff = 0; 1.229 + handle->writebufcnt = 0; 1.230 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY); 1.231 lua_setmetatable(L, -2); 1.232 lua_newtable(L); // uservalue 1.233 + lua_newtable(L); 1.234 + lua_setfield(L, -2, "writebuf"); 1.235 if (gc_idx) lua_pushvalue(L, gc_idx); 1.236 else lua_pushcfunction(L, moonbr_io_close); 1.237 lua_setfield(L, -2, "gc"); 1.238 @@ -182,7 +260,9 @@ 1.239 static const struct luaL_Reg moonbr_io_handle_methods[] = { 1.240 {"close", moonbr_io_close}, 1.241 {"write", moonbr_io_write}, 1.242 + {"write_nb", moonbr_io_write_nb}, 1.243 {"flush", moonbr_io_flush}, 1.244 + {"flush_nb", moonbr_io_flush_nb}, 1.245 {NULL, NULL} 1.246 }; 1.247