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);

Impressum / About Us