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  

Impressum / About Us