From b48c6736e5cda6ace9a91e484b42ed93805e5962 Mon Sep 17 00:00:00 2001 From: Georgijs <48869301+gvilums@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:12:03 -0700 Subject: [PATCH 1/3] (green ci) fix issue in workers and process deinit (#10715) Co-authored-by: gvilums --- src/bun.js/api/bun/subprocess.zig | 18 +++++++++++++++--- src/bun.js/bindings/BunWorkerGlobalScope.h | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 9133bc3c61..c09f9e9164 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -176,7 +176,7 @@ pub const Subprocess = struct { }; } }; - process: *Process = undefined, + process: *Process, stdin: Writable, stdout: Readable, stderr: Readable, @@ -208,6 +208,7 @@ pub const Subprocess = struct { is_sync: bool = false, killed: bool = false, has_stdin_destructor_called: bool = false, + finalized: bool = false, }; pub const SignalCode = bun.SignalCode; @@ -672,7 +673,13 @@ pub const Subprocess = struct { this.flags.has_stdin_destructor_called = true; this.weak_file_sink_stdin_ptr = null; - this.updateHasPendingActivity(); + if (this.flags.finalized) { + // if the process has already been garbage collected, we can free the memory now + bun.default_allocator.destroy(this); + } else { + // otherwise update the pending activity flag + this.updateHasPendingActivity(); + } } pub fn doSend(this: *Subprocess, global: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue { @@ -1514,7 +1521,12 @@ pub const Subprocess = struct { this.process.detach(); this.process.deref(); - bun.default_allocator.destroy(this); + + this.flags.finalized = true; + if (this.weak_file_sink_stdin_ptr == null) { + // if no file sink exists we can free immediately + bun.default_allocator.destroy(this); + } } pub fn getExited( diff --git a/src/bun.js/bindings/BunWorkerGlobalScope.h b/src/bun.js/bindings/BunWorkerGlobalScope.h index f8e0be52e9..e1ac3636c6 100644 --- a/src/bun.js/bindings/BunWorkerGlobalScope.h +++ b/src/bun.js/bindings/BunWorkerGlobalScope.h @@ -18,7 +18,7 @@ class MessagePortChannelProviderImpl; class GlobalScope : public RefCounted, public EventTargetWithInlineData { WTF_MAKE_ISO_ALLOCATED(GlobalScope); - uint32_t m_messageEventCount; + uint32_t m_messageEventCount{0}; static void onDidChangeListenerImpl(EventTarget&, const AtomString&, OnDidChangeListenerKind); From 3106b890ac5b38409fde819650c080eb9c3fbfb2 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Wed, 1 May 2024 01:27:12 -0700 Subject: [PATCH 2/3] Skip threadlocal destructors at exit on Windows (#10723) --- packages/bun-uws/src/Loop.h | 9 +++++++-- src/Global.zig | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/bun-uws/src/Loop.h b/packages/bun-uws/src/Loop.h index 7311dd9765..ce4f3da95a 100644 --- a/packages/bun-uws/src/Loop.h +++ b/packages/bun-uws/src/Loop.h @@ -25,6 +25,8 @@ #include #include +extern "C" int bun_is_exiting(); + namespace uWS { struct Loop { private: @@ -89,14 +91,17 @@ private: /* What to do with loops created with existingNativeLoop? */ struct LoopCleaner { ~LoopCleaner() { - if(loop && cleanMe) { + // There's no need to call this destructor if Bun is in the process of exiting. + // This is both a performance thing, and also to prevent freeing some things which are not meant to be freed + // such as uv_tty_t + if(loop && cleanMe && !bun_is_exiting()) { loop->free(); } } Loop *loop = nullptr; bool cleanMe = false; }; - + static LoopCleaner &getLazyLoop() { static thread_local LoopCleaner lazyLoop; return lazyLoop; diff --git a/src/Global.zig b/src/Global.zig index bddb8e767f..58e0acf845 100644 --- a/src/Global.zig +++ b/src/Global.zig @@ -98,7 +98,17 @@ pub fn exit(code: u8) noreturn { exitWide(@as(u32, code)); } +var is_exiting = std.atomic.Value(bool).init(false); +export fn bun_is_exiting() c_int { + return @intFromBool(isExiting()); +} +pub fn isExiting() bool { + return is_exiting.load(.Monotonic); +} + pub fn exitWide(code: u32) noreturn { + is_exiting.store(true, .Monotonic); + if (comptime Environment.isMac) { std.c.exit(@bitCast(code)); } From a38b3102b61eaa4d903228ee76b864634c811d77 Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Wed, 1 May 2024 01:28:04 -0700 Subject: [PATCH 3/3] override `std.mem.indexOfSentinel` (#10721) --- src/bun.zig | 24 +++++------------------- src/c.zig | 2 ++ src/deps/zig | 2 +- src/main.zig | 23 ++++++++++++++++++++++- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/bun.zig b/src/bun.zig index 993d164625..f82bb8d34a 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -226,20 +226,6 @@ pub inline fn cast(comptime To: type, value: anytype) To { return @ptrCast(@alignCast(value)); } -extern fn strlen(ptr: [*c]const u8) usize; - -pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { - if (Elem == u8 and sentinel == 0) { - return strlen(ptr); - } else { - var i: usize = 0; - while (ptr[i] != sentinel) { - i += 1; - } - return i; - } -} - pub fn len(value: anytype) usize { return switch (@typeInfo(@TypeOf(value))) { .Array => |info| info.len, @@ -260,11 +246,11 @@ pub fn len(value: anytype) usize { @compileError("length of pointer with no sentinel"); const sentinel = @as(*align(1) const info.child, @ptrCast(sentinel_ptr)).*; - return indexOfSentinel(info.child, sentinel, value); + return std.mem.indexOfSentinel(info.child, sentinel, value); }, .C => { assert(value != null); - return indexOfSentinel(info.child, 0, value); + return std.mem.indexOfSentinel(info.child, 0, value); }, .Slice => value.len, }, @@ -1318,7 +1304,7 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize { if (array_info.sentinel) |sentinel_ptr| { const sentinel = @as(*align(1) const array_info.child, @ptrCast(sentinel_ptr)).*; if (sentinel == end) { - return indexOfSentinel(array_info.child, end, ptr); + return std.mem.indexOfSentinel(array_info.child, end, ptr); } } return std.mem.indexOfScalar(array_info.child, ptr, end) orelse array_info.len; @@ -1336,13 +1322,13 @@ fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize { }, .C => { assert(ptr != null); - return indexOfSentinel(ptr_info.child, end, ptr); + return std.mem.indexOfSentinel(ptr_info.child, end, ptr); }, .Slice => { if (ptr_info.sentinel) |sentinel_ptr| { const sentinel = @as(*align(1) const ptr_info.child, @ptrCast(sentinel_ptr)).*; if (sentinel == end) { - return indexOfSentinel(ptr_info.child, sentinel, ptr); + return std.mem.indexOfSentinel(ptr_info.child, sentinel, ptr); } } return std.mem.indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len; diff --git a/src/c.zig b/src/c.zig index 5e74b804f3..3ec860c48c 100644 --- a/src/c.zig +++ b/src/c.zig @@ -468,3 +468,5 @@ pub extern "C" fn Bun__ttySetMode(fd: c_int, mode: c_int) c_int; pub extern "C" fn bun_initialize_process() void; pub extern "C" fn bun_restore_stdio() void; pub extern "C" fn open_as_nonblocking_tty(i32, i32) i32; + +pub extern fn strlen(ptr: [*c]const u8) usize; diff --git a/src/deps/zig b/src/deps/zig index 7fe33d94ea..d5b5fb3182 160000 --- a/src/deps/zig +++ b/src/deps/zig @@ -1 +1 @@ -Subproject commit 7fe33d94eaeb1af7705e9c5f43a3b243aa895436 +Subproject commit d5b5fb31828640ce3cd552f18ca74c2eb05993ad diff --git a/src/main.zig b/src/main.zig index 5d6800ecca..51802b9c10 100644 --- a/src/main.zig +++ b/src/main.zig @@ -20,7 +20,6 @@ comptime { extern fn bun_warn_avx_missing(url: [*:0]const u8) void; pub extern "C" var _environ: ?*anyopaque; pub extern "C" var environ: ?*anyopaque; - pub fn main() void { bun.crash_handler.init(); @@ -51,3 +50,25 @@ pub fn main() void { bun.CLI.Cli.start(bun.default_allocator); bun.Global.exit(0); } + +pub const overrides = struct { + pub const mem = struct { + extern "C" fn wcslen(s: [*:0]const u16) usize; + + pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize { + if (comptime T == u16 and sentinel == 0 and Environment.isWindows) { + return wcslen(p); + } + + if (comptime T == u8 and sentinel == 0) { + return bun.C.strlen(p); + } + + var i: usize = 0; + while (p[i] != sentinel) { + i += 1; + } + return i; + } + }; +};