Repository navigation
fix(windows): close worker libuv loop #24811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -654,19 +654,28 @@ pub const Loop = extern struct { | |
| return null; | ||
| } | ||
|
|
||
| pub fn close(ptr: *Loop) void { | ||
| _ = uv_loop_close(ptr); | ||
| fn closeWalkCb(handle: ?*uv_handle_t, data: ?*anyopaque) callconv(.c) void { | ||
| _ = data; | ||
| const h = handle.?; | ||
| if (uv_is_closing(h) == 0) { | ||
| uv_close(h, null); | ||
| } | ||
| } | ||
|
|
||
| pub fn new() ?*Loop { | ||
| const ptr = bun.default_allocator.create(Loop) catch return null; | ||
| if (init(ptr) != null) return null; | ||
| return ptr; | ||
| } | ||
| pub fn shutdown() void { | ||
| const loop = threadlocal_loop orelse { | ||
| return; | ||
| }; | ||
|
|
||
| if (uv_loop_close(loop).errEnum()) |err| { | ||
| if (err == .BUSY) { | ||
| uv_walk(loop, &closeWalkCb, null); | ||
| _ = uv_run(loop, .default); | ||
| bun.debugAssert(uv_loop_close(loop) == .zero); | ||
| } | ||
| } | ||
|
|
||
| pub fn delete(ptr: *Loop) void { | ||
| close(ptr); | ||
| bun.default_allocator.destroy(ptr); | ||
| threadlocal_loop = null; | ||
| } | ||
|
Comment on lines
+665
to
679
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider release-build error handling for final close failure. The shutdown sequence correctly follows the libuv pattern: close → walk handles → run loop → close again. The In release builds where assertions are disabled, if if (uv_loop_close(loop).errEnum()) |err| {
if (err == .BUSY) {
uv_walk(loop, &closeWalkCb, null);
_ = uv_run(loop, .default);
if (uv_loop_close(loop).errEnum()) |final_err| {
if (comptime bun.Environment.allow_assert) {
bun.assert(false); // Should not happen
} else {
log("uv_loop_close failed after cleanup: {s}", .{@tagName(final_err)});
}
}
} else {
// Non-BUSY error, log it
log("uv_loop_close failed: {s}", .{@tagName(err)});
}
}🤖 Prompt for AI Agents |
||
|
|
||
| threadlocal var threadlocal_loop_data: Loop = undefined; | ||
|
|
@@ -2120,7 +2129,7 @@ pub const uv_free_func = ?*const fn (?*anyopaque) callconv(.c) void; | |
| pub extern fn uv_library_shutdown() void; | ||
| pub extern fn uv_replace_allocator(malloc_func: uv_malloc_func, realloc_func: uv_realloc_func, calloc_func: uv_calloc_func, free_func: uv_free_func) c_int; | ||
| pub extern fn uv_loop_init(loop: *uv_loop_t) ReturnCode; | ||
| pub extern fn uv_loop_close(loop: *uv_loop_t) c_int; | ||
| pub extern fn uv_loop_close(loop: *uv_loop_t) ReturnCode; | ||
| pub extern fn uv_loop_new() *uv_loop_t; | ||
| pub extern fn uv_loop_delete(*uv_loop_t) void; | ||
| pub extern fn uv_loop_size() usize; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
LGTM: Cleanup callback correctly guards against double-close.
The
closeWalkCbproperly checksuv_is_closingbefore callinguv_close, preventing double-close attempts. The null callback is acceptable for cleanup scenarios.Consider adding debug-only logging to track which handles are being cleaned up, which could aid troubleshooting:
fn closeWalkCb(handle: ?*uv_handle_t, data: ?*anyopaque) callconv(.c) void { _ = data; const h = handle.?; if (uv_is_closing(h) == 0) { + if (comptime bun.Environment.isDebug) { + log("closeWalkCb: closing handle type {d}", .{h.type}); + } uv_close(h, null); } }🤖 Prompt for AI Agents