moonbridge

diff moonbridge_io.c @ 149:c820130f55d7

New function moonbridge_io.run(...) as a "coroutine scheduler"
author jbe
date Fri May 08 03:18:07 2015 +0200 (2015-05-08)
parents c51c38d991df
children 2a5bd37034c6
line diff
     1.1 --- a/moonbridge_io.c	Thu May 07 22:22:21 2015 +0200
     1.2 +++ b/moonbridge_io.c	Fri May 08 03:18:07 2015 +0200
     1.3 @@ -23,6 +23,8 @@
     1.4  #include <lauxlib.h>
     1.5  #include <lualib.h>
     1.6  
     1.7 +#include <assert.h>
     1.8 +
     1.9  #define MOONBR_IO_MAXSTRERRORLEN 80
    1.10  #define MOONBR_IO_READBUFLEN 4096
    1.11  #define MOONBR_IO_WRITEBUFLEN 4096
    1.12 @@ -38,6 +40,7 @@
    1.13  #define MOONBR_IO_LISTENER_MT_REGKEY "moonbridge_io_listener"
    1.14  
    1.15  char moonbr_io_block_udata = 0;
    1.16 +char moonbr_io_multiblock_udata = 0;
    1.17  
    1.18  typedef struct {
    1.19    int fd;
    1.20 @@ -74,7 +77,7 @@
    1.21  } moonbr_io_listener_t;
    1.22  
    1.23  static int moonbr_io_yield(lua_State *L) {
    1.24 -  return lua_yield(L, 0);
    1.25 +  return lua_yield(L, lua_gettop(L));
    1.26  }
    1.27  
    1.28  #if LUA_VERSION_NUM >= 503
    1.29 @@ -1334,6 +1337,154 @@
    1.30    return 1;
    1.31  }
    1.32  
    1.33 +#define MOONBR_IO_RUN_STACKBASE 7
    1.34 +
    1.35 +#if LUA_VERSION_NUM >= 503
    1.36 +static int moonbr_io_run_cont(lua_State *L, int status, lua_KContext ctx) {
    1.37 +#else
    1.38 +static int moonbr_io_run_cont(lua_State *L) {
    1.39 +#endif
    1.40 +#if !(LUA_VERSION_NUM >= 503)
    1.41 +  int ctx = 0;
    1.42 +  lua_getctx(L, &ctx);
    1.43 +#endif
    1.44 +  while (1) {
    1.45 +    int work_to_do = 0;
    1.46 +    assert(lua_gettop(L) == 7);
    1.47 +    if (lua_isboolean(L, -1) && !lua_toboolean(L, -1)) return 1;
    1.48 +    lua_pop(L, 1);
    1.49 +    if (ctx) {
    1.50 +      for (lua_pushnil(L); lua_next(L, 4); lua_pop(L, 1)) {
    1.51 +        lua_pushvalue(L, -2);
    1.52 +        lua_pushnil(L);
    1.53 +        lua_rawset(L, 4);
    1.54 +      }
    1.55 +      for (lua_pushnil(L); lua_next(L, 5); lua_pop(L, 1)) {
    1.56 +        lua_pushvalue(L, -2);
    1.57 +        lua_pushnil(L);
    1.58 +        lua_rawset(L, 5);
    1.59 +      }
    1.60 +    }
    1.61 +    assert(lua_gettop(L) == 6);
    1.62 +    while (lua_next(L, 1)) {
    1.63 +      void *marker;
    1.64 +      assert(lua_gettop(L) == MOONBR_IO_RUN_STACKBASE);
    1.65 +      while (1) {
    1.66 +        lua_pushvalue(L, -2);
    1.67 +        lua_call(L, 0, LUA_MULTRET);
    1.68 +        if (!lua_checkstack(L, LUA_MINSTACK)) luaL_error(L, "Lua stack exhausted");
    1.69 +        marker = lua_touserdata(L, MOONBR_IO_RUN_STACKBASE+1);
    1.70 +        if (marker == &moonbr_io_block_udata) {
    1.71 +          const char *mode = lua_tostring(L, MOONBR_IO_RUN_STACKBASE+3);
    1.72 +          if (mode && !lua_isnoneornil(L, MOONBR_IO_RUN_STACKBASE+2)) {
    1.73 +            if (strchr(mode, 'r')) {
    1.74 +              lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE+2);
    1.75 +              lua_pushboolean(L, 1);
    1.76 +              lua_rawset(L, 4);
    1.77 +            }
    1.78 +            if (strchr(mode, 'w')) {
    1.79 +              lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE+2);
    1.80 +              lua_pushboolean(L, 1);
    1.81 +              lua_rawset(L, 5);
    1.82 +            }
    1.83 +          }
    1.84 +          work_to_do = 1;
    1.85 +          break;
    1.86 +        } else if (marker == &moonbr_io_multiblock_udata) {
    1.87 +          if (lua_type(L, MOONBR_IO_RUN_STACKBASE+2) == LUA_TTABLE) {
    1.88 +            for (lua_pushnil(L); lua_next(L, MOONBR_IO_RUN_STACKBASE+2); lua_pop(L, 1)) {
    1.89 +              if (lua_toboolean(L, -1)) {
    1.90 +                lua_pushvalue(L, -2);
    1.91 +                lua_pushboolean(L, 1);
    1.92 +                lua_rawset(L, 4);
    1.93 +              }
    1.94 +            }
    1.95 +          }
    1.96 +          if (lua_type(L, MOONBR_IO_RUN_STACKBASE+3) == LUA_TTABLE) {
    1.97 +            for (lua_pushnil(L); lua_next(L, MOONBR_IO_RUN_STACKBASE+3); lua_pop(L, 1)) {
    1.98 +              if (lua_toboolean(L, -1)) {
    1.99 +                lua_pushvalue(L, -2);
   1.100 +                lua_pushboolean(L, 1);
   1.101 +                lua_rawset(L, 5);
   1.102 +              }
   1.103 +            }
   1.104 +          }
   1.105 +          work_to_do = 1;
   1.106 +          break;
   1.107 +        } else if (lua_isboolean(L, MOONBR_IO_RUN_STACKBASE)) {
   1.108 +          lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE-1);
   1.109 +          lua_pushnil(L);
   1.110 +          lua_rawset(L, 1);
   1.111 +          break;
   1.112 +        } else {
   1.113 +          lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE);
   1.114 +          lua_insert(L, MOONBR_IO_RUN_STACKBASE+1);
   1.115 +          lua_call(L, lua_gettop(L)-1-MOONBR_IO_RUN_STACKBASE, 1);
   1.116 +          if (lua_toboolean(L, -1)) {
   1.117 +            lua_pushvalue(L, MOONBR_IO_RUN_STACKBASE-1);
   1.118 +            lua_pushnil(L);
   1.119 +            lua_rawset(L, 1);
   1.120 +            break;
   1.121 +          }
   1.122 +        }
   1.123 +        lua_settop(L, MOONBR_IO_RUN_STACKBASE);
   1.124 +      }
   1.125 +      lua_settop(L, MOONBR_IO_RUN_STACKBASE-1);
   1.126 +    }
   1.127 +    if (!work_to_do) {
   1.128 +      lua_pushboolean(L, 1);
   1.129 +      return 1;
   1.130 +    }
   1.131 +    lua_pushnil(L);
   1.132 +    assert(lua_gettop(L) == 6);
   1.133 +    ctx = 1;
   1.134 +    if (lua_isfunction(L, 2)) {
   1.135 +      lua_pushvalue(L, 2);
   1.136 +      lua_pushlightuserdata(L, &moonbr_io_multiblock_udata);
   1.137 +      lua_pushvalue(L, 4);
   1.138 +      lua_pushvalue(L, 5);
   1.139 +      lua_callk(L, 3, 1, ctx, moonbr_io_run_cont);
   1.140 +    } else {
   1.141 +      lua_pushcfunction(L, moonbr_io_poll);
   1.142 +      lua_pushvalue(L, 4);
   1.143 +      lua_pushvalue(L, 5);
   1.144 +      if (lua_isnil(L, 2)) {
   1.145 +        lua_call(L, 2, 1);
   1.146 +      } else {
   1.147 +        lua_pushvalue(L, 2);
   1.148 +        lua_pushcfunction(L, moonbr_io_timeref);
   1.149 +        lua_pushvalue(L, 3);
   1.150 +        lua_call(L, 1, 1);
   1.151 +        lua_arith(L, LUA_OPSUB);
   1.152 +        lua_call(L, 3, 1);
   1.153 +      }
   1.154 +    }
   1.155 +    assert(lua_gettop(L) == 7);
   1.156 +  }
   1.157 +}
   1.158 +
   1.159 +static int moonbr_io_run(lua_State *L) {
   1.160 +  lua_settop(L, 2);
   1.161 +  luaL_checktype(L, 1, LUA_TTABLE);
   1.162 +  if (lua_isnil(L, 2) || lua_isfunction(L, 2)) {
   1.163 +    lua_pushnil(L);
   1.164 +  } else if (!lua_isnil(L, 2)) {
   1.165 +    luaL_checknumber(L, 2);
   1.166 +    lua_pushcfunction(L, moonbr_io_timeref);
   1.167 +    lua_call(L, 0, 1);
   1.168 +  }
   1.169 +  assert(lua_gettop(L) == 3);
   1.170 +  lua_newtable(L);  /* read_fds at stack position 4 */
   1.171 +  lua_newtable(L);  /* write_fds at stack position 5 */
   1.172 +  lua_pushnil(L);  /* current thread */
   1.173 +  lua_pushnil(L);
   1.174 +#if LUA_VERSION_NUM >= 503
   1.175 +  return moonbr_io_run_cont(L, 0, 0);
   1.176 +#else
   1.177 +  return moonbr_io_run_cont(L);
   1.178 +#endif
   1.179 +}
   1.180 +
   1.181  static const struct luaL_Reg moonbr_io_handle_methods[] = {
   1.182    {"read", moonbr_io_read},
   1.183    {"read_nb", moonbr_io_read_nb},
   1.184 @@ -1385,6 +1536,7 @@
   1.185    {"tcplisten", moonbr_io_tcplisten},
   1.186    {"poll", moonbr_io_poll},
   1.187    {"timeref", moonbr_io_timeref},
   1.188 +  {"run", moonbr_io_run},
   1.189    {NULL, NULL}
   1.190  };
   1.191  
   1.192 @@ -1396,6 +1548,8 @@
   1.193  
   1.194    lua_pushlightuserdata(L, &moonbr_io_block_udata);
   1.195    lua_setfield(L, -2, "block");
   1.196 +  lua_pushlightuserdata(L, &moonbr_io_multiblock_udata);
   1.197 +  lua_setfield(L, -2, "multiblock");
   1.198  
   1.199    lua_newtable(L);  // public metatable
   1.200    lua_newtable(L);  // handle methods

Impressum / About Us