int32_t context_lua_t::context_query_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination) { if (root_coro != NULL) { context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); message_t& message = lctx->get_yielding_message(); message.m_session = context_lua_t::lua_ref_yield_coroutine(root_coro); bool ret; if (message_is_string(message)) { ret = singleton_ref(node_lua_t).context_send_string_safe(destination, lctx->get_handle(), message.m_session, CONTEXT_QUERY, message_string(message)); } else if (message_is_bson(message)) { } else { ret = singleton_ref(node_lua_t).context_send(destination, message); } if (ret) { int64_t timeout = lctx->get_yielding_timeout(); if (timeout > 0) { context_lua_t::lua_ref_timer(main_coro, message.m_session, timeout, 0, false); } return UV_OK; } else { lua_free_ref_session(main_coro, message.m_session); return NL_ENOCONTEXT; } } return UV_OK; }
void uv_udp_handle_t::write(request_udp_write_t& request) { int32_t err = UV_UNKNOWN; if (request.m_shared_write) { uv_udp_handle_t* handle = (uv_udp_handle_t*)singleton_ref(network_t).get_shared_write_socket(request.m_socket_fd); if (handle != NULL) { uint32_t length = request.m_length > 0 ? request.m_length : (uint32_t)buffer_data_length(request.m_buffer); if (uv_is_closing((uv_handle_t*)handle)) { err = NL_EUDPSCLOSED; } else { err = handle->write_handle(request); } } else { err = NL_EUDPNOWSHARED; } } else { err = request.m_socket_handle->write_handle(request); } if (err != UV_OK) { /* write error had been occurred */ if (request.m_length > 0) { nl_free((void*)request.m_string); } else { buffer_release(request.m_buffer); } if (request.m_session != LUA_REFNIL) { singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_WRITE, (nl_err_code)err); } } }
void uv_udp_handle_t::read(request_udp_read_t& request) { if (!m_read_started) { if (uv_udp_recv_start((uv_udp_t*)m_handle, on_read_alloc, on_read) != 0) { singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_UDP_READ, singleton_ref(network_t).last_error()); return; } m_read_started = true; } }
void uv_udp_handle_t::set_udp_wshared(bool enable) { if (!uv_is_closing((uv_handle_t*)(m_handle))) { int64_t fd = SOCKET_MAKE_FD(m_lua_ref, m_source); if (enable) { singleton_ref(network_t).put_shared_write_socket(fd, this); } else { singleton_ref(network_t).pop_shared_write_socket(fd); } } }
void context_lua_t::on_received(message_t& message) { switch (message_raw_type(message)) { case LUA_CTX_INIT: lua_ctx_init(message); return; case CONTEXT_QUERY: response_context_query(message); break; case CONTEXT_REPLY: response_context_reply(message); break; case LUA_CTX_WAIT: response_context_wait(message); break; case LUA_CTX_WAKEUP: response_context_wakeup(message); break; case RESPONSE_TCP_LISTEN: response_tcp_listen(message); break; case RESPONSE_TCP_ACCEPT: response_tcp_accept(message); break; case RESPONSE_TCP_CONNECT: response_tcp_connect(message); break; case RESPONSE_TCP_READ: response_tcp_read(message); break; case RESPONSE_TCP_WRITE: response_tcp_write(message); break; case RESPONSE_HANDLE_CLOSE: response_handle_close(message); break; case RESPONSE_TCP_CLOSING: response_tcp_closing(message); break; case RESPONSE_TIMEOUT: response_timeout(message); break; case SYSTEM_CTX_DESTROY: singleton_ref(node_lua_t).context_destroy(this, message.m_source, message_string(message)); return; default: break; } if (!is_active()) { singleton_ref(node_lua_t).context_destroy(this, m_handle, "lua context exit normally"); } }
void uv_udp_handle_t::open(request_udp_open_t& request) { uv_udp_t* server = (uv_udp_t*)m_handle; if ((!request.m_ipv6 ? uv_udp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port), 0) == 0 : uv_udp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port), 0) == 0)) { m_udp_sock = uv_udp_fd((uv_udp_t*)server); if (!singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_OPEN, (void*)this)) { uv_close((uv_handle_t*)server, on_closed); } } else { singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_OPEN, singleton_ref(network_t).last_error()); uv_close((uv_handle_t*)server, on_closed); } }
int32_t context_lua_t::context_destroy(lua_State *L) { int32_t type = lua_type(L, 1); uint32_t src_handle = lua_get_context_handle(L); if (type == LUA_TNIL || type == LUA_TSTRING) { //kill self singleton_ref(node_lua_t).context_destroy(src_handle, src_handle, lua_tostring(L, 1)); return 0; } int32_t handle = luaL_checkunsigned(L, 1); if (handle > 0) { singleton_ref(node_lua_t).context_destroy(handle, src_handle, lua_tostring(L, 2)); } return 0; }
int32_t uv_udp_handle_t::write_handle(request_udp_write_t& request) { int result; uv_buf_t uv_buf; write_uv_request_t* uv_request = get_write_cached_request(); uv_request->m_source = request.m_source; uv_request->m_session = request.m_session; uv_request->m_length = request.m_length; if (request.m_length > 0) { uv_request->m_string = request.m_string; uv_buf.len = request.m_length; uv_buf.base = (char*)request.m_string; } else { uv_request->m_buffer = request.m_buffer; uv_buf.len = buffer_data_length(request.m_buffer); uv_buf.base = buffer_data_ptr(request.m_buffer); } if (!request.m_ipv6) { result = uv_udp_send(&uv_request->m_write_req, (uv_udp_t*)m_handle, &uv_buf, 1, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port), on_write); } else { result = uv_udp_send6(&uv_request->m_write_req, (uv_udp_t*)m_handle, &uv_buf, 1, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port), on_write); } if (result == 0) return UV_OK; put_write_cached_request(uv_request); return singleton_ref(network_t).last_error(); /* write error occurs */ }
int32_t context_lua_t::context_wait(lua_State *L) { context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); if (handle == 0) { luaL_error(L, "invalid context handle to wait"); return 0; } if (handle == lctx->get_handle()) { luaL_error(L, "can't wait self to die away"); return 0; } int32_t top = lua_gettop(L); uint64_t timeout = 0; int32_t callback = 0; int32_t session; if (top >= 2) { if (lua_isnil(L, 2)) { lctx->m_context_wait_sessions.free_nonblocking_callback(handle, L); return 0; } if (lua_isfunction(L, 2)) { callback = 2; } else { timeout = 1000 * luaL_checknumber(L, 2); if (top >= 3) { luaL_checktype(L, 3, LUA_TFUNCTION); callback = 3; } } } if (callback > 0) { //nonblocking lua_settop(L, callback); if (singleton_ref(node_lua_t).context_send(handle, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT, (int64_t)handle)) { lctx->m_context_wait_sessions.make_nonblocking_callback(handle, L, callback - 1, common_callback_adjust, &session); if (timeout > 0) { context_lua_t::lua_ref_timer(L, session, timeout, 0, false, (void*)handle, context_wait_timeout); } } else { singleton_ref(node_lua_t).context_send(lctx, handle, LUA_REFNIL, LUA_CTX_WAKEUP, UV_OK); } return 0; } return lctx->lua_yield_send(L, handle, context_wait_yield_finalize, NULL, context_wait_yield_continue, timeout); }
void context_lua_t::response_context_query(message_t& response) { if (response.m_source == 0) return; if (!m_context_recv_sessions.wakeup_once(response.m_source, this, response) && !m_context_recv_sessions.wakeup_once(0, this, response)) { if (response.m_session != LUA_REFNIL) { singleton_ref(node_lua_t).context_send(response.m_source, m_handle, response.m_session, CONTEXT_REPLY, NL_ENOREPLY); } } }
bool context_lua_t::deinit(const char *arg) { for (std::set<uint32_t>::iterator it = m_context_wait_handles.begin(); it != m_context_wait_handles.end(); ++it) { singleton_ref(node_lua_t).context_send(*it, m_handle, LUA_REFNIL, LUA_CTX_WAKEUP, UV_OK); } m_context_wait_handles.clear(); if (m_lstate) { lua_close(m_lstate); m_lstate = NULL; } printf("[alert] context:0x%08x deinit: %s\n", m_handle, arg); /* to be implemented : put reason to another context and output it */ return true; }
void uv_udp_handle_t::on_write(uv_udp_send_t* req, int status) { write_uv_request_t *uv_request = (write_uv_request_t*)req->data; uv_udp_handle_t *socket_handle = (uv_udp_handle_t*)(req->handle->data); if (uv_request->m_length > 0) { nl_free((void*)uv_request->m_string); } else { buffer_release(uv_request->m_buffer); } if (uv_request->m_session != LUA_REFNIL) { singleton_ref(node_lua_t).context_send(uv_request->m_source, 0, uv_request->m_session, RESPONSE_UDP_WRITE, status == 0 ? UV_OK : singleton_ref(network_t).last_error()); } socket_handle->put_write_cached_request(uv_request); }
void context_lua_t::on_dropped(message_t& message) { switch (message_raw_type(message)) { case RESPONSE_TCP_LISTEN: case RESPONSE_TCP_ACCEPT: case RESPONSE_TCP_CONNECT: if (message_is_userdata(message)) { uv_handle_base_t* handle = (uv_handle_base_t*)message_userdata(message); lua_handle_base_t::close_uv_handle(handle); } break; case CONTEXT_QUERY: if (message.m_source != 0 && message.m_session != LUA_REFNIL) { singleton_ref(node_lua_t).context_send(message.m_source, m_handle, message.m_session, CONTEXT_REPLY, NL_ENOREPLY); } return; case LUA_CTX_WAIT: singleton_ref(node_lua_t).context_send(message.m_source, (uint32_t)message_integer(message), LUA_REFNIL, LUA_CTX_WAKEUP, UV_OK); return; default: break; } }
void uv_udp_handle_t::on_read(uv_udp_t* handle, ssize_t nread, uv_buf_t buf, struct sockaddr* addr, unsigned flags) { /* udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024) */ if (nread == 0) { return; } uv_udp_handle_t* udp_handle = (uv_udp_handle_t*)(handle->data); if (nread == -1) { singleton_ref(node_lua_t).context_send(udp_handle->m_source, 0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, singleton_ref(network_t).last_error()); return; } buffer_t buffer = buffer_new(nread, buf.base, nread); char* host = (char*)nl_malloc(64); uint16_t port = 0; bool ipv6 = false; *host = '\0'; sockaddr_host(addr, host, 64, &ipv6, &port); message_array_t* array = message_array_create(4); array->m_array[0] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, buffer); array->m_array[1] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, host); array->m_array[2] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, (int64_t)port); array->m_array[3] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, ipv6); singleton_ref(node_lua_t).context_send_array_release(udp_handle->m_source, 0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, array); }
void context_lua_t::lua_ctx_init(message_t& message) { int32_t argc = (int32_t)message_integer(message); int32_t envc = lua_gettop(m_lstate) - argc; const char *file = lua_tostring(m_lstate, 1); if (luaL_loadfile(m_lstate, file) == LUA_OK) { lua_State *co; lua_init(m_lstate); lua_insert(m_lstate, -envc - 1); lua_init_env(m_lstate, envc); co = lua_new_root_coro(m_lstate); lua_pushlightuserdata(m_lstate, NULL); lua_pushcclosure(m_lstate, lua_ref_callback_entry, argc + 1); /* make the c closure callback */ lua_xmove(m_lstate, co, 1); /* move top c closure to co */ lua_pop(m_lstate, 1); /* pop the file name on top */ resume_coroutine(co, 0); if (!is_active()) { singleton_ref(node_lua_t).context_destroy(this, m_handle, "lua context exit normally"); } return; } const char *error = lua_tostring(m_lstate, -1); singleton_ref(node_lua_t).context_destroy(this, m_handle, "fail to initialize lua context %s, %s", file, error); }
int32_t context_lua_t::context_wait_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination) { if (root_coro != NULL) { context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); if (singleton_ref(node_lua_t).context_send(destination, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT, (int64_t)destination)) { int32_t session = lctx->m_context_wait_sessions.push_blocking(destination, root_coro); int64_t timeout = lctx->get_yielding_timeout(); if (timeout > 0) { context_lua_t::lua_ref_timer(main_coro, session, timeout, 0, false, (void*)destination, context_wait_timeout); } return UV_OK; } else { return NL_ENOCONTEXT; } } return UV_OK; }
int32_t context_lua_t::context_reply(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); int32_t session = luaL_checkinteger(L, 2); int32_t ret = context_send(L, 3, handle, session, CONTEXT_REPLY); if (ret == UV_OK) { lua_pushboolean(L, 1); return 1; } if (ret == NL_ETRANSTYPE) { context_t* ctx = lua_get_context(L); singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, CONTEXT_REPLY, NL_ETRANSTYPE); luaL_argerror(L, 3, common_strerror(NL_ETRANSTYPE)); return 0; } lua_pushboolean(L, 0); lua_pushinteger(L, NL_ENOCONTEXT); return 2; }
bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) { m_lstate = luaL_newstateex(this); if (argc <= 0) { printf("[error] context:0x%08x init failed: lua file is needed to initialize lua context\n", m_handle); /* to be implemented : put reason to another context and output it */ return false; } int32_t envc = 2; if (argc > MAX_CTX_ARGC || !lua_checkstack(m_lstate, argc + envc)) { printf("[error] context:0x%08x init failed: too many arguments to initialize lua context %s\n", m_handle, argv[0]); /* to be implemented : put reason to another context and output it */ return false; } int32_t total_length = 0; int32_t lengths[MAX_CTX_ARGC]; for (int32_t i = 0; i < argc; ++i) { lengths[i] = strlen(argv[i]); lua_pushlstring(m_lstate, argv[i], lengths[i]); total_length += lengths[i] + 1; } char** envp = env; char* lua_path = NULL; char* lua_cpath = NULL; while (*envp) { if (strncmp(*envp, "LUA_PATH=", 9) == 0) { lua_path = *envp + 9; } else if (strncmp(*envp, "LUA_CPATH=", 10) == 0) { lua_cpath = *envp + 10; } ++envp; } lua_pushstring(m_lstate, lua_path); lua_pushstring(m_lstate, lua_cpath); char* args = (char*)nl_calloc(total_length, 1); char* argp = args; for (int32_t i = 0; i < argc; ++i) { memcpy(argp, argv[i], lengths[i]); argp += lengths[i]; *argp++ = (i != argc - 1) ? ' ' : '\0'; } printf("[alert] context:0x%08x init: %s\n", m_handle, args); /* to be implemented : put reason to another context and output it */ nl_free(args); return singleton_ref(node_lua_t).context_send(this, m_handle, 0, LUA_CTX_INIT, (int64_t)argc); }
lua_timer_handle_t* lua_timer_handle_t::create_timer(lua_State* L, int32_t session, uint64_t timeout, uint64_t repeat, bool is_cancel, void *userdata, timeout_callback_t callback) { lua_checkstack(L, 3); uv_timer_handle_t* uv_timer = new uv_timer_handle_t(context_lua_t::lua_get_context_handle(L)); lua_timer_handle_t* lua_timer = new(lua_newuserdata(L, sizeof(lua_timer_handle_t)))lua_timer_handle_t(uv_timer, L, session, repeat > 0, is_cancel, userdata, callback); if (luaL_newmetatable(L, TIMER_METATABLE)) { /* create new metatable */ lua_pushcfunction(L, lua_timer_handle_t::release); lua_setfield(L, -2, "__gc"); } lua_setmetatable(L, -2); request_t request; request.m_type = REQUEST_TIMER_START; request.m_length = REQUEST_SIZE(request_timer_start_t, 0); request.m_timer_start.m_timer_handle = uv_timer; request.m_timer_start.m_timeout = timeout; request.m_timer_start.m_repeat = repeat; singleton_ref(network_t).send_request(request); return lua_timer; }
int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t handle, int32_t session, uint32_t msg_type) { bool ret = false; nil_t nil; buffer_t* buffer; context_t* ctx = lua_get_context(L); switch (lua_type(L, idx)) { case LUA_TNUMBER: if (lua_isinteger(L, idx)) { ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (int64_t)lua_tointeger(L, idx)); } else { ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (double)lua_tonumber(L, idx)); } break; case LUA_TSTRING: ret = singleton_ref(node_lua_t).context_send_string_safe(handle, ctx->get_handle(), session, msg_type, lua_tostring(L, idx)); break; case LUA_TBOOLEAN: ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (bool)lua_toboolean(L, idx)); break; case LUA_TNIL: ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, nil); break; case LUA_TUSERDATA: buffer = (buffer_t*)luaL_testudata(L, idx, BUFFER_METATABLE); if (buffer) { ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, *buffer); break; } else { return NL_ETRANSTYPE; } //to be fix : bson, array case LUA_TLIGHTUSERDATA: ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (void*)lua_touserdata(L, idx)); break; default: return NL_ETRANSTYPE; } return ret ? UV_OK : NL_ENOCONTEXT; }
int32_t context_lua_t::context_create(lua_State *L) { int32_t argc = lua_gettop(L); if (argc <= 0) { luaL_error(L, "lua file is needed to initialize lua context"); } if (argc > MAX_CTX_ARGC) { luaL_error(L, "too many arguments to initialize lua context"); } char* argv[MAX_CTX_ARGC]; char* env[16] = { NULL }; lua_load_env(L, env); for (int32_t i = 0; i < argc; ++i) { argv[i] = (char*)luaL_checkstring(L, i + 1); } uint32_t parent = lua_get_context_handle(L); uint32_t handle = singleton_ref(node_lua_t).context_create<context_lua_t>(parent, argc, argv, env); lua_free_env(L, env); if (handle > 0) { lua_pushinteger(L, handle); return 1; } return 0; }
uv_udp_handle_t::~uv_udp_handle_t() { clear_write_cached_requests(); singleton_ref(network_t).pop_shared_write_socket(SOCKET_MAKE_FD(m_lua_ref, m_source)); }
void worker_mgr_t::worker_entry(void* arg) { singleton_ref(worker_mgr_t).worker_process((int64_t)arg); }
uv_buf_t uv_udp_handle_t::on_read_alloc(uv_handle_t* handle, size_t suggested_size) { return singleton_ref(network_t).make_shared_read_buffer(); }