Skip to content

Commit

Permalink
Check handle to close in current loop when loop_gc
Browse files Browse the repository at this point in the history
* Fix luvit#437
* Fix luvit#599
  • Loading branch information
zhaozg committed May 26, 2023
1 parent 16bbffd commit 66b0fd8
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static int luv_is_closing(lua_State* L) {
static void luv_close_cb(uv_handle_t* handle) {
lua_State* L;
luv_handle_t* data = (luv_handle_t*)handle->data;
if (!data) return;
if (!data || !handle->loop || !data->ctx->loop) return;
L = data->ctx->L;
luv_call_callback(L, data, LUV_CLOSED, 0);
luv_unref_handle(L, data);
Expand Down
17 changes: 14 additions & 3 deletions src/luv.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,19 +794,30 @@ LUALIB_API void luv_set_cthread(lua_State* L, luv_CFcpcall cpcall) {

static void walk_cb(uv_handle_t *handle, void *arg)
{
(void)arg;
if (!uv_is_closing(handle)) {
uv_loop_t* loop = arg;
if (handle->loop == loop && !uv_is_closing(handle)) {
uv_close(handle, luv_close_cb);
}
}

static int loop_gc(lua_State *L) {
luv_ctx_t *ctx = luv_context(L);
uv_loop_t* loop = ctx->loop;
#if LUV_UV_VERSION_GEQ(1, 45, 0)
uv_metrics_t metrics;
#endif

if (loop==NULL)
return 0;

#if LUV_UV_VERSION_GEQ(1, 45, 0)
if(uv_metrics_info(loop, &metrics)
|| metrics.loop_count == 0)
return 0;
#endif

// Call uv_close on every active handle
uv_walk(loop, walk_cb, NULL);
uv_walk(loop, walk_cb, loop);
// Run the event loop until all handles are successfully closed
while (uv_loop_close(loop)) {
uv_run(loop, UV_RUN_DEFAULT);
Expand Down
22 changes: 22 additions & 0 deletions tests/manual-test-exit.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--come from https://github.com/luvit/luv/issues/599

-- run `lua manual-test-exit.lua || echo $?`
-- it shoud print `5`

local uv = require('luv')

local function setTimeout(callback, ms)
local timer = uv.new_timer()
timer:start(ms, 0, function()
timer:stop()
timer:close()
callback()
end)
return timer
end

setTimeout(function()
os.exit(5, true)
end, 1000)

uv.run()
4 changes: 4 additions & 0 deletions tests/manual-test-without-uv.run.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
local uv = require('luv')

local test = uv.new_pipe(false)
uv.close(test)
39 changes: 39 additions & 0 deletions tests/test-loop.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
return require('lib/tap')(function (test)

local function get_cmd()
local i=1
repeat
i=i-1
until not arg[i]
return arg[i+1]
end

local cmd = get_cmd()
local cwd = require('luv').cwd()
print("cmd: ", cmd)
print("cwd: ", cwd)

test("uv.loop_mode", function (print, p, expect, uv)
assert(uv.loop_mode() == nil)
local timer = uv.new_timer()
Expand All @@ -10,4 +23,30 @@ return require('lib/tap')(function (test)
end))
end)

test("issue #437, crash without uv.run", function (print, p, expect, uv)
local handle
handle = uv.spawn(cmd, {
args = { "tests/manual-test-without-uv.run.lua" },
cwd = cwd
},
expect(function(status, signal)
assert(status==0)
assert(signal==0)
handle:close()
end))
end)

test("issue #599, crash during calling os.exit", function (print, p, expect, uv)
local handle
handle = uv.spawn(cmd, {
args = { "tests/manual-test-exit.lua" },
cwd = cwd
},
expect(function(status, signal)
assert(status==5)
assert(signal==0)
handle:close()
end))
end)

end)

0 comments on commit 66b0fd8

Please sign in to comment.