Skip to content

Commit

Permalink
refactor handle gc, that maybe called before close_cb
Browse files Browse the repository at this point in the history
Lua `os.exit` prioritize `userdata` gc, cause `reference` failed.
  • Loading branch information
zhaozg committed May 27, 2023
1 parent 0b97f64 commit b4ead03
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 14 deletions.
37 changes: 23 additions & 14 deletions src/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,27 @@ static int luv_is_closing(lua_State* L) {
return 1;
}

static void luv_handle_free(uv_handle_t* handle) {
luv_handle_t* data = (luv_handle_t*)handle->data;
if (data) {
if (data->extra_gc)
data->extra_gc(data->extra);
free(data);
}
free(handle);
}

static void luv_close_cb(uv_handle_t* handle) {
lua_State* L;
luv_handle_t* data = (luv_handle_t*)handle->data;
if (!data) return;
L = data->ctx->L;
luv_call_callback(L, data, LUV_CLOSED, 0);
luv_unref_handle(L, data);
if(data->ref > 0) {
luv_call_callback(L, data, LUV_CLOSED, 0);
luv_unref_handle(L, data);
} else {
luv_handle_free(handle);
}
}

static int luv_close(lua_State* L) {
Expand All @@ -109,16 +123,6 @@ static int luv_close(lua_State* L) {
return 0;
}

static void luv_handle_free(uv_handle_t* handle) {
luv_handle_t* data = (luv_handle_t*)handle->data;
if (data) {
if (data->extra_gc)
data->extra_gc(data->extra);
free(data);
}
free(handle);
}

static void luv_gc_cb(uv_handle_t* handle) {
luv_close_cb(handle);
luv_handle_free(handle);
Expand All @@ -127,19 +131,24 @@ static void luv_gc_cb(uv_handle_t* handle) {
static int luv_handle_gc(lua_State* L) {
uv_handle_t** udata = (uv_handle_t**)lua_touserdata(L, 1);
uv_handle_t* handle = *udata;
luv_handle_t* data = (luv_handle_t*)handle->data;

// Only cleanup if the handle hasn't been cleaned up yet.
if (handle) {
if (data->ref == LUA_NOREF) {
if (!uv_is_closing(handle)) {
// If the handle is not closed yet, close it first before freeing memory.
uv_close(handle, luv_gc_cb);
uv_close(handle, luv_handle_free);
}
else {
// Otherwise, free the memory right away.
luv_handle_free(handle);
}
// Mark as cleaned up by wiping the dangling pointer.
*udata = NULL;
} else {
// os.exit maybe cause gc before close_cb
// use LUA_REFNIL to tell close_cb to free memory.
data->ref = LUA_REFNIL;
}

return 0;
Expand Down
1 change: 1 addition & 0 deletions src/lhandle.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ static void luv_call_callback(lua_State* L, luv_handle_t* data, luv_callback_id

static void luv_unref_handle(lua_State* L, luv_handle_t* data) {
luaL_unref(L, LUA_REGISTRYINDEX, data->ref);
data->ref = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[0]);
luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[1]);
}
Expand Down

0 comments on commit b4ead03

Please sign in to comment.