moonbridge

diff moonbridge.c @ 78:0ec070d6f5d9

Reverted experimental work on non-blocking I/O with file handles
author jbe
date Sun Apr 05 15:15:06 2015 +0200 (2015-04-05)
parents 38e7bd13200d
children 22dbb9d09f02
line diff
     1.1 --- a/moonbridge.c	Sun Apr 05 01:17:06 2015 +0200
     1.2 +++ b/moonbridge.c	Sun Apr 05 15:15:06 2015 +0200
     1.3 @@ -936,20 +936,10 @@
     1.4    return lua_gettop(L);
     1.5  }
     1.6  
     1.7 -/* Lua method for socket object to read from input stream using xread */
     1.8 -static int moonbr_child_lua_xread_stream(lua_State *L) {
     1.9 +/* Lua method for socket object to read from input stream until terminator */
    1.10 +static int moonbr_child_lua_readuntil_stream(lua_State *L) {
    1.11    lua_getfield(L, 1, "input");
    1.12 -  lua_getfield(L, -1, "xread");
    1.13 -  lua_insert(L, 1);
    1.14 -  lua_replace(L, 2);
    1.15 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
    1.16 -  return lua_gettop(L);
    1.17 -}
    1.18 -
    1.19 -/* Lua method for socket object to read from input stream using xread_nb */
    1.20 -static int moonbr_child_lua_xread_nb_stream(lua_State *L) {
    1.21 -  lua_getfield(L, 1, "input");
    1.22 -  lua_getfield(L, -1, "xread_nb");
    1.23 +  lua_getfield(L, -1, "readuntil");
    1.24    lua_insert(L, 1);
    1.25    lua_replace(L, 2);
    1.26    lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
    1.27 @@ -976,16 +966,6 @@
    1.28    return lua_gettop(L);
    1.29  }
    1.30  
    1.31 -/* Lua method for socket object to write to output stream using write_nb */
    1.32 -static int moonbr_child_lua_write_nb_stream(lua_State *L) {
    1.33 -  lua_getfield(L, 1, "output");
    1.34 -  lua_getfield(L, -1, "write_nb");
    1.35 -  lua_insert(L, 1);
    1.36 -  lua_replace(L, 2);
    1.37 -  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
    1.38 -  return lua_gettop(L);
    1.39 -}
    1.40 -
    1.41  /* Lua method for socket object to flush the output stream */
    1.42  static int moonbr_child_lua_flush_stream(lua_State *L) {
    1.43    lua_getfield(L, 1, "output");
    1.44 @@ -1062,15 +1042,13 @@
    1.45  
    1.46  /* Methods of (bidirectional) socket object passed to handler */
    1.47  static luaL_Reg moonbr_child_lua_socket_functions[] = {
    1.48 -  {"read",     moonbr_child_lua_read_stream},
    1.49 -  {"xread",    moonbr_child_lua_xread_stream},
    1.50 -  {"xread_nb", moonbr_child_lua_xread_nb_stream},
    1.51 -  {"lines",    moonbr_child_lua_lines_stream},
    1.52 -  {"write",    moonbr_child_lua_write_stream},
    1.53 -  {"write_nb", moonbr_child_lua_write_nb_stream},
    1.54 -  {"flush",    moonbr_child_lua_flush_stream},
    1.55 -  {"close",    moonbr_child_lua_close_both_streams},
    1.56 -  {"cancel",   moonbr_child_lua_cancel_both_streams},
    1.57 +  {"read", moonbr_child_lua_read_stream},
    1.58 +  {"readuntil", moonbr_child_lua_readuntil_stream},
    1.59 +  {"lines", moonbr_child_lua_lines_stream},
    1.60 +  {"write", moonbr_child_lua_write_stream},
    1.61 +  {"flush", moonbr_child_lua_flush_stream},
    1.62 +  {"close", moonbr_child_lua_close_both_streams},
    1.63 +  {"cancel", moonbr_child_lua_cancel_both_streams},
    1.64    {NULL, NULL}
    1.65  };
    1.66  
    1.67 @@ -2258,7 +2236,46 @@
    1.68    return ptr;
    1.69  }
    1.70  
    1.71 -/* Helper function to convert a value at the given stack index to a natural number */
    1.72 +/* New method for Lua file objects: read until terminator or length exceeded */
    1.73 +static int moonbr_readuntil(lua_State *L) {
    1.74 +  luaL_Stream *stream;
    1.75 +  FILE *file;
    1.76 +  const char *terminatorstr;
    1.77 +  size_t terminatorlen;
    1.78 +  luaL_Buffer buf;
    1.79 +  lua_Integer maxlen;
    1.80 +  char terminator;
    1.81 +  int byte;
    1.82 +  stream = luaL_checkudata(L, 1, LUA_FILEHANDLE);
    1.83 +  terminatorstr = luaL_checklstring(L, 2, &terminatorlen);
    1.84 +  luaL_argcheck(L, terminatorlen == 1, 2, "single byte expected");
    1.85 +  maxlen = luaL_optinteger(L, 3, 0);
    1.86 +  if (!stream->closef) luaL_error(L, "attempt to use a closed file");
    1.87 +  file = stream->f;
    1.88 +  luaL_buffinit(L, &buf);
    1.89 +  if (!maxlen) maxlen = -1;
    1.90 +  terminator = terminatorstr[0];
    1.91 +  while (maxlen > 0 ? maxlen-- : maxlen) {
    1.92 +    byte = fgetc(file);
    1.93 +    if (byte == EOF) {
    1.94 +      if (ferror(file)) {
    1.95 +        char errmsg[MOONBR_MAXSTRERRORLEN];
    1.96 +        strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
    1.97 +        lua_pushnil(L);
    1.98 +        lua_pushstring(L, errmsg);
    1.99 +        return 2;
   1.100 +      } else {
   1.101 +        break;
   1.102 +      }
   1.103 +    }
   1.104 +    luaL_addchar(&buf, byte);
   1.105 +    if (byte == terminator) break;
   1.106 +  }
   1.107 +  luaL_pushresult(&buf);
   1.108 +  if (!lua_rawlen(L, -1)) lua_pushnil(L);
   1.109 +  return 1;
   1.110 +}
   1.111 +
   1.112  static int moonbr_lua_tonatural(lua_State *L, int idx) {
   1.113    int isnum;
   1.114    lua_Number n;
   1.115 @@ -2267,7 +2284,6 @@
   1.116    else return -1;
   1.117  }
   1.118  
   1.119 -/* Helper function to convert a value at the given stack index to a timeval struct */
   1.120  static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) {
   1.121    int isnum;
   1.122    lua_Number n;
   1.123 @@ -2281,275 +2297,6 @@
   1.124    }
   1.125  }
   1.126  
   1.127 -/* New function io.poll(...) */
   1.128 -static int moonbr_io_poll(lua_State *L) {
   1.129 -  int i;
   1.130 -  luaL_Stream *stream;
   1.131 -  int fd, isnum;
   1.132 -  int nfds = 0;
   1.133 -  fd_set readfds, writefds, exceptfds;
   1.134 -  struct timeval timeout = {0, };
   1.135 -  int status;
   1.136 -  FD_ZERO(&readfds);
   1.137 -  FD_ZERO(&writefds);
   1.138 -  FD_ZERO(&exceptfds);
   1.139 -  if (!lua_isnoneornil(L, 1)) {
   1.140 -    luaL_checktype(L, 1, LUA_TTABLE);
   1.141 -    for (i=1; ; i++) {
   1.142 -#if LUA_VERSION_NUM >= 503
   1.143 -      if (lua_geti(L, 1, i) == LUA_TNIL) break;
   1.144 -#else
   1.145 -      lua_pushinteger(L, i);
   1.146 -      lua_gettable(L, 1);
   1.147 -      if (lua_isnil(L, -1)) break;
   1.148 -#endif
   1.149 -      stream = luaL_testudata(L, -1, LUA_FILEHANDLE);
   1.150 -      if (stream) {
   1.151 -        /* in case of file handle, check for pending data in buffer */
   1.152 -        FILE *file = stream->f;
   1.153 -        int flags, chr;
   1.154 -        flockfile(file);
   1.155 -        fd = fileno_unlocked(file);
   1.156 -        if (ferror(file) || feof(file)) goto moonbr_io_poll_pending_shortcut1;
   1.157 -        flags = fcntl(fd, F_GETFL, 0);
   1.158 -        if (flags == -1) goto moonbr_io_poll_pending_error;
   1.159 -        if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_poll_pending_error;
   1.160 -        chr = getc_unlocked(file);
   1.161 -        if (chr == EOF) {
   1.162 -          if (ferror(file) && errno == EAGAIN) clearerr_unlocked(file);
   1.163 -          else goto moonbr_io_poll_pending_shortcut2;
   1.164 -        } else {
   1.165 -          if (ungetc(chr, file) == EOF) {
   1.166 -            fcntl(fd, F_SETFL, flags);
   1.167 -            goto moonbr_io_poll_pending_error;
   1.168 -          }
   1.169 -          goto moonbr_io_poll_pending_shortcut2;
   1.170 -        }
   1.171 -        if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_poll_pending_error;
   1.172 -        funlockfile(file);
   1.173 -        goto moonbr_io_poll_pending_cont;
   1.174 -        moonbr_io_poll_pending_shortcut2:
   1.175 -        if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_poll_pending_error;
   1.176 -        moonbr_io_poll_pending_shortcut1:
   1.177 -        funlockfile(file);
   1.178 -        lua_pushboolean(L, 1);
   1.179 -        return 1;
   1.180 -        moonbr_io_poll_pending_error:
   1.181 -        funlockfile(file);
   1.182 -        {
   1.183 -          char errmsg[MOONBR_MAXSTRERRORLEN];
   1.184 -          strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.185 -          return luaL_error(L, "Unexpected error while checking buffer of FILE handle: %s", errmsg);
   1.186 -        }
   1.187 -      }
   1.188 -      fd = lua_tointegerx(L, -1, &isnum);
   1.189 -      if (!isnum) luaL_error(L, "File descriptor is not an integer");
   1.190 -      moonbr_io_poll_pending_cont:
   1.191 -      FD_SET(fd, &readfds);
   1.192 -      if (fd+1 > nfds) nfds = fd+1;
   1.193 -      lua_pop(L, 1);
   1.194 -    }
   1.195 -  }
   1.196 -  if (!lua_isnoneornil(L, 2)) {
   1.197 -    luaL_checktype(L, 2, LUA_TTABLE);
   1.198 -    for (i=1; ; i++) {
   1.199 -#if LUA_VERSION_NUM >= 503
   1.200 -      if (lua_geti(L, 2, i) == LUA_TNIL) break;
   1.201 -#else
   1.202 -      lua_pushinteger(L, i);
   1.203 -      lua_gettable(L, 2);
   1.204 -      if (lua_isnil(L, -1)) break;
   1.205 -#endif
   1.206 -      stream = luaL_testudata(L, -1, LUA_FILEHANDLE);
   1.207 -      if (stream) {
   1.208 -        fd = fileno(stream->f);
   1.209 -      } else {
   1.210 -        fd = lua_tointegerx(L, -1, &isnum);
   1.211 -        if (!isnum) luaL_error(L, "File descriptor is not an integer");
   1.212 -      }
   1.213 -      FD_SET(fd, &writefds);
   1.214 -      if (fd+1 > nfds) nfds = fd+1;
   1.215 -      lua_pop(L, 1);
   1.216 -    }
   1.217 -    lua_pop(L, 2);
   1.218 -  }
   1.219 -  if (!lua_isnoneornil(L, 3)) {
   1.220 -    luaL_argcheck(L, moonbr_lua_totimeval(L, 3, &timeout), 3, "not a valid timeout");
   1.221 -  }
   1.222 -  status = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
   1.223 -  if (status == -1) {
   1.224 -    if (errno == EINTR) {
   1.225 -      lua_pushboolean(L, 0);
   1.226 -      lua_pushliteral(L, "Signal received while polling file descriptors");
   1.227 -      return 2;
   1.228 -    } else {
   1.229 -      char errmsg[MOONBR_MAXSTRERRORLEN];
   1.230 -      strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.231 -      return luaL_error(L, "Unexpected error during \"select\" system call: %s", errmsg);
   1.232 -    }
   1.233 -  } else if (status == 0) {
   1.234 -    lua_pushboolean(L, 0);
   1.235 -    lua_pushliteral(L, "Timeout while polling file descriptors");
   1.236 -    return 2;
   1.237 -  } else {
   1.238 -    lua_pushboolean(L, 1);
   1.239 -    return 1;
   1.240 -  }
   1.241 -}
   1.242 -
   1.243 -/* New methods for Lua file objects: read until terminator or length exceeded (blocking and non-blocking) */
   1.244 -static int moonbr_io_xread_impl(lua_State *L, int nonblock) {
   1.245 -  luaL_Stream *stream;
   1.246 -  lua_Integer maxlen;
   1.247 -  const char *terminatorstr;
   1.248 -  size_t terminatorlen;
   1.249 -  FILE *file;
   1.250 -  int chr, terminator;
   1.251 -  luaL_Buffer buf;
   1.252 -  int wouldblock = 0;
   1.253 -  stream = luaL_checkudata(L, 1, LUA_FILEHANDLE);
   1.254 -  maxlen = luaL_optinteger(L, 2, 0);
   1.255 -  terminatorstr = luaL_optlstring(L, 3, "", &terminatorlen);
   1.256 -  luaL_argcheck(L, terminatorlen <= 1, 3, "single byte expected");
   1.257 -  if (!stream->closef) luaL_error(L, "attempt to use a closed file");
   1.258 -  file = stream->f;
   1.259 -  if (ferror(file)) {
   1.260 -    lua_pushnil(L);
   1.261 -    lua_pushliteral(L, "Previous error condition on file handle");
   1.262 -    return 2;
   1.263 -  }
   1.264 -  if (!maxlen) maxlen = -1;
   1.265 -  terminator = terminatorlen ? terminatorstr[0] : -1;
   1.266 -  luaL_buffinit(L, &buf);
   1.267 -  while (maxlen > 0 ? maxlen-- : maxlen) {
   1.268 -    chr = getc(file);
   1.269 -    if (chr == EOF) {
   1.270 -      if (ferror(file)) {
   1.271 -        if (nonblock && errno == EAGAIN) {
   1.272 -          clearerr(file);
   1.273 -          wouldblock = 1;
   1.274 -        } else {
   1.275 -          char errmsg[MOONBR_MAXSTRERRORLEN];
   1.276 -          strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.277 -          lua_pushnil(L);
   1.278 -          lua_pushstring(L, errmsg);
   1.279 -          return 2;
   1.280 -        }
   1.281 -      }
   1.282 -      break;
   1.283 -    }
   1.284 -    luaL_addchar(&buf, chr);
   1.285 -    if (chr == terminator) break;
   1.286 -  }
   1.287 -  luaL_pushresult(&buf);
   1.288 -  if (wouldblock || lua_rawlen(L, -1)) {
   1.289 -    return 1;
   1.290 -  } else {
   1.291 -    lua_pushboolean(L, 0);
   1.292 -    lua_pushliteral(L, "End of file");
   1.293 -    return 2;
   1.294 -  }
   1.295 -}
   1.296 -static int moonbr_io_xread(lua_State *L) {
   1.297 -  return moonbr_io_xread_impl(L, 0);
   1.298 -}
   1.299 -static int moonbr_io_xread_nb_impl(lua_State *L) {
   1.300 -  return moonbr_io_xread_impl(L, 1);
   1.301 -}
   1.302 -static int moonbr_io_xread_nb(lua_State *L) {
   1.303 -  luaL_Stream *stream;
   1.304 -  int fd, flags;
   1.305 -  stream = luaL_checkudata(L, 1, LUA_FILEHANDLE);
   1.306 -  if (!stream->closef) luaL_error(L, "attempt to use a closed file");
   1.307 -  lua_pushcfunction(L, moonbr_io_xread_nb_impl);
   1.308 -  lua_insert(L, 1);
   1.309 -  lua_settop(L, 4);
   1.310 -  fd = fileno(stream->f);
   1.311 -  flags = fcntl(fd, F_GETFL, 0);
   1.312 -  if (flags == -1) goto moonbr_io_xread_nb_error;
   1.313 -  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_xread_nb_error;
   1.314 -  if (lua_pcall(L, 3, LUA_MULTRET, 0)) {
   1.315 -    fcntl(fd, F_SETFL, flags);
   1.316 -    return lua_error(L);
   1.317 -  }
   1.318 -  if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_xread_nb_error;
   1.319 -  return lua_gettop(L);
   1.320 -  moonbr_io_xread_nb_error:
   1.321 -  {
   1.322 -    char errmsg[MOONBR_MAXSTRERRORLEN];
   1.323 -    strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.324 -    return luaL_error(L, "Unexpected error in xread_nb method: %s", errmsg);
   1.325 -  }
   1.326 -}
   1.327 -
   1.328 -/* New methods for Lua file objects: non-blocking writing */
   1.329 -static int moonbr_io_write_nb_impl(lua_State *L) {
   1.330 -  int fd, argc, i;
   1.331 -  const char *str;
   1.332 -  size_t strlen;
   1.333 -  ssize_t written;
   1.334 -  luaL_Buffer buf;
   1.335 -  fd = lua_tointeger(L, 1);
   1.336 -  argc = lua_gettop(L) - 1;
   1.337 -  for (i=0; i<argc; i++) {
   1.338 -    str = luaL_checklstring(L, 2+i, &strlen);
   1.339 -    written = write(fd, str, strlen);
   1.340 -    if (written < 0) {
   1.341 -      if (errno != EAGAIN) {
   1.342 -        char errmsg[MOONBR_MAXSTRERRORLEN];
   1.343 -        strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.344 -        lua_pushnil(L);
   1.345 -        lua_pushstring(L, errmsg);
   1.346 -        return 2;
   1.347 -      }
   1.348 -      written = 0;
   1.349 -    }
   1.350 -    if (written < strlen) {
   1.351 -      luaL_buffinit(L, &buf);
   1.352 -      luaL_addlstring(&buf, str+written, strlen-written);
   1.353 -      for (i=i+1; i<argc; i++) {
   1.354 -        luaL_checkstring(L, 2+i);
   1.355 -        lua_pushvalue(L, 2+i);
   1.356 -        luaL_addvalue(&buf);
   1.357 -      }
   1.358 -      luaL_pushresult(&buf);
   1.359 -      return 1;
   1.360 -    }
   1.361 -  }
   1.362 -  lua_pushliteral(L, "");
   1.363 -  return 1;
   1.364 -}
   1.365 -static int moonbr_io_write_nb(lua_State *L) {
   1.366 -  luaL_Stream *stream;
   1.367 -  FILE *file;
   1.368 -  int fd, flags;
   1.369 -  stream = luaL_checkudata(L, 1, LUA_FILEHANDLE);
   1.370 -  if (!stream->closef) luaL_error(L, "attempt to use a closed file");
   1.371 -  file = stream->f;
   1.372 -  if (fflush(file)) goto moonbr_io_write_nb_error;
   1.373 -  lua_pushcfunction(L, moonbr_io_write_nb_impl);
   1.374 -  lua_insert(L, 2);
   1.375 -  fd = fileno(file);
   1.376 -  lua_pushinteger(L, fd);
   1.377 -  lua_insert(L, 3);
   1.378 -  flags = fcntl(fd, F_GETFL, 0);
   1.379 -  if (flags == -1) goto moonbr_io_write_nb_error;
   1.380 -  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) goto moonbr_io_write_nb_error;
   1.381 -  if (lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0)) {
   1.382 -    fcntl(fd, F_SETFL, flags);
   1.383 -    return lua_error(L);
   1.384 -  }
   1.385 -  if (fcntl(fd, F_SETFL, flags) == -1) goto moonbr_io_write_nb_error;
   1.386 -  return lua_gettop(L) - 1;
   1.387 -  moonbr_io_write_nb_error:
   1.388 -  {
   1.389 -    char errmsg[MOONBR_MAXSTRERRORLEN];
   1.390 -    strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   1.391 -    return luaL_error(L, "Unexpected error in write_nb method: %s", errmsg);
   1.392 -  }
   1.393 -}
   1.394 -
   1.395 -/* New global function timeout(...) */
   1.396  static int moonbr_timeout(lua_State *L) {
   1.397    struct itimerval oldval;
   1.398    if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) {
   1.399 @@ -3017,21 +2764,13 @@
   1.400  #ifdef MOONBR_LUA_CPATH
   1.401      moonbr_modify_path(L, "cpath", MOONBR_LUA_CPATH);
   1.402  #endif
   1.403 -    lua_getglobal(L, "io");
   1.404 -    lua_pushcfunction(L, moonbr_io_poll);
   1.405 -    lua_setfield(L, -2, "poll");
   1.406 -    lua_pop(L, 1);
   1.407      if (luaL_newmetatable(L, LUA_FILEHANDLE)) {
   1.408        moonbr_log(LOG_CRIT, "Lua metatable LUA_FILEHANDLE does not exist");
   1.409        moonbr_terminate_error();
   1.410      }
   1.411      lua_getfield(L, -1, "__index");
   1.412 -    lua_pushcfunction(L, moonbr_io_xread);
   1.413 -    lua_setfield(L, -2, "xread");
   1.414 -    lua_pushcfunction(L, moonbr_io_xread_nb);
   1.415 -    lua_setfield(L, -2, "xread_nb");
   1.416 -    lua_pushcfunction(L, moonbr_io_write_nb);
   1.417 -    lua_setfield(L, -2, "write_nb");
   1.418 +    lua_pushcfunction(L, moonbr_readuntil);
   1.419 +    lua_setfield(L, -2, "readuntil");
   1.420      lua_pop(L, 2);
   1.421      lua_pushcfunction(L, moonbr_timeout);
   1.422      lua_setglobal(L, "timeout");

Impressum / About Us