moonbridge
diff moonbridge.c @ 66:3d1f23f1dbc6
Work on non-blocking I/O; Improved efficiency of :readuntil(...)
author | jbe |
---|---|
date | Sat Apr 04 05:10:05 2015 +0200 (2015-04-04) |
parents | 8090fe97518a |
children | c488f2ea29aa |
line diff
1.1 --- a/moonbridge.c Sat Apr 04 03:22:06 2015 +0200 1.2 +++ b/moonbridge.c Sat Apr 04 05:10:05 2015 +0200 1.3 @@ -2202,27 +2202,6 @@ 1.4 return 1; 1.5 } 1.6 1.7 -static int moonbr_lua_tonatural(lua_State *L, int idx) { 1.8 - int isnum; 1.9 - lua_Number n; 1.10 - n = lua_tonumberx(L, idx, &isnum); 1.11 - if (isnum && n>=0 && n<INT_MAX && (lua_Number)(int)n == n) return n; 1.12 - else return -1; 1.13 -} 1.14 - 1.15 -static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) { 1.16 - int isnum; 1.17 - lua_Number n; 1.18 - n = lua_tonumberx(L, idx, &isnum); 1.19 - if (isnum && n>=0 && n<=100000000) { 1.20 - value->tv_sec = n; 1.21 - value->tv_usec = 1e6 * (n - value->tv_sec); 1.22 - return 1; 1.23 - } else { 1.24 - return 0; 1.25 - } 1.26 -} 1.27 - 1.28 /* Memory allocator that allows limiting memory consumption */ 1.29 static void *moonbr_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { 1.30 (void)ud; /* not used */ 1.31 @@ -2257,11 +2236,33 @@ 1.32 return ptr; 1.33 } 1.34 1.35 +/* Helper function to convert a value at the given stack index to a natural number */ 1.36 +static int moonbr_lua_tonatural(lua_State *L, int idx) { 1.37 + int isnum; 1.38 + lua_Number n; 1.39 + n = lua_tonumberx(L, idx, &isnum); 1.40 + if (isnum && n>=0 && n<INT_MAX && (lua_Number)(int)n == n) return n; 1.41 + else return -1; 1.42 +} 1.43 + 1.44 +/* Helper function to convert a value at the given stack index to a timeval struct */ 1.45 +static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) { 1.46 + int isnum; 1.47 + lua_Number n; 1.48 + n = lua_tonumberx(L, idx, &isnum); 1.49 + if (isnum && n>=0 && n<=100000000) { 1.50 + value->tv_sec = n; 1.51 + value->tv_usec = 1e6 * (n - value->tv_sec); 1.52 + return 1; 1.53 + } else { 1.54 + return 0; 1.55 + } 1.56 +} 1.57 + 1.58 /* New function io.poll(...) */ 1.59 static int moonbr_io_poll(lua_State *L) { 1.60 - int idx_tbl = 1; 1.61 - int idx_timeout = 0; 1.62 int i; 1.63 + luaL_Stream *stream; 1.64 int fd, isnum; 1.65 int nfds = 0; 1.66 fd_set readfds, writefds, exceptfds; 1.67 @@ -2270,82 +2271,73 @@ 1.68 FD_ZERO(&readfds); 1.69 FD_ZERO(&writefds); 1.70 FD_ZERO(&exceptfds); 1.71 - if (lua_type(L, 1) == LUA_TNUMBER) { 1.72 - idx_timeout = 1; 1.73 - idx_tbl = 2; 1.74 - } 1.75 - luaL_checktype(L, idx_tbl, LUA_TTABLE); 1.76 - for (i=1; ; i++) { 1.77 -#if LUA_VERSION_NUM >= 503 1.78 - if (lua_geti(L, idx_tbl, i) == LUA_TNIL) break; 1.79 -#else 1.80 - lua_pushinteger(L, i); 1.81 - lua_gettable(L, idx_tbl); 1.82 - if (lua_isnil(L, -1)) break; 1.83 -#endif 1.84 - fd = lua_tointegerx(L, -1, &isnum); 1.85 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.86 - FD_SET(fd, &readfds); 1.87 - if (fd+1 > nfds) nfds = fd+1; 1.88 - lua_pop(L, 1); 1.89 - } 1.90 - if (!idx_timeout && lua_type(L, 2) == LUA_TNUMBER) { 1.91 - idx_timeout = 2; 1.92 - idx_tbl = 3; 1.93 - } else { 1.94 - idx_tbl = 2; 1.95 - } 1.96 - if (!lua_isnoneornil(L, idx_tbl)) { 1.97 - luaL_checktype(L, idx_tbl, LUA_TTABLE); 1.98 + if (!lua_isnoneornil(L, 1)) { 1.99 + luaL_checktype(L, 1, LUA_TTABLE); 1.100 for (i=1; ; i++) { 1.101 #if LUA_VERSION_NUM >= 503 1.102 - if (lua_geti(L, idx_tbl, i) == LUA_TNIL) break; 1.103 + if (lua_geti(L, 1, i) == LUA_TNIL) break; 1.104 #else 1.105 lua_pushinteger(L, i); 1.106 - lua_gettable(L, idx_tbl); 1.107 + lua_gettable(L, 1); 1.108 if (lua_isnil(L, -1)) break; 1.109 #endif 1.110 - fd = lua_tointegerx(L, -1, &isnum); 1.111 - if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.112 + stream = luaL_testudata(L, -1, LUA_FILEHANDLE); 1.113 + if (stream) { 1.114 + fd = fileno(stream->f); 1.115 + } else { 1.116 + fd = lua_tointegerx(L, -1, &isnum); 1.117 + if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.118 + } 1.119 + FD_SET(fd, &readfds); 1.120 + if (fd+1 > nfds) nfds = fd+1; 1.121 + lua_pop(L, 1); 1.122 + } 1.123 + } 1.124 + if (!lua_isnoneornil(L, 2)) { 1.125 + luaL_checktype(L, 2, LUA_TTABLE); 1.126 + for (i=1; ; i++) { 1.127 +#if LUA_VERSION_NUM >= 503 1.128 + if (lua_geti(L, 2, i) == LUA_TNIL) break; 1.129 +#else 1.130 + lua_pushinteger(L, i); 1.131 + lua_gettable(L, 2); 1.132 + if (lua_isnil(L, -1)) break; 1.133 +#endif 1.134 + stream = luaL_testudata(L, -1, LUA_FILEHANDLE); 1.135 + if (stream) { 1.136 + fd = fileno(stream->f); 1.137 + } else { 1.138 + fd = lua_tointegerx(L, -1, &isnum); 1.139 + if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.140 + } 1.141 FD_SET(fd, &writefds); 1.142 if (fd+1 > nfds) nfds = fd+1; 1.143 lua_pop(L, 1); 1.144 } 1.145 lua_pop(L, 2); 1.146 - if (!idx_timeout && !lua_isnoneornil(L, 3)) idx_timeout = 3; 1.147 } 1.148 - if (idx_timeout) { 1.149 - luaL_argcheck( 1.150 - L, 1.151 - moonbr_lua_totimeval(L, idx_timeout, &timeout), 1.152 - idx_timeout, 1.153 - "not a valid timeout" 1.154 - ); 1.155 + if (!lua_isnoneornil(L, 3)) { 1.156 + luaL_argcheck(L, moonbr_lua_totimeval(L, 3, &timeout), 3, "not a valid timeout"); 1.157 } 1.158 status = select(nfds, &readfds, &writefds, &exceptfds, &timeout); 1.159 if (status == -1) { 1.160 if (errno == EINTR) { 1.161 lua_pushboolean(L, 0); 1.162 + lua_pushliteral(L, "Signal received while polling file descriptors"); 1.163 + return 2; 1.164 } else { 1.165 char errmsg[MOONBR_MAXSTRERRORLEN]; 1.166 strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.167 - luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg); 1.168 + return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg); 1.169 } 1.170 } else if (status == 0) { 1.171 lua_pushboolean(L, 0); 1.172 + lua_pushliteral(L, "Timeout while polling file descriptors"); 1.173 + return 2; 1.174 } else { 1.175 lua_pushboolean(L, 1); 1.176 + return 1; 1.177 } 1.178 - return 1; 1.179 -} 1.180 - 1.181 -/* New method for Lua file objects: get file descriptor */ 1.182 -static int moonbr_io_getfd(lua_State *L) { 1.183 - luaL_Stream *stream; 1.184 - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.185 - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.186 - lua_pushinteger(L, fileno(stream->f)); 1.187 - return 1; 1.188 } 1.189 1.190 /* New method for Lua file objects: check if non-blocking reading is possible */ 1.191 @@ -2389,32 +2381,6 @@ 1.192 return 0; 1.193 } 1.194 1.195 -/* New method for Lua file objects: set blocking or non-blocking I/O */ 1.196 -static int moonbr_io_setblocking(lua_State *L) { 1.197 - luaL_Stream *stream; 1.198 - int blocking; 1.199 - int fd, flags; 1.200 - stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.201 - luaL_checktype(L, 2, LUA_TBOOLEAN); 1.202 - blocking = lua_toboolean(L, 2); 1.203 - if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.204 - fd = fileno_unlocked(stream->f); 1.205 - flags = fcntl(fd, F_GETFL, 0); 1.206 - if (flags == -1) goto moonbr_io_setblocking_error; 1.207 - if (blocking) flags &= ~ O_NONBLOCK; 1.208 - else flags |= O_NONBLOCK; 1.209 - if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_setblocking_error; 1.210 - lua_pushboolean(L, 1); 1.211 - return 1; 1.212 - moonbr_io_setblocking_error: 1.213 - { 1.214 - char errmsg[MOONBR_MAXSTRERRORLEN]; 1.215 - strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.216 - luaL_error(L, "Unexpected error in method \"setblocking\" of FILE handle: %s", errmsg); 1.217 - } 1.218 - return 0; 1.219 -} 1.220 - 1.221 /* New method for Lua file objects: read until terminator or length exceeded */ 1.222 static int moonbr_io_readuntil(lua_State *L) { 1.223 luaL_Stream *stream; 1.224 @@ -2434,12 +2400,14 @@ 1.225 luaL_buffinit(L, &buf); 1.226 if (!maxlen) maxlen = -1; 1.227 terminator = terminatorstr[0]; 1.228 + flockfile(file); 1.229 while (maxlen > 0 ? maxlen-- : maxlen) { 1.230 - byte = fgetc(file); 1.231 + byte = getc_unlocked(file); 1.232 if (byte == EOF) { 1.233 if (ferror(file)) { 1.234 char errmsg[MOONBR_MAXSTRERRORLEN]; 1.235 strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.236 + funlockfile(file); 1.237 lua_pushnil(L); 1.238 lua_pushstring(L, errmsg); 1.239 return 2; 1.240 @@ -2450,6 +2418,7 @@ 1.241 luaL_addchar(&buf, byte); 1.242 if (byte == terminator) break; 1.243 } 1.244 + funlockfile(file); 1.245 luaL_pushresult(&buf); 1.246 if (!lua_rawlen(L, -1)) lua_pushnil(L); 1.247 return 1; 1.248 @@ -2931,12 +2900,8 @@ 1.249 moonbr_terminate_error(); 1.250 } 1.251 lua_getfield(L, -1, "__index"); 1.252 - lua_pushcfunction(L, moonbr_io_getfd); 1.253 - lua_setfield(L, -2, "getfd"); 1.254 - lua_pushcfunction(L, moonbr_io_pending); 1.255 + eua_pushcfunction(L, moonbr_io_pending); 1.256 lua_setfield(L, -2, "pending"); 1.257 - lua_pushcfunction(L, moonbr_io_setblocking); 1.258 - lua_setfield(L, -2, "setblocking"); 1.259 lua_pushcfunction(L, moonbr_io_readuntil); 1.260 lua_setfield(L, -2, "readuntil"); 1.261 lua_pop(L, 2);