Exemplo n.º 1
0
static int rb_save_with_growth(lua_State *L, int index, struct ringbuffer_t *rb) {
   while (1) {
      ringbuffer_push_write_pos(rb);
      int ret = rb_save(L, index, rb, 0);
      if (ret == -ENOMEM) {
         ringbuffer_pop_write_pos(rb);
         ringbuffer_grow_by(rb, MAX_ARG_SIZE);
      } else {
         return ret;
      }
   }
}
Exemplo n.º 2
0
static int sock_send_msg(lua_State *L, int index, int sock, ringbuffer_t *rb, copy_context_t *copy_context) {
   ringbuffer_push_write_pos(rb);
   int ret = rb_save(L, index, rb, 1);
   if (ret) return LUA_HANDLE_ERROR(L, ret);
   size_t len = ringbuffer_peek(rb);
   ringbuffer_pop_write_pos(rb);
   if (ret) return ret;
   ret = sock_send(sock, &len, sizeof(len), copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if (ret != sizeof(len)) return LUA_HANDLE_ERROR_STR(L, "failed to send the correct number of bytes");
   ret = sock_send(sock, ringbuffer_buf_ptr(rb), len, copy_context);
   if (ret < 0) return LUA_HANDLE_ERROR(L, errno);
   if ((size_t)ret != len) return LUA_HANDLE_ERROR_STR(L, "failed to send the correct number of bytes");
   return 0;
}
Exemplo n.º 3
0
static int workqueue_queue_write(lua_State *L, int index, queue_t *queue) {
   pthread_mutex_lock(&queue->mutex);
   int ret = 0;
   while (1) {
      ringbuffer_push_write_pos(queue->rb);
      ret = rb_save(L, index, queue->rb, 0);
      if (ret) {
         ringbuffer_pop_write_pos(queue->rb);
         if (ringbuffer_peek(queue->rb)) {
            pthread_cond_wait(&queue->write_avail_cond, &queue->mutex);
         } else {
            return LUA_HANDLE_ERROR_STR(L, "workqueue.write message is too big for the ring buffer.");
         }
      } else {
         break;
      }
   }
   queue->num_items++;
   pthread_cond_signal(&queue->read_avail_cond);
   pthread_mutex_unlock(&queue->mutex);
   return ret;
}
Exemplo n.º 4
0
int rb_save(lua_State *L, int index, ringbuffer_t *rb, int oop, int upval) {
   char type = lua_type(L, index);
   switch (type) {
      case LUA_TNIL: {
         RB_WRITE(L, rb, &type, sizeof(char));
         return 0;
      }
      case LUA_TBOOLEAN: {
         RB_WRITE(L, rb, &type, sizeof(char));
         type = lua_toboolean(L, index);
         RB_WRITE(L, rb, &type, sizeof(char));
         return 0;
      }
      case LUA_TNUMBER: {
#if LUA_VERSION_NUM >= 503
         if (lua_isinteger(L, index)) {
            type = EXTRA_LUA_TINTEGER;
            RB_WRITE(L, rb, &type, sizeof(char));
            lua_Integer n = lua_tointeger(L, index);
            RB_WRITE(L, rb, &n, sizeof(n));
         } else
#endif
         {
            RB_WRITE(L, rb, &type, sizeof(char));
            lua_Number n = lua_tonumber(L, index);
            RB_WRITE(L, rb, &n, sizeof(n));
         }
         return 0;
      }
      case LUA_TSTRING: {
         RB_WRITE(L, rb, &type, sizeof(char));
         size_t str_len;
         const char *str = lua_tolstring(L, index, &str_len);
         RB_WRITE(L, rb, &str_len, sizeof(str_len));
         RB_WRITE(L, rb, str, str_len);
         return 0;
      }
      case LUA_TTABLE: {
         RB_WRITE(L, rb, &type, sizeof(char));
         int top = lua_gettop(L);
         int ret;

         lua_pushnil(L);
         while (lua_next(L, index) != 0) {
            ret = rb_save(L, top + 1, rb, oop, upval); // key
            if (ret) {
               lua_pop(L, 2);
               return ret;
            }
            ret = rb_save(L, top + 2, rb, oop, upval); // value
            if (ret) {
               lua_pop(L, 2);
               return ret;
            }
            lua_pop(L, 1);
         }
         type = LUA_TNIL;
         RB_WRITE(L, rb, &type, sizeof(char)); // breaks the read loop

         // the typename identifies the metatable
         const char *str = luaT_typename(L, index);
         if (!str) {
            if (luaL_callmeta(L, index, "metatablename")) {
               str = lua_tostring(L, lua_gettop(L));
               lua_pop(L, 1);
            } else {
               str = "";
            }
         }
         size_t str_len = strlen(str);
         RB_WRITE(L, rb, &str_len, sizeof(str_len));
         RB_WRITE(L, rb, str, str_len);
         return 0;
      }
      case LUA_TFUNCTION: {

         RB_WRITE(L, rb, &type, sizeof(char));
         if (index != lua_gettop(L)) {
            lua_pushvalue(L, index);
         }
         lua_Debug ar;
         lua_pushvalue(L, -1);
         lua_getinfo(L, ">nuS", &ar);
         if (ar.what[0] != 'L') {
             luaL_error(L, "attempt to persist a C function '%s'", ar.name);
         }
         
         // this returns different things under LuaJIT vs Lua
#if LUA_VERSION_NUM >= 503
         lua_dump(L, rb_lua_writer, rb, 0);
#else
         lua_dump(L, rb_lua_writer, rb);
#endif

         size_t str_len = 0;
         RB_WRITE(L, rb, &str_len, sizeof(size_t)); // zero-terminated

         // does the serialization accept upvalues?
         RB_WRITE(L, rb, &upval, sizeof(int)); 
         
         // upvalues
         if (upval == 1) {
            lua_newtable(L);
            int envIdx = -1;
            for (int i=1; i <= ar.nups; i++) {
               const char *name = lua_getupvalue(L, -2, i);
               if (strcmp(name, "_ENV") != 0) { 
                  lua_rawseti(L, -2, i);
               } else { // ignore _ENV as we assume that this is the global _G variable
                  lua_pop(L, 1);
                  envIdx = i;
               }
            }
            // write upvalue index of _ENV
            RB_WRITE(L, rb, &envIdx, sizeof(int));

            // write upvalue table
            int ret = rb_save(L, lua_gettop(L), rb, oop, upval);
            if (ret) {
               return ret;
            }
            lua_pop(L, 1);
         } else if (ar.nups > 1) {
            luaL_error(L, "attempt to serialize a funciton with upvalues (i.e. a closure). Use ipc.workqueue.writeup().");
         }

         if (index != lua_gettop(L)) {
            lua_pop(L, 1);
         }

         return 0;
      }
      case LUA_TUSERDATA: {
         if (oop) return -EPERM;
         const char *str = luaT_typename(L, index);
         if (!str) {
            if (luaL_callmeta(L, index, "metatablename")) {
               str = lua_tostring(L, lua_gettop(L));
               lua_pop(L, 1);
               type = -type;
            } else {
               return -EINVAL;
            }
         }
         RB_WRITE(L, rb, &type, sizeof(char));
         size_t str_len = strlen(str);
         RB_WRITE(L, rb, &str_len, sizeof(str_len));
         RB_WRITE(L, rb, str, str_len);
         void *ptr = lua_touserdata(L, index);
         RB_WRITE(L, rb, ptr, sizeof(void *));
         if (luaL_callmeta(L, index, "retain")) {
            lua_pop(L, 1);
         } else {
            return -EINVAL;
         }
         return 0;
      }
      default:
         return -EPERM;
   }
}