moonbridge
changeset 64:5df424e74383
Work on support for non-blocking I/O
author | jbe |
---|---|
date | Sat Apr 04 01:38:25 2015 +0200 (2015-04-04) |
parents | 12950c28b73a |
children | 8090fe97518a |
files | moonbridge.c |
line diff
1.1 --- a/moonbridge.c Mon Mar 30 00:44:18 2015 +0200 1.2 +++ b/moonbridge.c Sat Apr 04 01:38:25 2015 +0200 1.3 @@ -2202,6 +2202,27 @@ 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 @@ -2236,8 +2257,164 @@ 1.32 return ptr; 1.33 } 1.34 1.35 +/* New function io.poll(...) */ 1.36 +static int moonbr_io_poll(lua_State *L) { 1.37 + int idx_tbl = 1; 1.38 + int idx_timeout = 0; 1.39 + int i; 1.40 + int fd, isnum; 1.41 + int nfds = 0; 1.42 + fd_set readfds, writefds, exceptfds; 1.43 + struct timeval timeout = {0, }; 1.44 + int status; 1.45 + FD_ZERO(&readfds); 1.46 + FD_ZERO(&writefds); 1.47 + FD_ZERO(&exceptfds); 1.48 + if (lua_type(L, 1) == LUA_TNUMBER) { 1.49 + idx_timeout = 1; 1.50 + idx_tbl = 2; 1.51 + } 1.52 + luaL_checktype(L, idx_tbl, LUA_TTABLE); 1.53 + for (i=1; ; i++) { 1.54 +#if LUA_VERSION_NUM >= 503 1.55 + if (lua_geti(L, idx_tbl, i) == LUA_TNIL) break; 1.56 +#else 1.57 + lua_pushinteger(L, i); 1.58 + lua_gettable(L, idx_tbl); 1.59 + if (lua_isnil(L, -1)) break; 1.60 +#endif 1.61 + fd = lua_tointegerx(L, -1, &isnum); 1.62 + if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.63 + FD_SET(fd, &readfds); 1.64 + if (fd+1 > nfds) nfds = fd+1; 1.65 + lua_pop(L, 1); 1.66 + } 1.67 + if (!idx_timeout && lua_type(L, 2) == LUA_TNUMBER) { 1.68 + idx_timeout = 2; 1.69 + idx_tbl = 3; 1.70 + } else { 1.71 + idx_tbl = 2; 1.72 + } 1.73 + luaL_checktype(L, idx_tbl, LUA_TTABLE); 1.74 + for (i=1; ; i++) { 1.75 +#if LUA_VERSION_NUM >= 503 1.76 + if (lua_geti(L, idx_tbl, i) == LUA_TNIL) break; 1.77 +#else 1.78 + lua_pushinteger(L, i); 1.79 + lua_gettable(L, idx_tbl); 1.80 + if (lua_isnil(L, -1)) break; 1.81 +#endif 1.82 + fd = lua_tointegerx(L, -1, &isnum); 1.83 + if (!isnum) luaL_error(L, "File descriptor is not an integer"); 1.84 + FD_SET(fd, &writefds); 1.85 + if (fd+1 > nfds) nfds = fd+1; 1.86 + lua_pop(L, 1); 1.87 + } 1.88 + lua_pop(L, 2); 1.89 + if (!idx_timeout && !lua_isnoneornil(L, 3)) idx_timeout = 3; 1.90 + if (idx_timeout) { 1.91 + luaL_argcheck( 1.92 + L, 1.93 + moonbr_lua_totimeval(L, idx_timeout, &timeout), 1.94 + idx_timeout, 1.95 + "not a valid timeout" 1.96 + ); 1.97 + } 1.98 + status = select(nfds, &readfds, &writefds, &exceptfds, &timeout); 1.99 + if (status == -1) { 1.100 + if (errno == EINTR) { 1.101 + lua_pushboolean(L, 0); 1.102 + } else { 1.103 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.104 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.105 + luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg); 1.106 + } 1.107 + } else if (status == 0) { 1.108 + lua_pushboolean(L, 0); 1.109 + } else { 1.110 + lua_pushboolean(L, 1); 1.111 + } 1.112 + return 1; 1.113 +} 1.114 + 1.115 +/* New method for Lua file objects: get file descriptor */ 1.116 +static int moonbr_io_getfd(lua_State *L) { 1.117 + luaL_Stream *stream; 1.118 + stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.119 + if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.120 + lua_pushinteger(L, fileno(stream->f)); 1.121 + return 1; 1.122 +} 1.123 + 1.124 +/* New method for Lua file objects: check if non-blocking reading is possible */ 1.125 +static int moonbr_io_pending(lua_State *L) { 1.126 + luaL_Stream *stream; 1.127 + FILE *file; 1.128 + int fd, flags, chr; 1.129 + stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.130 + if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.131 + file = stream->f; 1.132 + flockfile(file); 1.133 + fd = fileno_unlocked(file); 1.134 + if (ferror(file) || feof(file)) { 1.135 + funlockfile(file); 1.136 + lua_pushboolean(L, 1); 1.137 + return 1; 1.138 + } 1.139 + flags = fcntl(fd, F_GETFL, 0); 1.140 + if (flags == -1) goto moonbr_io_pending_error; 1.141 + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_pending_error; 1.142 + chr = getc_unlocked(file); 1.143 + lua_pushboolean(L, 1); 1.144 + if (chr == EOF) { 1.145 + if (ferror(file) && errno == EAGAIN) { 1.146 + clearerr_unlocked(file); 1.147 + lua_pushboolean(L, 0); 1.148 + } 1.149 + } else { 1.150 + if (ungetc(chr, file) == EOF) goto moonbr_io_pending_error; 1.151 + } 1.152 + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_pending_error; 1.153 + funlockfile(file); 1.154 + return 1; 1.155 + moonbr_io_pending_error: 1.156 + funlockfile(file); 1.157 + { 1.158 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.159 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.160 + luaL_error(L, "Unexpected error in method \"pending\" of FILE handle: %s", errmsg); 1.161 + } 1.162 + return 0; 1.163 +} 1.164 + 1.165 +/* New method for Lua file objects: set blocking or non-blocking I/O */ 1.166 +static int moonbr_io_setblocking(lua_State *L) { 1.167 + luaL_Stream *stream; 1.168 + int blocking; 1.169 + int fd, flags; 1.170 + stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); 1.171 + luaL_checktype(L, 2, LUA_TBOOLEAN); 1.172 + blocking = lua_toboolean(L, 2); 1.173 + if (!stream->closef) luaL_error(L, "attempt to use a closed file"); 1.174 + fd = fileno_unlocked(stream->f); 1.175 + flags = fcntl(fd, F_GETFL, 0); 1.176 + if (flags == -1) goto moonbr_io_setblocking_error; 1.177 + if (blocking) flags &= ~ O_NONBLOCK; 1.178 + else flags |= O_NONBLOCK; 1.179 + if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_setblocking_error; 1.180 + lua_pushboolean(L, 1); 1.181 + return 1; 1.182 + moonbr_io_setblocking_error: 1.183 + { 1.184 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.185 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.186 + luaL_error(L, "Unexpected error in method \"setblocking\" of FILE handle: %s", errmsg); 1.187 + } 1.188 + return 0; 1.189 +} 1.190 + 1.191 /* New method for Lua file objects: read until terminator or length exceeded */ 1.192 -static int moonbr_readuntil(lua_State *L) { 1.193 +static int moonbr_io_readuntil(lua_State *L) { 1.194 luaL_Stream *stream; 1.195 FILE *file; 1.196 const char *terminatorstr; 1.197 @@ -2276,27 +2453,6 @@ 1.198 return 1; 1.199 } 1.200 1.201 -static int moonbr_lua_tonatural(lua_State *L, int idx) { 1.202 - int isnum; 1.203 - lua_Number n; 1.204 - n = lua_tonumberx(L, idx, &isnum); 1.205 - if (isnum && n>=0 && n<INT_MAX && (lua_Number)(int)n == n) return n; 1.206 - else return -1; 1.207 -} 1.208 - 1.209 -static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) { 1.210 - int isnum; 1.211 - lua_Number n; 1.212 - n = lua_tonumberx(L, idx, &isnum); 1.213 - if (isnum && n>=0 && n<=100000000) { 1.214 - value->tv_sec = n; 1.215 - value->tv_usec = 1e6 * (n - value->tv_sec); 1.216 - return 1; 1.217 - } else { 1.218 - return 0; 1.219 - } 1.220 -} 1.221 - 1.222 static int moonbr_timeout(lua_State *L) { 1.223 struct itimerval oldval; 1.224 if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) { 1.225 @@ -2764,12 +2920,22 @@ 1.226 #ifdef MOONBR_LUA_CPATH 1.227 moonbr_modify_path(L, "cpath", MOONBR_LUA_CPATH); 1.228 #endif 1.229 + lua_getglobal(L, "io"); 1.230 + lua_pushcfunction(L, moonbr_io_poll); 1.231 + lua_setfield(L, -2, "poll"); 1.232 + lua_pop(L, 1); 1.233 if (luaL_newmetatable(L, LUA_FILEHANDLE)) { 1.234 moonbr_log(LOG_CRIT, "Lua metatable LUA_FILEHANDLE does not exist"); 1.235 moonbr_terminate_error(); 1.236 } 1.237 lua_getfield(L, -1, "__index"); 1.238 - lua_pushcfunction(L, moonbr_readuntil); 1.239 + lua_pushcfunction(L, moonbr_io_getfd); 1.240 + lua_setfield(L, -2, "getfd"); 1.241 + lua_pushcfunction(L, moonbr_io_pending); 1.242 + lua_setfield(L, -2, "pending"); 1.243 + lua_pushcfunction(L, moonbr_io_setblocking); 1.244 + lua_setfield(L, -2, "setblocking"); 1.245 + lua_pushcfunction(L, moonbr_io_readuntil); 1.246 lua_setfield(L, -2, "readuntil"); 1.247 lua_pop(L, 2); 1.248 lua_pushcfunction(L, moonbr_timeout);