Skip to content

Commit

Permalink
Merge pull request luvit#331 from zhaozg/master
Browse files Browse the repository at this point in the history
Implement support for external uv_loop_t
  • Loading branch information
zhaozg committed Jun 5, 2019
2 parents 788fa44 + 83a9c55 commit f975ede
Show file tree
Hide file tree
Showing 25 changed files with 161 additions and 57 deletions.
4 changes: 2 additions & 2 deletions src/async.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ static uv_async_t* luv_check_async(lua_State* L, int index) {
}

static void luv_async_cb(uv_async_t* handle) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
int n = luv_thread_arg_push(L, (luv_thread_arg_t*)data->extra, 0);
luv_call_callback(L, data, LUV_ASYNC, n);
luv_thread_arg_clear(L, (luv_thread_arg_t*)data->extra, 0);
Expand Down Expand Up @@ -54,7 +54,7 @@ static int luv_async_send(lua_State* L) {
int ret;
uv_async_t* handle = luv_check_async(L, 1);
luv_thread_arg_t* arg = (luv_thread_arg_t *)((luv_handle_t*) handle->data)->extra;

luv_thread_arg_set(L, arg, 2, lua_gettop(L), 0);
ret = uv_async_send(handle);
if (ret < 0) return luv_error(L, ret);
Expand Down
2 changes: 1 addition & 1 deletion src/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ static int luv_new_check(lua_State* L) {
}

static void luv_check_cb(uv_check_t* handle) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
luv_call_callback(L, data, LUV_CHECK, 0);
}

Expand Down
7 changes: 4 additions & 3 deletions src/dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ static void luv_pushaddrinfo(lua_State* L, struct addrinfo* res) {
}

static void luv_getaddrinfo_cb(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
lua_State* L = luv_state(req->loop);
luv_req_t* data = (luv_req_t*)req->data;
lua_State* L = data->L;
int nargs;

if (status < 0) {
Expand Down Expand Up @@ -206,8 +207,8 @@ static int luv_getaddrinfo(lua_State* L) {
}

static void luv_getnameinfo_cb(uv_getnameinfo_t* req, int status, const char* hostname, const char* service) {
lua_State* L = luv_state(req->loop);

luv_req_t* data = (luv_req_t*)req->data;
lua_State* L = data->L;
int nargs;

if (status < 0) {
Expand Down
3 changes: 2 additions & 1 deletion src/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ static int push_fs_result(lua_State* L, uv_fs_t* req) {
#endif

static void luv_fs_cb(uv_fs_t* req) {
lua_State* L = luv_state(req->loop);
luv_req_t* data = (luv_req_t*)req->data;
lua_State* L = data->L;

int nargs = push_fs_result(L, req);
if (nargs == 2 && lua_isnil(L, -nargs)) {
Expand Down
3 changes: 2 additions & 1 deletion src/fs_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ static int luv_new_fs_event(lua_State* L) {
}

static void luv_fs_event_cb(uv_fs_event_t* handle, const char* filename, int events, int status) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;

// err
luv_status(L, status);
Expand Down
3 changes: 2 additions & 1 deletion src/fs_poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ static int luv_new_fs_poll(lua_State* L) {
}

static void luv_fs_poll_cb(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;

// err
luv_status(L, status);
Expand Down
3 changes: 2 additions & 1 deletion src/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ static int luv_is_closing(lua_State* L) {
}

static void luv_close_cb(uv_handle_t* handle) {
lua_State* L = luv_state(handle->loop);
lua_State* L;
luv_handle_t* data = (luv_handle_t*)handle->data;
if (!data) return;
L = data->L;
luv_call_callback(L, data, LUV_CLOSED, 0);
luv_unref_handle(L, data);
}
Expand Down
2 changes: 1 addition & 1 deletion src/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ static int luv_new_idle(lua_State* L) {
}

static void luv_idle_cb(uv_idle_t* handle) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
luv_call_callback(L, data, LUV_IDLE, 0);
}

Expand Down
2 changes: 2 additions & 0 deletions src/lhandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "lhandle.h"

static luv_handle_t* luv_setup_handle(lua_State* L) {
lua_State* luvL = luv_state(L);
luv_handle_t* data;
const uv_handle_t* handle;
void *udata;
Expand Down Expand Up @@ -49,6 +50,7 @@ static luv_handle_t* luv_setup_handle(lua_State* L) {
data->ref = luaL_ref(L, LUA_REGISTRYINDEX);
data->callbacks[0] = LUA_NOREF;
data->callbacks[1] = LUA_NOREF;
data->L = luvL;
data->extra = NULL;
return data;
}
Expand Down
1 change: 1 addition & 0 deletions src/lhandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
typedef struct {
int ref;
int callbacks[2];
lua_State* L;
void* extra;
} luv_handle_t;

Expand Down
1 change: 1 addition & 0 deletions src/loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
static int luv_loop_close(lua_State* L) {
int ret = uv_loop_close(luv_loop(L));
if (ret < 0) return luv_error(L, ret);
luv_set_loop(L, NULL);
lua_pushinteger(L, ret);
return 1;
}
Expand Down
2 changes: 2 additions & 0 deletions src/lreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static int luv_check_continuation(lua_State* L, int index) {
// Store a lua callback in a luv_req for the continuation.
// The uv_req_t is assumed to be at the top of the stack
static luv_req_t* luv_setup_req(lua_State* L, int callback_ref) {
lua_State* luvL = luv_state(L);
luv_req_t* data;

luaL_checktype(L, -1, LUA_TUSERDATA);
Expand All @@ -41,6 +42,7 @@ static luv_req_t* luv_setup_req(lua_State* L, int callback_ref) {
data->req_ref = luaL_ref(L, LUA_REGISTRYINDEX);
data->callback_ref = callback_ref;
data->data_ref = LUA_NOREF;
data->L = luvL;
data->data = NULL;

return data;
Expand Down
1 change: 1 addition & 0 deletions src/lreq.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ typedef struct {
int req_ref; /* ref for uv_req_t's userdata */
int callback_ref; /* ref for callback */
int data_ref; /* ref for write data */
lua_State* L;
void* data; /* extra data */
} luv_req_t;

Expand Down
107 changes: 77 additions & 30 deletions src/luv.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,20 +508,55 @@ static void luv_handle_init(lua_State* L) {
lua_setfield(L, LUA_REGISTRYINDEX, "uv_stream");
}

LUALIB_API lua_State* luv_state(uv_loop_t* loop) {
return (lua_State*)loop->data;
// TODO: see if we can avoid using a string key for this to increase performance
static const char* luv_loop_key = "luv_loop";
static const char* luv_state_key = "luv_main_thread";

// Get main thread, ensure coroutines works
// Only called when luv setup uv_handle_t or uv_req_t
LUALIB_API lua_State* luv_state(lua_State* L) {
lua_State* lstate;
lua_pushstring(L, luv_state_key);
lua_rawget(L, LUA_REGISTRYINDEX);
lstate = lua_tothread(L, -1);
lua_pop(L, 1);
if (lstate==NULL) {
luaL_error(L, "cannot get main thread");
}
return lstate;
}

// TODO: find out if storing this somehow in an upvalue is faster
// Called when luv init uv_handle_t
LUALIB_API uv_loop_t* luv_loop(lua_State* L) {
uv_loop_t* loop;
lua_pushstring(L, "uv_loop");
lua_pushstring(L, luv_loop_key);
lua_rawget(L, LUA_REGISTRYINDEX);
loop = (uv_loop_t*)lua_touserdata(L, -1);
if (lua_isnil(L, -1))
loop = NULL;
else
loop = *(uv_loop_t**)lua_touserdata(L, -1);
lua_pop(L, 1);
return loop;
}

// Set an extran loop, before luaopen_luv
LUALIB_API void luv_set_loop(lua_State* L, uv_loop_t* loop) {
if (loop==NULL) {
lua_pushstring(L, luv_loop_key);
lua_pushnil(L);
lua_rawset(L, LUA_REGISTRYINDEX);
} else {
lua_pushstring(L, luv_loop_key);
*((uv_loop_t**)lua_newuserdata(L, sizeof(uv_loop_t**))) = loop;
lua_rawset(L, LUA_REGISTRYINDEX);

// Push main thread with luv_state_key in registry table
lua_pushstring(L, luv_state_key);
lua_pushthread(L);
lua_rawset(L, LUA_REGISTRYINDEX);
}
}

static void walk_cb(uv_handle_t *handle, void *arg)
{
(void)arg;
Expand All @@ -532,6 +567,8 @@ static void walk_cb(uv_handle_t *handle, void *arg)

static int loop_gc(lua_State *L) {
uv_loop_t* loop = luv_loop(L);
if (loop==NULL)
return 0;
// Call uv_close on every active handle
uv_walk(loop, walk_cb, NULL);
// Run the event loop until all handles are successfully closed
Expand All @@ -541,33 +578,43 @@ static int loop_gc(lua_State *L) {
return 0;
}

LUALIB_API int luaopen_luv (lua_State *L) {
LUALIB_API int luaopen_luv (lua_State* L) {
uv_loop_t* loop = luv_loop(L);

uv_loop_t* loop;
int ret;

// Setup the uv_loop meta table for a proper __gc
luaL_newmetatable(L, "uv_loop.meta");
lua_pushstring(L, "__gc");
lua_pushcfunction(L, loop_gc);
lua_settable(L, -3);

loop = (uv_loop_t*)lua_newuserdata(L, sizeof(*loop));
ret = uv_loop_init(loop);
if (ret < 0) {
return luaL_error(L, "%s: %s\n", uv_err_name(ret), uv_strerror(ret));
// loop is NULL, luv need to create an inner loop
if (loop==NULL) {
int ret;
void* p;

// Setup the uv_loop meta table for a proper __gc
luaL_newmetatable(L, "uv_loop.meta");
lua_pushstring(L, "__gc");
lua_pushcfunction(L, loop_gc);
lua_settable(L, -3);
lua_pop(L, 1);

// Push luv_loop_key as key for registry table
lua_pushstring(L, luv_loop_key);
// userdata content is: pointer of loop, and followed by loop
p = lua_newuserdata(L, sizeof(uv_loop_t*) + sizeof(uv_loop_t));
loop = (uv_loop_t*)((char*)p + sizeof(uv_loop_t*));
*((uv_loop_t**)p) = loop;
// setup the metatable for __gc
luaL_getmetatable(L, "uv_loop.meta");
lua_setmetatable(L, -2);
// rawset registry
lua_rawset(L, LUA_REGISTRYINDEX);

// Push main thread with luv_state_key in registry table
lua_pushstring(L, luv_state_key);
lua_pushthread(L);
lua_rawset(L, LUA_REGISTRYINDEX);

ret = uv_loop_init(loop);
if (ret < 0) {
return luaL_error(L, "%s: %s\n", uv_err_name(ret), uv_strerror(ret));
}
}
// setup the metatable for __gc
luaL_getmetatable(L, "uv_loop.meta");
lua_setmetatable(L, -2);
// Tell the state how to find the loop.
lua_pushstring(L, "uv_loop");
lua_insert(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_pop(L, 1);

// Tell the loop how to find the state.
loop->data = L;

luv_req_init(L);
luv_handle_init(L);
Expand Down
7 changes: 6 additions & 1 deletion src/luv.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,16 @@
These are exposed for extensions built with luv
This allows luv to be used in multithreaded applications.
*/
LUALIB_API lua_State* luv_state(uv_loop_t* loop);
LUALIB_API lua_State* luv_state(lua_State* L);
/* All libuv callbacks will lua_call directly from this root-per-thread state
*/
LUALIB_API uv_loop_t* luv_loop(lua_State* L);

/* Set or clear an external uv_loop_t in a lua_State
This must be called before luaopen_luv, so luv doesn't init an own loop
*/
LUALIB_API void luv_set_loop(lua_State* L, uv_loop_t* loop);

/* This is the main hook to load the library.
This can be called multiple times in a process as long
as you use a different lua_State and thread for each.
Expand Down
2 changes: 1 addition & 1 deletion src/poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ static const char *const luv_pollevents[] = {
};

static void luv_poll_cb(uv_poll_t* handle, int status, int events) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
const char* evtstr;

if (status < 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/prepare.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ static int luv_new_prepare(lua_State* L) {
}

static void luv_prepare_cb(uv_prepare_t* handle) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
luv_call_callback(L, data, LUV_PREPARE, 0);
}

Expand Down
5 changes: 3 additions & 2 deletions src/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ static uv_process_t* luv_check_process(lua_State* L, int index) {
}

static void exit_cb(uv_process_t* handle, int64_t exit_status, int term_signal) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
lua_pushinteger(L, exit_status);
lua_pushinteger(L, term_signal);
luv_call_callback(L, data, LUV_EXIT, 2);
}

static void luv_spawn_close_cb(uv_handle_t* handle) {
lua_State *L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
luv_unref_handle(L, (luv_handle_t*)handle->data);
}

Expand Down
2 changes: 1 addition & 1 deletion src/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ static int luv_new_signal(lua_State* L) {
}

static void luv_signal_cb(uv_signal_t* handle, int signum) {
lua_State* L = luv_state(handle->loop);
luv_handle_t* data = (luv_handle_t*)handle->data;
lua_State* L = data->L;
lua_pushstring(L, luv_sig_num_to_string(signum));
luv_call_callback(L, data, LUV_SIGNAL, 1);
}
Expand Down
Loading

0 comments on commit f975ede

Please sign in to comment.