From d6fc0c1b4ab93618bb2d860fda6d862abf390a0e Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 27 Nov 2024 17:11:39 -0800 Subject: [PATCH 01/68] Support WTF timers integrating with event loop --- src/bun.js/api/Timer.zig | 100 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 6f9dcb62e34f35..8cd8e26c831bc9 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -722,7 +722,7 @@ pub const EventLoopTimer = struct { state: State = .PENDING, - tag: Tag = .TimerCallback, + tag: Tag, pub const Tag = if (Environment.isWindows) enum { TimerCallback, @@ -731,6 +731,7 @@ pub const EventLoopTimer = struct { StatWatcherScheduler, UpgradedDuplex, WindowsNamedPipe, + WTFTimer, pub fn Type(comptime T: Tag) type { return switch (T) { @@ -740,6 +741,7 @@ pub const EventLoopTimer = struct { .StatWatcherScheduler => StatWatcherScheduler, .UpgradedDuplex => uws.UpgradedDuplex, .WindowsNamedPipe => uws.WindowsNamedPipe, + .WTFTimer => WTFTimer, }; } } else enum { @@ -748,6 +750,7 @@ pub const EventLoopTimer = struct { TestRunner, StatWatcherScheduler, UpgradedDuplex, + WTFTimer, pub fn Type(comptime T: Tag) type { return switch (T) { @@ -756,6 +759,7 @@ pub const EventLoopTimer = struct { .TestRunner => JSC.Jest.TestRunner, .StatWatcherScheduler => StatWatcherScheduler, .UpgradedDuplex => uws.UpgradedDuplex, + .WTFTimer => WTFTimer, }; } }; @@ -810,6 +814,10 @@ pub const EventLoopTimer = struct { switch (this.tag) { inline else => |t| { var container: *t.Type() = @alignCast(@fieldParentPtr("event_loop_timer", this)); + if (comptime t.Type() == WTFTimer) { + return container.fire(now, vm); + } + if (comptime t.Type() == TimerObject) { return container.fire(now, vm); } @@ -839,3 +847,93 @@ pub const EventLoopTimer = struct { }; const timespec = bun.timespec; + +/// A timer created by WTF code and invoked by Bun's event loop +pub const WTFTimer = struct { + /// This is WTF::RunLoop::TimerBase from WebKit + const RunLoopTimer = opaque {}; + + vm: *VirtualMachine, + run_loop_timer: *RunLoopTimer, + event_loop_timer: EventLoopTimer, + repeat: bool, + + pub usingnamespace bun.New(@This()); + + pub fn init(run_loop_timer: *RunLoopTimer, js_vm: *VirtualMachine) *WTFTimer { + const this = WTFTimer.new(.{ + .vm = js_vm, + .event_loop_timer = .{ + .next = timespec.msFromNow(std.math.maxInt(i64)), + .tag = .WTFTimer, + .state = .CANCELLED, + }, + .run_loop_timer = run_loop_timer, + .repeat = false, + }); + + return this; + } + + pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { + this.cancel(); + + // TODO increase precision + const interval = bun.timespec.msFromNow(@intFromFloat(seconds / std.time.ms_per_s)); + this.event_loop_timer.next = interval; + this.vm.timer.insert(&this.event_loop_timer); + this.repeat = repeat; + } + + pub fn cancel(this: *WTFTimer) void { + if (this.event_loop_timer.state == .ACTIVE) { + this.vm.timer.remove(&this.event_loop_timer); + } + } + + pub fn fire(this: *WTFTimer, now: *const bun.timespec, js_vm: *VirtualMachine) EventLoopTimer.Arm { + _ = now; + _ = js_vm; + this.event_loop_timer.state = .FIRED; + WTFTimer__fire(this.run_loop_timer); + return if (this.repeat) + .{ .rearm = this.event_loop_timer.next } + else + .disarm; + } + + pub fn deinit(this: *WTFTimer) void { + this.cancel(); + this.destroy(); + } + + export fn WTFTimer__create(run_loop_timer: *RunLoopTimer) *WTFTimer { + return init(run_loop_timer, VirtualMachine.get()); + } + + export fn WTFTimer__update(this: *WTFTimer, seconds: f64, repeat: bool) void { + this.update(seconds, repeat); + } + + export fn WTFTimer__deinit(this: *WTFTimer) void { + this.deinit(); + } + + export fn WTFTimer__isActive(this: *const WTFTimer) bool { + return this.event_loop_timer.state == .ACTIVE; + } + + export fn WTFTimer__cancel(this: *WTFTimer) void { + this.cancel(); + } + + export fn WTFTimer__secondsUntilTimer(this: *const WTFTimer) f64 { + if (this.event_loop_timer.state == .ACTIVE) { + // TODO increase precision + return @as(f64, @floatFromInt(this.event_loop_timer.next.duration(&bun.timespec.now()).ms())) / std.time.ms_per_s; + } + @panic("TODO"); + } + + extern fn WTFTimer__fire(this: *RunLoopTimer) void; +}; From 2b795f090ed5f996a5b4b71d924da80fb4b28aaa Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 22 Nov 2024 13:42:11 -0800 Subject: [PATCH 02/68] Add regression test for #14982 --- test/regression/issue/14982/14982.test.ts | 17 +++++++++++++++++ test/regression/issue/14982/bun.lockb | Bin 0 -> 3481 bytes test/regression/issue/14982/commander-index.ts | 2 ++ test/regression/issue/14982/index.ts | 1 + test/regression/issue/14982/package.json | 14 ++++++++++++++ test/regression/issue/14982/test-test.ts | 8 ++++++++ 6 files changed, 42 insertions(+) create mode 100644 test/regression/issue/14982/14982.test.ts create mode 100755 test/regression/issue/14982/bun.lockb create mode 100644 test/regression/issue/14982/commander-index.ts create mode 100644 test/regression/issue/14982/index.ts create mode 100644 test/regression/issue/14982/package.json create mode 100644 test/regression/issue/14982/test-test.ts diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts new file mode 100644 index 00000000000000..32a12930ce6e16 --- /dev/null +++ b/test/regression/issue/14982/14982.test.ts @@ -0,0 +1,17 @@ +import { describe, it, expect } from "bun:test"; +import { bunExe } from "../../../harness"; + +it("does not hang running commander", async () => { + const child = Bun.spawn({ + cmd: [bunExe(), "commander-index.ts", "test"], + cwd: __dirname, + stdout: "pipe", + stderr: "inherit", + }); + + await Promise.race([child.exited, Bun.sleep(1000)]); + expect(child.exitCode).toBe(0); + expect(await new Response(child.stdout).text()).toBe("Test command\n"); +}); + +// TODO: test performance in express and memory usage with abort signals diff --git a/test/regression/issue/14982/bun.lockb b/test/regression/issue/14982/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..5a3c2b1e8c9620cf4fa5ffb2e1acda0bece58782 GIT binary patch literal 3481 zcmd5;dr(wW7{3eagH1qmbxb1`Nm6j{zF=8oUDUx|D642_D(13#SuXC&d+&m5J|G{1 zLJFnfXruW^35S9vt%R1$T+8=x~hwq$wzu)hi z?|k20eo>J!C(FpPXq$|(%fHW3V|#co`fO$)TA6{e+a`pGYS<#_!;{uhNChf7X=s1FK;Ah7-(_YYslKhMDdgd#3cqlBko7(oP4 zC;|_oa2>xs2mTpYO9TWl0DKew9Gp9@e(sH$_EDopoDE5|4H}aA>e0Sq>Qd!J?Qi{V zK2bdA`p9zGoOh!4jZX}+Ya6dk-+XZAu}uZra+~OFqYB5yuA;Jl_Nffr3bJq*NpLSlDp@9r}pdy4Y5Jz8rjX04Z zkKTJ580Jrh?+ookg#V`jpMdc2`ceyLg~mKrea>`}dCgm0*%$Wv-Z&M z?@g$@du!FsGp4oTw~vn>+~iEDZ4G;`p~84O)7+sVvJH#_td-|oq&Yw1W^{VX*j`uRU| zx9%?wPr2j6i|c@{LumVY+EHP>to?SslCs1@u2|{*^+i?9mW+t5kgAT)m!-X&J3usl zeM?zH$(rIp%M)rv7j~6549~D{iHT~xHBW!YhZofoo3QrC;kMKCf@Ejo;@F7+jb-`+ z>9wbm6V_5WhEnn7^W3iQ)Th|xy1iUZeCx6kL*v&q?zI`r? zo>rRFww;?Ks+zv&y&Vx5h2o4H)s2Rv(yk$+q~lsY8)nroL2FX}sN!X1Z`ix$k#R`#3Ka5?R2n@jk^$YTxHN~4#5po=~g zkra~D++xkMhHqGSzdqJALKx~DrtI#R zw7O&&@b)IdHOBr)&eqFPdXf}+C8mb|VAk_qq-7Z+N!wV?V6l)`Zjdt>iqc7xatTYj zD0}u;Nu0!Bq0KgXHWCKBb#{3SEm1$;<~av|fIueFI#o&?Kp#PZYK*>L=v#w&1^tH6 z?@hzwXZL^y?Ta`N7ve#9%!Pb0=HkyS(#}P>@uWgdV5Nl> z6TDH%NrjTsNFYh1y|9LYH}RxWO~(BTCI)gxR>|l6n>T;odb5-@k7CHli#dw187wn6 zhPIh?5=HmbXdb>Af@6(t-f#XAf5dDk6C=Tjo`qi6sl6G#=m5vE6a$=@KT3+yvs3SH z=g+)S6MtN=IHYqJh)84tURXenKrIxHDh0t6I4IW0&<<{bdnyA}Y_wag2AhduayZVx zj+4n4%1pByQ$X4r)?AjfGiI4LMkei^OW_t3P)*M4@&oPO2(UxLVvr>1jdalIX0G^`zNu#@tK+wH_%@ar^+S}6>z3=beFLi%_ literal 0 HcmV?d00001 diff --git a/test/regression/issue/14982/commander-index.ts b/test/regression/issue/14982/commander-index.ts new file mode 100644 index 00000000000000..ea6decfaa99a5b --- /dev/null +++ b/test/regression/issue/14982/commander-index.ts @@ -0,0 +1,2 @@ +import { program } from "commander"; +program.name("test").command("test", "Test command").parse(); diff --git a/test/regression/issue/14982/index.ts b/test/regression/issue/14982/index.ts new file mode 100644 index 00000000000000..f67b2c6454eecf --- /dev/null +++ b/test/regression/issue/14982/index.ts @@ -0,0 +1 @@ +console.log("Hello via Bun!"); \ No newline at end of file diff --git a/test/regression/issue/14982/package.json b/test/regression/issue/14982/package.json new file mode 100644 index 00000000000000..ebdf919da99e40 --- /dev/null +++ b/test/regression/issue/14982/package.json @@ -0,0 +1,14 @@ +{ + "name": "14982", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "commander": "^12.1.0" + } +} \ No newline at end of file diff --git a/test/regression/issue/14982/test-test.ts b/test/regression/issue/14982/test-test.ts new file mode 100644 index 00000000000000..827af4a6629102 --- /dev/null +++ b/test/regression/issue/14982/test-test.ts @@ -0,0 +1,8 @@ +import { Command } from "commander"; + +new Command("test") + .action(() => { + console.log("Test command"); + process.exit(0); + }) + .parse(); From a62b22d28c2f657c6e10370dcc234618c241d635 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 22 Nov 2024 13:51:46 -0800 Subject: [PATCH 03/68] Revert --- test/regression/issue/14982/14982.test.ts | 17 ----------------- test/regression/issue/14982/bun.lockb | Bin 3481 -> 0 bytes test/regression/issue/14982/commander-index.ts | 2 -- test/regression/issue/14982/index.ts | 1 - test/regression/issue/14982/package.json | 14 -------------- test/regression/issue/14982/test-test.ts | 8 -------- 6 files changed, 42 deletions(-) delete mode 100644 test/regression/issue/14982/14982.test.ts delete mode 100755 test/regression/issue/14982/bun.lockb delete mode 100644 test/regression/issue/14982/commander-index.ts delete mode 100644 test/regression/issue/14982/index.ts delete mode 100644 test/regression/issue/14982/package.json delete mode 100644 test/regression/issue/14982/test-test.ts diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts deleted file mode 100644 index 32a12930ce6e16..00000000000000 --- a/test/regression/issue/14982/14982.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { describe, it, expect } from "bun:test"; -import { bunExe } from "../../../harness"; - -it("does not hang running commander", async () => { - const child = Bun.spawn({ - cmd: [bunExe(), "commander-index.ts", "test"], - cwd: __dirname, - stdout: "pipe", - stderr: "inherit", - }); - - await Promise.race([child.exited, Bun.sleep(1000)]); - expect(child.exitCode).toBe(0); - expect(await new Response(child.stdout).text()).toBe("Test command\n"); -}); - -// TODO: test performance in express and memory usage with abort signals diff --git a/test/regression/issue/14982/bun.lockb b/test/regression/issue/14982/bun.lockb deleted file mode 100755 index 5a3c2b1e8c9620cf4fa5ffb2e1acda0bece58782..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3481 zcmd5;dr(wW7{3eagH1qmbxb1`Nm6j{zF=8oUDUx|D642_D(13#SuXC&d+&m5J|G{1 zLJFnfXruW^35S9vt%R1$T+8=x~hwq$wzu)hi z?|k20eo>J!C(FpPXq$|(%fHW3V|#co`fO$)TA6{e+a`pGYS<#_!;{uhNChf7X=s1FK;Ah7-(_YYslKhMDdgd#3cqlBko7(oP4 zC;|_oa2>xs2mTpYO9TWl0DKew9Gp9@e(sH$_EDopoDE5|4H}aA>e0Sq>Qd!J?Qi{V zK2bdA`p9zGoOh!4jZX}+Ya6dk-+XZAu}uZra+~OFqYB5yuA;Jl_Nffr3bJq*NpLSlDp@9r}pdy4Y5Jz8rjX04Z zkKTJ580Jrh?+ookg#V`jpMdc2`ceyLg~mKrea>`}dCgm0*%$Wv-Z&M z?@g$@du!FsGp4oTw~vn>+~iEDZ4G;`p~84O)7+sVvJH#_td-|oq&Yw1W^{VX*j`uRU| zx9%?wPr2j6i|c@{LumVY+EHP>to?SslCs1@u2|{*^+i?9mW+t5kgAT)m!-X&J3usl zeM?zH$(rIp%M)rv7j~6549~D{iHT~xHBW!YhZofoo3QrC;kMKCf@Ejo;@F7+jb-`+ z>9wbm6V_5WhEnn7^W3iQ)Th|xy1iUZeCx6kL*v&q?zI`r? zo>rRFww;?Ks+zv&y&Vx5h2o4H)s2Rv(yk$+q~lsY8)nroL2FX}sN!X1Z`ix$k#R`#3Ka5?R2n@jk^$YTxHN~4#5po=~g zkra~D++xkMhHqGSzdqJALKx~DrtI#R zw7O&&@b)IdHOBr)&eqFPdXf}+C8mb|VAk_qq-7Z+N!wV?V6l)`Zjdt>iqc7xatTYj zD0}u;Nu0!Bq0KgXHWCKBb#{3SEm1$;<~av|fIueFI#o&?Kp#PZYK*>L=v#w&1^tH6 z?@hzwXZL^y?Ta`N7ve#9%!Pb0=HkyS(#}P>@uWgdV5Nl> z6TDH%NrjTsNFYh1y|9LYH}RxWO~(BTCI)gxR>|l6n>T;odb5-@k7CHli#dw187wn6 zhPIh?5=HmbXdb>Af@6(t-f#XAf5dDk6C=Tjo`qi6sl6G#=m5vE6a$=@KT3+yvs3SH z=g+)S6MtN=IHYqJh)84tURXenKrIxHDh0t6I4IW0&<<{bdnyA}Y_wag2AhduayZVx zj+4n4%1pByQ$X4r)?AjfGiI4LMkei^OW_t3P)*M4@&oPO2(UxLVvr>1jdalIX0G^`zNu#@tK+wH_%@ar^+S}6>z3=beFLi%_ diff --git a/test/regression/issue/14982/commander-index.ts b/test/regression/issue/14982/commander-index.ts deleted file mode 100644 index ea6decfaa99a5b..00000000000000 --- a/test/regression/issue/14982/commander-index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { program } from "commander"; -program.name("test").command("test", "Test command").parse(); diff --git a/test/regression/issue/14982/index.ts b/test/regression/issue/14982/index.ts deleted file mode 100644 index f67b2c6454eecf..00000000000000 --- a/test/regression/issue/14982/index.ts +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello via Bun!"); \ No newline at end of file diff --git a/test/regression/issue/14982/package.json b/test/regression/issue/14982/package.json deleted file mode 100644 index ebdf919da99e40..00000000000000 --- a/test/regression/issue/14982/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "14982", - "module": "index.ts", - "type": "module", - "devDependencies": { - "@types/bun": "latest" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "commander": "^12.1.0" - } -} \ No newline at end of file diff --git a/test/regression/issue/14982/test-test.ts b/test/regression/issue/14982/test-test.ts deleted file mode 100644 index 827af4a6629102..00000000000000 --- a/test/regression/issue/14982/test-test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Command } from "commander"; - -new Command("test") - .action(() => { - console.log("Test command"); - process.exit(0); - }) - .parse(); From a8079c14d2fdce1c10c0d997c4e6729e14846e82 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 8 Nov 2024 16:49:27 -0800 Subject: [PATCH 04/68] Cherry-pick memory/perf tests from #14996 --- src/bun.js/bindings/bindings.zig | 9 ++++++--- src/bun.js/module_loader.zig | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 63f5715076d2c8..9247f5e077ddd3 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -6376,16 +6376,19 @@ pub const VM = extern struct { extern fn Bun__JSC_onAfterWait(vm: *VM) void; pub const ReleaseHeapAccess = struct { vm: *VM, - needs_to_release: bool, + needs_to_acquire: bool, pub fn acquire(this: *const ReleaseHeapAccess) void { - if (this.needs_to_release) { + if (this.needs_to_acquire) { Bun__JSC_onAfterWait(this.vm); } } }; + /// Temporarily give up access to the heap, allowing other work to proceed. Call acquire() on + /// the return value at scope exit. If you did not already have heap access, release and acquire + /// are both safe no-ops. pub fn releaseHeapAccess(vm: *VM) ReleaseHeapAccess { - return .{ .vm = vm, .needs_to_release = Bun__JSC_onBeforeWait(vm) != 0 }; + return .{ .vm = vm, .needs_to_acquire = Bun__JSC_onBeforeWait(vm) != 0 }; } pub fn create(heap_type: HeapType) *VM { diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index b3a0b91da9e4ae..8207a87e939609 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -1649,7 +1649,7 @@ pub const ModuleLoader = struct { const heap_access = if (!disable_transpilying) jsc_vm.jsc.releaseHeapAccess() else - JSC.VM.ReleaseHeapAccess{ .vm = jsc_vm.jsc, .needs_to_release = false }; + JSC.VM.ReleaseHeapAccess{ .vm = jsc_vm.jsc, .needs_to_acquire = false }; defer heap_access.acquire(); break :brk jsc_vm.bundler.parseMaybeReturnFileOnly( From 4977c0db6c2a50327900122dfad1aa17e1d4ddfd Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 8 Nov 2024 16:57:26 -0800 Subject: [PATCH 05/68] Kill zombie processes with SIGKILL instead of SIGTERM in test runner --- src/bun.js/javascript.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 8b8e8b6c1520bc..545697f028514e 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -743,7 +743,7 @@ const AutoKiller = struct { while (this.processes.popOrNull()) |process| { if (!process.key.hasExited()) { log("process.kill {d}", .{process.key.pid}); - count += @as(u32, @intFromBool(process.key.kill(bun.SignalCode.default) == .result)); + count += @as(u32, @intFromBool(process.key.kill(bun.SignalCode.SIGKILL) == .result)); } } return count; From 3714111694ce2250e2b455d6bfbefb1a575c0e82 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 8 Nov 2024 19:03:12 -0800 Subject: [PATCH 06/68] WIP regression testing for #14982 --- test/regression/issue/14982/14982.test.ts | 33 ++++++++++++++++++ test/regression/issue/14982/README.md | 15 ++++++++ test/regression/issue/14982/bun.lockb | Bin 0 -> 3481 bytes .../issue/14982/commander-hang.fixture.ts | 3 ++ test/regression/issue/14982/package.json | 14 ++++++++ test/regression/issue/14982/raise.js | 7 ++++ test/regression/issue/14982/raiser.c | 8 +++++ test/regression/issue/14982/test-test.ts | 8 +++++ test/regression/issue/14982/tsconfig.json | 27 ++++++++++++++ 9 files changed, 115 insertions(+) create mode 100644 test/regression/issue/14982/14982.test.ts create mode 100644 test/regression/issue/14982/README.md create mode 100755 test/regression/issue/14982/bun.lockb create mode 100644 test/regression/issue/14982/commander-hang.fixture.ts create mode 100644 test/regression/issue/14982/package.json create mode 100644 test/regression/issue/14982/raise.js create mode 100644 test/regression/issue/14982/raiser.c create mode 100644 test/regression/issue/14982/test-test.ts create mode 100644 test/regression/issue/14982/tsconfig.json diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts new file mode 100644 index 00000000000000..ace341acdb6e98 --- /dev/null +++ b/test/regression/issue/14982/14982.test.ts @@ -0,0 +1,33 @@ +import { expect, test, it, describe } from "bun:test"; +import { bunEnv, bunExe } from "../../../harness"; +import { join } from "path"; + +describe("issue 14982", () => { + it("does not hang in commander", async () => { + const process = Bun.spawn([bunExe(), join(__dirname, "commander-hang.fixture.ts"), "test"], { + stdin: "inherit", + stdout: "pipe", + stderr: "inherit", + env: bunEnv, + }); + await process.exited; + expect(process.exitCode).toBe(0); + expect(await new Response(process.stdout).text()).toBe("Test command\n"); + }, 1000); + + it("does not crash when sent SIGUSR1 by a child", async () => { + const process = Bun.spawn([bunExe(), join(__dirname, "raise.js")], { + stdin: "inherit", + stdout: "pipe", + stderr: "inherit", + env: bunEnv, + }); + await process.exited; + expect(process.exitCode).toBe(0); + expect(await new Response(process.stdout).text()).toBe("exited with 0\n"); + }); + + // does not slow down express + // does not slow down fastify + // decreases AbortSignal spam memory usage +}); diff --git a/test/regression/issue/14982/README.md b/test/regression/issue/14982/README.md new file mode 100644 index 00000000000000..ad07fd3a732013 --- /dev/null +++ b/test/regression/issue/14982/README.md @@ -0,0 +1,15 @@ +# 14982 + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.1.34. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/test/regression/issue/14982/bun.lockb b/test/regression/issue/14982/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..aef5d3a1b60aad5f951277cefbd9068bc6d0b343 GIT binary patch literal 3481 zcmd5;Yfuwc6y895kSZt*j@2STD=IOY2O$KBK|9zNQxJ6U{Rqj11oMF14Ug0+)W@J= zg=(u~9j#(pip7dk9V>%YdCd5#mZ~FYozbeaTE(_F)u~|5-Ruo$Qbc`N5{Cse{BQz}e&EtK?)g>#6JKp&< z>r_eTt&!#O*=wWrO^gq6>Y8q*ZLY02v8ixdcC&Tc=%Vq`6;vkBK9`|eK^6`p0nP_! zB%X#7<7Wa+19*f*gTF|a`8SN;2w`Y{j34PA=6#FtH{i(xz@s{#9D=(w5J^|t3^`#ch2#J2V`l9JH{jig*b!9q_Ck||p2O6vO=ba(n z-J4YTd;5xtbEehe_fAfHvDuYWbA9kz=c=xcQOW|BT^kZ~@qiC6t{XbGFxsSiV`$jS zaqcP7t-I5k%;`hky=031th#ye+qV`})t2rX8{a|B`{_<+>c%6VTk2XnQ&zr2O^X`w zAbacn^6;eJe0XskI9|u0smFy4@{YUx)|AB`c1vaZ*A-W_*fJs>1y^-`y(H!J>;asreq)~qTCT^d&-y1cWzaae})+vlbp_TfeK#3rmcR^N8kx-ikzR3M!k&{URs zFumq%V%%!VVki}FzQpc4syV|f)$d|0k!gxXL3ur+U$@Ds4%C0tCqH+#bh8hyZ=VaJ zrj{nOZD(H?8Qfh}yG$^O8tjvcO_c7uYu8a#kZ&^?~_P{J> z|JfH#-#%FXrG3i*jbnZEh3cr?+jG}03lD9N8RJ_a?1;4Ola#cW)Kh!M>?m3L z0;*Q}5 z?v3HmTs+4SqedJ&eLlla98MGEht4Mo2vM-i(+*0G&E+szjn@A>ly4Z&_%3B!55@NE nQt}x<=QA>{S3Ot4HGrq+e$wc!BM@{iU~>)0@p#&z_x=4Fv^0U0 literal 0 HcmV?d00001 diff --git a/test/regression/issue/14982/commander-hang.fixture.ts b/test/regression/issue/14982/commander-hang.fixture.ts new file mode 100644 index 00000000000000..5430ca3a6bbcfb --- /dev/null +++ b/test/regression/issue/14982/commander-hang.fixture.ts @@ -0,0 +1,3 @@ +import { program } from "commander"; + +program.name("test").command("test", "Test command").parse(); diff --git a/test/regression/issue/14982/package.json b/test/regression/issue/14982/package.json new file mode 100644 index 00000000000000..645f52c271333c --- /dev/null +++ b/test/regression/issue/14982/package.json @@ -0,0 +1,14 @@ +{ + "name": "14982", + "module": "commander-hang.fixture.ts", + "type": "module", + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "commander": "^12.1.0" + } +} diff --git a/test/regression/issue/14982/raise.js b/test/regression/issue/14982/raise.js new file mode 100644 index 00000000000000..c81fb1fdef9eb9 --- /dev/null +++ b/test/regression/issue/14982/raise.js @@ -0,0 +1,7 @@ +import { spawn } from "node:child_process"; +import { join } from "path"; + +const child = spawn(join(import.meta.dirname, "./raiser"), [], { stdio: "inherit" }); +child.on("close", code => { + console.log(`exited with ${code}`); +}); diff --git a/test/regression/issue/14982/raiser.c b/test/regression/issue/14982/raiser.c new file mode 100644 index 00000000000000..44702688f589e1 --- /dev/null +++ b/test/regression/issue/14982/raiser.c @@ -0,0 +1,8 @@ +#include +#include + +int main(void) { + usleep(250000); + kill(getppid(), SIGUSR1); + return 0; +} diff --git a/test/regression/issue/14982/test-test.ts b/test/regression/issue/14982/test-test.ts new file mode 100644 index 00000000000000..827af4a6629102 --- /dev/null +++ b/test/regression/issue/14982/test-test.ts @@ -0,0 +1,8 @@ +import { Command } from "commander"; + +new Command("test") + .action(() => { + console.log("Test command"); + process.exit(0); + }) + .parse(); diff --git a/test/regression/issue/14982/tsconfig.json b/test/regression/issue/14982/tsconfig.json new file mode 100644 index 00000000000000..238655f2ce24cd --- /dev/null +++ b/test/regression/issue/14982/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} From 9cd542694a4b2feaf790012ec8b5fac2b3b48236 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 8 Nov 2024 19:03:41 -0800 Subject: [PATCH 07/68] Fix compile error --- src/bun.js/javascript.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 545697f028514e..8ca9f2b60db5d9 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -743,7 +743,7 @@ const AutoKiller = struct { while (this.processes.popOrNull()) |process| { if (!process.key.hasExited()) { log("process.kill {d}", .{process.key.pid}); - count += @as(u32, @intFromBool(process.key.kill(bun.SignalCode.SIGKILL) == .result)); + count += @as(u32, @intFromBool(process.key.kill(@intFromEnum(bun.SignalCode.SIGKILL)) == .result)); } } return count; From 62a26a6f85dee12d1629d88f0bfed5280c35f80f Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 11 Nov 2024 13:32:50 -0800 Subject: [PATCH 08/68] Test server performance in #14982 regression test --- test/regression/issue/14982/14982.test.ts | 56 +++++++++++++++++- test/regression/issue/14982/bun.lockb | Bin 3481 -> 44341 bytes test/regression/issue/14982/express-server.js | 20 +++++++ .../regression/issue/14982/fastify-server.mjs | 20 +++++++ test/regression/issue/14982/package.json | 4 +- 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 test/regression/issue/14982/express-server.js create mode 100644 test/regression/issue/14982/fastify-server.mjs diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts index ace341acdb6e98..cf7f9fc4b3a998 100644 --- a/test/regression/issue/14982/14982.test.ts +++ b/test/regression/issue/14982/14982.test.ts @@ -27,7 +27,59 @@ describe("issue 14982", () => { expect(await new Response(process.stdout).text()).toBe("exited with 0\n"); }); - // does not slow down express - // does not slow down fastify + it("does not slow down express", async () => { + // requests per second with bun 1.1.34 on @190n's work laptop + const baseline = 95939; + + const server = Bun.spawn([bunExe(), join(__dirname, "express-server.js")], { + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + + // let it start listening + await Bun.sleep(100); + + const oha = Bun.spawn(["oha", "http://localhost:3000", "-j", "-n", "1000000", "-c", "40"], { + stdin: "inherit", + stdout: "pipe", + stderr: "inherit", + }); + + const results = await new Response(oha.stdout).json(); + const rps = results.summary.requestsPerSec; + const slowdownPercent = ((baseline - rps) / baseline) * 100; + expect(slowdownPercent).toBeLessThan(5); + + server.kill(); + }, 15000); + + it("does not slow down fastify", async () => { + // requests per second with bun 1.1.34 on @190n's work laptop + const baseline = 161178; + + const server = Bun.spawn([bunExe(), join(__dirname, "fastify-server.mjs")], { + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); + + // let it start listening + await Bun.sleep(100); + + const oha = Bun.spawn(["oha", "http://localhost:3000", "-j", "-n", "1000000", "-c", "40"], { + stdin: "inherit", + stdout: "pipe", + stderr: "inherit", + }); + + const results = await new Response(oha.stdout).json(); + const rps = results.summary.requestsPerSec; + const slowdownPercent = ((baseline - rps) / baseline) * 100; + expect(slowdownPercent).toBeLessThan(5); + + server.kill(); + }, 15000); + // decreases AbortSignal spam memory usage }); diff --git a/test/regression/issue/14982/bun.lockb b/test/regression/issue/14982/bun.lockb index aef5d3a1b60aad5f951277cefbd9068bc6d0b343..99f013f3cb221fc1cbc0aa051b3b5349cec1c788 100755 GIT binary patch literal 44341 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 E05qnDVgLXD diff --git a/test/regression/issue/14982/express-server.js b/test/regression/issue/14982/express-server.js new file mode 100644 index 00000000000000..95eddb1aef9335 --- /dev/null +++ b/test/regression/issue/14982/express-server.js @@ -0,0 +1,20 @@ +const express = require("express"); +const app = express(); + +let count = 0; + +app.get("/", (req, res) => { + count++; + if (count >= 1_000_000) { + setTimeout(() => process.exit(0), 1); + } + + if (count % 50_000 === 0) { + console.log("RSS", (process.memoryUsage.rss() / 1024 / 1024) | 0, "MB"); + } + res.send("Hello World!"); +}); + +app.listen(3000, () => { + console.log("Example app listening on port 3000"); +}); diff --git a/test/regression/issue/14982/fastify-server.mjs b/test/regression/issue/14982/fastify-server.mjs new file mode 100644 index 00000000000000..f1a05a976f23bc --- /dev/null +++ b/test/regression/issue/14982/fastify-server.mjs @@ -0,0 +1,20 @@ +import Fastify from "fastify"; + +let startOfLastRequest = performance.now(); +const fastify = Fastify({}); + +// Declare a route +fastify.get("/", (request, reply) => { + const now = performance.now(); + // if (startOfLastRequest && now - startOfLastRequest > 0.5) { + // console.log("Elapsed", Math.trunc(now - startOfLastRequest), "ms"); + // } + // startOfLastRequest = now; + reply.send({ hello: "world" }); +}); + +// Run the server! +fastify.listen({ port: 3000 }, (err, address) => { + if (err) throw err; + // Server is now listening on ${address} +}); diff --git a/test/regression/issue/14982/package.json b/test/regression/issue/14982/package.json index 645f52c271333c..e9b2f92fac32c6 100644 --- a/test/regression/issue/14982/package.json +++ b/test/regression/issue/14982/package.json @@ -9,6 +9,8 @@ "typescript": "^5.0.0" }, "dependencies": { - "commander": "^12.1.0" + "commander": "^12.1.0", + "express": "^4.21.1", + "fastify": "^5.1.0" } } From 6af5b25959dd036735efbed33e1105552fabca18 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Tue, 3 Dec 2024 14:11:15 -0800 Subject: [PATCH 09/68] Make SubtleCrypto use Bun WorkPool instead of WTF::WorkQueue --- .../bindings/webcrypto/CryptoAlgorithm.h | 2 +- .../bindings/webcrypto/PhonyWorkQueue.cpp | 23 +++++++++++++++++++ .../bindings/webcrypto/PhonyWorkQueue.h | 20 ++++++++++++++++ src/bun.js/bindings/webcrypto/SubtleCrypto.h | 4 +++- src/bun.js/event_loop.zig | 20 ++++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp create mode 100644 src/bun.js/bindings/webcrypto/PhonyWorkQueue.h diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithm.h b/src/bun.js/bindings/webcrypto/CryptoAlgorithm.h index 40dbb0ad61b0f7..3e0e52466989b5 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithm.h +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithm.h @@ -35,7 +35,7 @@ #include #include #include -#include +#include "SubtleCrypto.h" #if ENABLE(WEB_CRYPTO) diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp new file mode 100644 index 00000000000000..43f1ecfe45284b --- /dev/null +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp @@ -0,0 +1,23 @@ +#include "PhonyWorkQueue.h" + +#include +#include "EventLoopTask.h" + +using WebCore::EventLoopTask; + +namespace Bun { + +Ref PhonyWorkQueue::create(WTF::ASCIILiteral name) +{ + (void)name; + return adoptRef(*new PhonyWorkQueue); +} + +extern "C" void ConcurrentCppTask__createAndRun(EventLoopTask*); + +void PhonyWorkQueue::dispatch(WTF::Function&& function) +{ + ConcurrentCppTask__createAndRun(new EventLoopTask(WTFMove(function))); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h new file mode 100644 index 00000000000000..8232b0adf50f64 --- /dev/null +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h @@ -0,0 +1,20 @@ +#pragma once + +#include "root.h" + +#include +#include + +namespace Bun { + +// Work queue which really uses CppTask.Concurrent in Bun's event loop (which enqueues into a WorkPool). +// Maintained so that SubtleCrypto functions can pretend they're using a WorkQueue, even though +// WTF::WorkQueue doesn't work and we need to use Bun's equivalent. +class PhonyWorkQueue : public WTF::RefCounted { +public: + static Ref create(WTF::ASCIILiteral name); + + void dispatch(Function&&); +}; + +}; // namespace Bun diff --git a/src/bun.js/bindings/webcrypto/SubtleCrypto.h b/src/bun.js/bindings/webcrypto/SubtleCrypto.h index dbfee4649bf5f2..cd4f68ddb48102 100644 --- a/src/bun.js/bindings/webcrypto/SubtleCrypto.h +++ b/src/bun.js/bindings/webcrypto/SubtleCrypto.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include "PhonyWorkQueue.h" namespace JSC { class ArrayBufferView; @@ -44,6 +44,8 @@ class CallFrame; namespace WebCore { +using WorkQueue = Bun::PhonyWorkQueue; + struct JsonWebKey; class BufferSource; diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 9f70b3a48e339b..595934f3bbbac7 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -299,6 +299,26 @@ pub const CppTask = opaque { JSC.markBinding(@src()); Bun__performTask(global, this); } + + pub const Concurrent = struct { + cpp_task: *CppTask, + workpool_task: JSC.WorkPoolTask = .{ .callback = &runFromWorkpool }, + + pub fn runFromWorkpool(task: *JSC.WorkPoolTask) void { + var this: *Concurrent = @fieldParentPtr("workpool_task", task); + const cpp_task = this.cpp_task; + this.destroy(); + // TODO figure out what this should be + cpp_task.run(undefined); + } + + pub usingnamespace bun.New(@This()); + }; + + pub export fn ConcurrentCppTask__createAndRun(cpp_task: *CppTask) void { + const cpp = Concurrent.new(.{ .cpp_task = cpp_task }); + JSC.WorkPool.schedule(&cpp.workpool_task); + } }; pub const JSCScheduler = struct { pub const JSCDeferredWorkTask = opaque { From 06a894fafc11413c90b2cc74f1502f1c08f81be9 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 4 Dec 2024 13:07:10 -0800 Subject: [PATCH 10/68] Specify WebKit version using commit from oven-sh/WebKit#70 --- cmake/tools/SetupWebKit.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index e7cb26be5e59b4..ccf98388ae7414 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION 8f9ae4f01a047c666ef548864294e01df731d4ea) + set(WEBKIT_VERSION f12e277d2f5b5f0ddb0f502d9f86a8037158833a) endif() if(WEBKIT_LOCAL) From 351eda5c4e76fc1eff3c9c2fdfe2224c39ad5e73 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 4 Dec 2024 13:12:52 -0800 Subject: [PATCH 11/68] Release heap access while waiting for events (the change from #14996) --- src/bun.js/bindings/BunJSCEventLoop.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/bun.js/bindings/BunJSCEventLoop.cpp b/src/bun.js/bindings/BunJSCEventLoop.cpp index 30498f1be9157e..05a7096374c2ef 100644 --- a/src/bun.js/bindings/BunJSCEventLoop.cpp +++ b/src/bun.js/bindings/BunJSCEventLoop.cpp @@ -5,19 +5,17 @@ extern "C" int Bun__JSC_onBeforeWait(JSC::VM* vm) { - UNUSED_PARAM(vm); // TODO: use JSC timers, run the incremental sweeper. // That will fix this. // In the meantime, we're disabling this due to https://github.com/oven-sh/bun/issues/14982 - // if (vm->heap.hasAccess()) { - // vm->heap.releaseAccess(); - // return 1; - // } + if (vm->heap.hasAccess()) { + vm->heap.releaseAccess(); + return 1; + } return 0; } extern "C" void Bun__JSC_onAfterWait(JSC::VM* vm) { - UNUSED_PARAM(vm); - // vm->heap.acquireAccess(); + vm->heap.acquireAccess(); } From f606c1061d81b3a9e36e6c327414364d96e3207c Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 4 Dec 2024 13:14:28 -0800 Subject: [PATCH 12/68] Fix PhonyWorkQueue --- .../bindings/EventLoopTaskNoContext.cpp | 12 ++++++ src/bun.js/bindings/EventLoopTaskNoContext.h | 28 +++++++++++++ .../bindings/webcrypto/PhonyWorkQueue.cpp | 8 ++-- src/bun.js/event_loop.zig | 40 +++++++++++++------ 4 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 src/bun.js/bindings/EventLoopTaskNoContext.cpp create mode 100644 src/bun.js/bindings/EventLoopTaskNoContext.h diff --git a/src/bun.js/bindings/EventLoopTaskNoContext.cpp b/src/bun.js/bindings/EventLoopTaskNoContext.cpp new file mode 100644 index 00000000000000..2695ecb84f5a04 --- /dev/null +++ b/src/bun.js/bindings/EventLoopTaskNoContext.cpp @@ -0,0 +1,12 @@ +#include "EventLoopTaskNoContext.h" + +namespace Bun { + +WTF_MAKE_ISO_ALLOCATED_IMPL(EventLoopTaskNoContext); + +extern "C" void Bun__EventLoopTaskNoContext__performTask(EventLoopTaskNoContext* task) +{ + task->performTask(); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/EventLoopTaskNoContext.h b/src/bun.js/bindings/EventLoopTaskNoContext.h new file mode 100644 index 00000000000000..ee4ef6eab6db82 --- /dev/null +++ b/src/bun.js/bindings/EventLoopTaskNoContext.h @@ -0,0 +1,28 @@ +#pragma once +#include "root.h" + +namespace Bun { + +// Just like WebCore::EventLoopTask but does not take a ScriptExecutionContext +class EventLoopTaskNoContext { + WTF_MAKE_ISO_ALLOCATED(EventLoopTaskNoContext); + +public: + EventLoopTaskNoContext(Function&& task) + : m_task(WTFMove(task)) + { + } + + void performTask() + { + m_task(); + delete this; + } + +private: + Function m_task; +}; + +extern "C" void Bun__EventLoopTaskNoContext__performTask(EventLoopTaskNoContext* task); + +} // namespace Bun diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp index 43f1ecfe45284b..1657db4bcfac49 100644 --- a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp @@ -1,9 +1,7 @@ #include "PhonyWorkQueue.h" #include -#include "EventLoopTask.h" - -using WebCore::EventLoopTask; +#include "EventLoopTaskNoContext.h" namespace Bun { @@ -13,11 +11,11 @@ Ref PhonyWorkQueue::create(WTF::ASCIILiteral name) return adoptRef(*new PhonyWorkQueue); } -extern "C" void ConcurrentCppTask__createAndRun(EventLoopTask*); +extern "C" void ConcurrentCppTask__createAndRun(EventLoopTaskNoContext* task); void PhonyWorkQueue::dispatch(WTF::Function&& function) { - ConcurrentCppTask__createAndRun(new EventLoopTask(WTFMove(function))); + ConcurrentCppTask__createAndRun(new EventLoopTaskNoContext(WTFMove(function))); } } // namespace Bun diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 595934f3bbbac7..75e48a12356c59 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -299,27 +299,41 @@ pub const CppTask = opaque { JSC.markBinding(@src()); Bun__performTask(global, this); } +}; - pub const Concurrent = struct { - cpp_task: *CppTask, - workpool_task: JSC.WorkPoolTask = .{ .callback = &runFromWorkpool }, +pub const ConcurrentCppTask = struct { + cpp_task: *EventLoopTaskNoContext, + workpool_task: JSC.WorkPoolTask = .{ .callback = &runFromWorkpool }, - pub fn runFromWorkpool(task: *JSC.WorkPoolTask) void { - var this: *Concurrent = @fieldParentPtr("workpool_task", task); - const cpp_task = this.cpp_task; - this.destroy(); - // TODO figure out what this should be - cpp_task.run(undefined); - } + const EventLoopTaskNoContext = opaque { + extern fn Bun__EventLoopTaskNoContext__performTask(task: *EventLoopTaskNoContext) void; - pub usingnamespace bun.New(@This()); + /// Deallocates `this` + pub fn run(this: *EventLoopTaskNoContext) void { + Bun__EventLoopTaskNoContext__performTask(this); + } }; - pub export fn ConcurrentCppTask__createAndRun(cpp_task: *CppTask) void { - const cpp = Concurrent.new(.{ .cpp_task = cpp_task }); + pub fn runFromWorkpool(task: *JSC.WorkPoolTask) void { + var this: *ConcurrentCppTask = @fieldParentPtr("workpool_task", task); + const cpp_task = this.cpp_task; + this.destroy(); + cpp_task.run(); + } + + pub usingnamespace bun.New(@This()); + + pub export fn ConcurrentCppTask__createAndRun(cpp_task: *EventLoopTaskNoContext) void { + JSC.markBinding(@src()); + const cpp = ConcurrentCppTask.new(.{ .cpp_task = cpp_task }); JSC.WorkPool.schedule(&cpp.workpool_task); } }; + +comptime { + _ = ConcurrentCppTask.ConcurrentCppTask__createAndRun; +} + pub const JSCScheduler = struct { pub const JSCDeferredWorkTask = opaque { extern fn Bun__runDeferredWork(task: *JSCScheduler.JSCDeferredWorkTask) void; From 7bc87b370b70033ddfa83ee6696962fbc59ab610 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 5 Dec 2024 18:47:17 -0800 Subject: [PATCH 13/68] Address todos --- src/bun.js/api/Timer.zig | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 8cd8e26c831bc9..596748d6a6f708 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -878,8 +878,15 @@ pub const WTFTimer = struct { pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { this.cancel(); - // TODO increase precision - const interval = bun.timespec.msFromNow(@intFromFloat(seconds / std.time.ms_per_s)); + const modf = std.math.modf(seconds); + var interval = bun.timespec.now(); + interval.sec += @intFromFloat(modf.ipart); + interval.nsec += @intFromFloat(modf.fpart * std.time.ns_per_s); + if (interval.nsec >= std.time.ns_per_s) { + interval.sec += 1; + interval.nsec -= std.time.ns_per_s; + } + this.event_loop_timer.next = interval; this.vm.timer.insert(&this.event_loop_timer); this.repeat = repeat; @@ -930,9 +937,11 @@ pub const WTFTimer = struct { export fn WTFTimer__secondsUntilTimer(this: *const WTFTimer) f64 { if (this.event_loop_timer.state == .ACTIVE) { // TODO increase precision - return @as(f64, @floatFromInt(this.event_loop_timer.next.duration(&bun.timespec.now()).ms())) / std.time.ms_per_s; + const until = this.event_loop_timer.next.duration(&bun.timespec.now()); + const sec: f64, const nsec: f64 = .{ @floatFromInt(until.sec), @floatFromInt(until.nsec) }; + return sec + nsec / std.time.ns_per_s; } - @panic("TODO"); + return std.math.inf(f64); } extern fn WTFTimer__fire(this: *RunLoopTimer) void; From 33d22416f3292177d06dffdd1d516246f1044fc7 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 5 Dec 2024 18:52:16 -0800 Subject: [PATCH 14/68] Remove outdated comment --- src/bun.js/api/Timer.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 596748d6a6f708..1438335ff6c1ae 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -936,7 +936,6 @@ pub const WTFTimer = struct { export fn WTFTimer__secondsUntilTimer(this: *const WTFTimer) f64 { if (this.event_loop_timer.state == .ACTIVE) { - // TODO increase precision const until = this.event_loop_timer.next.duration(&bun.timespec.now()); const sec: f64, const nsec: f64 = .{ @floatFromInt(until.sec), @floatFromInt(until.nsec) }; return sec + nsec / std.time.ns_per_s; From ef9ed38cef3d36c40ab2c0fd08d43c94bc23906b Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 5 Dec 2024 19:43:34 -0800 Subject: [PATCH 15/68] Clean up #14982 regression test --- test/regression/issue/14982/14982.test.ts | 70 +----------------- test/regression/issue/14982/README.md | 15 ---- test/regression/issue/14982/bun.lockb | Bin 44341 -> 3481 bytes .../issue/14982/commander-hang.fixture.ts | 1 + test/regression/issue/14982/express-server.js | 20 ----- .../regression/issue/14982/fastify-server.mjs | 20 ----- test/regression/issue/14982/package.json | 4 +- test/regression/issue/14982/raise.js | 7 -- test/regression/issue/14982/raiser.c | 8 -- 9 files changed, 3 insertions(+), 142 deletions(-) delete mode 100644 test/regression/issue/14982/README.md delete mode 100644 test/regression/issue/14982/express-server.js delete mode 100644 test/regression/issue/14982/fastify-server.mjs delete mode 100644 test/regression/issue/14982/raise.js delete mode 100644 test/regression/issue/14982/raiser.c diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts index cf7f9fc4b3a998..0141479a0e3e25 100644 --- a/test/regression/issue/14982/14982.test.ts +++ b/test/regression/issue/14982/14982.test.ts @@ -1,4 +1,4 @@ -import { expect, test, it, describe } from "bun:test"; +import { expect, it, describe } from "bun:test"; import { bunEnv, bunExe } from "../../../harness"; import { join } from "path"; @@ -14,72 +14,4 @@ describe("issue 14982", () => { expect(process.exitCode).toBe(0); expect(await new Response(process.stdout).text()).toBe("Test command\n"); }, 1000); - - it("does not crash when sent SIGUSR1 by a child", async () => { - const process = Bun.spawn([bunExe(), join(__dirname, "raise.js")], { - stdin: "inherit", - stdout: "pipe", - stderr: "inherit", - env: bunEnv, - }); - await process.exited; - expect(process.exitCode).toBe(0); - expect(await new Response(process.stdout).text()).toBe("exited with 0\n"); - }); - - it("does not slow down express", async () => { - // requests per second with bun 1.1.34 on @190n's work laptop - const baseline = 95939; - - const server = Bun.spawn([bunExe(), join(__dirname, "express-server.js")], { - stdin: "inherit", - stdout: "inherit", - stderr: "inherit", - }); - - // let it start listening - await Bun.sleep(100); - - const oha = Bun.spawn(["oha", "http://localhost:3000", "-j", "-n", "1000000", "-c", "40"], { - stdin: "inherit", - stdout: "pipe", - stderr: "inherit", - }); - - const results = await new Response(oha.stdout).json(); - const rps = results.summary.requestsPerSec; - const slowdownPercent = ((baseline - rps) / baseline) * 100; - expect(slowdownPercent).toBeLessThan(5); - - server.kill(); - }, 15000); - - it("does not slow down fastify", async () => { - // requests per second with bun 1.1.34 on @190n's work laptop - const baseline = 161178; - - const server = Bun.spawn([bunExe(), join(__dirname, "fastify-server.mjs")], { - stdin: "inherit", - stdout: "inherit", - stderr: "inherit", - }); - - // let it start listening - await Bun.sleep(100); - - const oha = Bun.spawn(["oha", "http://localhost:3000", "-j", "-n", "1000000", "-c", "40"], { - stdin: "inherit", - stdout: "pipe", - stderr: "inherit", - }); - - const results = await new Response(oha.stdout).json(); - const rps = results.summary.requestsPerSec; - const slowdownPercent = ((baseline - rps) / baseline) * 100; - expect(slowdownPercent).toBeLessThan(5); - - server.kill(); - }, 15000); - - // decreases AbortSignal spam memory usage }); diff --git a/test/regression/issue/14982/README.md b/test/regression/issue/14982/README.md deleted file mode 100644 index ad07fd3a732013..00000000000000 --- a/test/regression/issue/14982/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# 14982 - -To install dependencies: - -```bash -bun install -``` - -To run: - -```bash -bun run index.ts -``` - -This project was created using `bun init` in bun v1.1.34. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/test/regression/issue/14982/bun.lockb b/test/regression/issue/14982/bun.lockb index 99f013f3cb221fc1cbc0aa051b3b5349cec1c788..7d6d29d881383c259c015fbc6ebc3951923d69ba 100755 GIT binary patch delta 664 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 { - count++; - if (count >= 1_000_000) { - setTimeout(() => process.exit(0), 1); - } - - if (count % 50_000 === 0) { - console.log("RSS", (process.memoryUsage.rss() / 1024 / 1024) | 0, "MB"); - } - res.send("Hello World!"); -}); - -app.listen(3000, () => { - console.log("Example app listening on port 3000"); -}); diff --git a/test/regression/issue/14982/fastify-server.mjs b/test/regression/issue/14982/fastify-server.mjs deleted file mode 100644 index f1a05a976f23bc..00000000000000 --- a/test/regression/issue/14982/fastify-server.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import Fastify from "fastify"; - -let startOfLastRequest = performance.now(); -const fastify = Fastify({}); - -// Declare a route -fastify.get("/", (request, reply) => { - const now = performance.now(); - // if (startOfLastRequest && now - startOfLastRequest > 0.5) { - // console.log("Elapsed", Math.trunc(now - startOfLastRequest), "ms"); - // } - // startOfLastRequest = now; - reply.send({ hello: "world" }); -}); - -// Run the server! -fastify.listen({ port: 3000 }, (err, address) => { - if (err) throw err; - // Server is now listening on ${address} -}); diff --git a/test/regression/issue/14982/package.json b/test/regression/issue/14982/package.json index e9b2f92fac32c6..645f52c271333c 100644 --- a/test/regression/issue/14982/package.json +++ b/test/regression/issue/14982/package.json @@ -9,8 +9,6 @@ "typescript": "^5.0.0" }, "dependencies": { - "commander": "^12.1.0", - "express": "^4.21.1", - "fastify": "^5.1.0" + "commander": "^12.1.0" } } diff --git a/test/regression/issue/14982/raise.js b/test/regression/issue/14982/raise.js deleted file mode 100644 index c81fb1fdef9eb9..00000000000000 --- a/test/regression/issue/14982/raise.js +++ /dev/null @@ -1,7 +0,0 @@ -import { spawn } from "node:child_process"; -import { join } from "path"; - -const child = spawn(join(import.meta.dirname, "./raiser"), [], { stdio: "inherit" }); -child.on("close", code => { - console.log(`exited with ${code}`); -}); diff --git a/test/regression/issue/14982/raiser.c b/test/regression/issue/14982/raiser.c deleted file mode 100644 index 44702688f589e1..00000000000000 --- a/test/regression/issue/14982/raiser.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -int main(void) { - usleep(250000); - kill(getppid(), SIGUSR1); - return 0; -} From c25469f23a5133ecd412ebec97ee2c2ba913f0f7 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 12 Dec 2024 03:31:36 -0800 Subject: [PATCH 16/68] Update CryptoAlgorithmHMACOpenSSL.cpp --- src/bun.js/bindings/webcrypto/CryptoAlgorithmHMACOpenSSL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmHMACOpenSSL.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmHMACOpenSSL.cpp index 78cbc6f8e86740..c7f5ba08cb761c 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmHMACOpenSSL.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmHMACOpenSSL.cpp @@ -95,7 +95,7 @@ ExceptionOr CryptoAlgorithmHMAC::platformVerifyWithAlgorithm(const CryptoK if (!expectedSignature) return Exception { OperationError }; // Using a constant time comparison to prevent timing attacks. - return signature.size() == expectedSignature->size() && !constantTimeMemcmp(expectedSignature->data(), signature.data(), expectedSignature->size()); + return signature.size() == expectedSignature->size() && !constantTimeMemcmp(expectedSignature->span(), signature.span()); } ExceptionOr CryptoAlgorithmHMAC::platformVerify(const CryptoKeyHMAC& key, const Vector& signature, const Vector& data) @@ -108,7 +108,7 @@ ExceptionOr CryptoAlgorithmHMAC::platformVerify(const CryptoKeyHMAC& key, if (!expectedSignature) return Exception { OperationError }; // Using a constant time comparison to prevent timing attacks. - return signature.size() == expectedSignature->size() && !constantTimeMemcmp(expectedSignature->data(), signature.data(), expectedSignature->size()); + return signature.size() == expectedSignature->size() && !constantTimeMemcmp(expectedSignature->span(), signature.span()); } } // namespace WebCore From 908b8641efc50f247c5fb4f9842ff6979516d10e Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 12 Dec 2024 04:43:11 -0800 Subject: [PATCH 17/68] Partially fix some threadsafety issues in the new timers --- src/bun.js/api/Timer.zig | 108 ++++++++++++++++++----- src/bun.js/api/bun/subprocess.zig | 32 ++++--- src/bun.js/javascript.zig | 6 +- src/bun.js/node/node_fs_stat_watcher.zig | 12 ++- src/bun.js/test/jest.zig | 6 +- 5 files changed, 115 insertions(+), 49 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 1438335ff6c1ae..26657e5ef2c08e 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -27,6 +27,8 @@ const TimerHeap = heap.Intrusive(EventLoopTimer, void, EventLoopTimer.less); pub const All = struct { last_id: i32 = 1, + lock: bun.Lock = .{}, + thread_id: std.Thread.Id, timers: TimerHeap = .{ .context = {}, }, @@ -49,7 +51,15 @@ pub const All = struct { } } = .{}, + pub fn init() @This() { + return .{ + .thread_id = std.Thread.getCurrentId(), + }; + } + pub fn insert(this: *All, timer: *EventLoopTimer) void { + this.lock.lock(); + defer this.lock.unlock(); this.timers.insert(timer); timer.state = .ACTIVE; @@ -59,12 +69,33 @@ pub const All = struct { } pub fn remove(this: *All, timer: *EventLoopTimer) void { + this.lock.lock(); + defer this.lock.unlock(); this.timers.remove(timer); timer.state = .CANCELLED; timer.heap = .{}; } + /// Remove the EventLoopTimer if necessary. + pub fn update(this: *All, timer: *EventLoopTimer, time: *const timespec) void { + this.lock.lock(); + defer this.lock.unlock(); + if (timer.state == .ACTIVE) { + this.timers.remove(timer); + } + + timer.state = .ACTIVE; + if (comptime Environment.isDebug) { + if (&timer.next == time) { + @panic("timer.next == time. For threadsafety reasons, time and timer.next must always be a different pointer."); + } + } + timer.next = time.*; + + this.timers.insert(timer); + } + fn ensureUVTimer(this: *All, vm: *VirtualMachine) void { if (this.uv_timer.data == null) { this.uv_timer.init(vm.uvLoop()); @@ -159,22 +190,40 @@ pub const All = struct { _ = &Bun__internal_drainTimers; } - pub fn drainTimers(this: *All, vm: *VirtualMachine) void { - if (this.timers.peek() == null) { - return; - } + // Getting the current time is expensive on certain platforms. + // We don't want to call it when there are no timers. + // And when we do call it, we want to be sure we only call it once. + // and we do NOT want to hold the lock while the timer is running it's code. + // This function has to be thread-safe. + fn next(this: *All, has_set_now: *bool, now: *timespec) ?*EventLoopTimer { + this.lock.lock(); + defer this.lock.unlock(); - const now = ×pec.now(); - - while (this.timers.peek()) |t| { - if (t.next.greater(now)) { - break; + if (this.timers.peek()) |timer| { + if (!has_set_now.*) { + now.* = timespec.now(); + has_set_now.* = true; } + if (!timer.next.greater(now)) { + return null; + } + + assert(this.timers.deleteMin().? == timer); - assert(this.timers.deleteMin().? == t); + return timer; + } + return null; + } + + pub fn drainTimers(this: *All, vm: *VirtualMachine) void { + // Set in next(). + var now: timespec = undefined; + // Split into a separate variable to avoid increasing the size of the timespec type. + var has_set_now: bool = false; + while (this.next(&has_set_now, &now)) |t| { switch (t.fire( - now, + &now, vm, )) { .disarm => {}, @@ -467,8 +516,7 @@ pub const TimerObject = struct { switch (this.event_loop_timer.state) { .FIRED => { // If we didn't clear the setInterval, reschedule it starting from - this.event_loop_timer.next = time_before_call; - vm.timer.insert(&this.event_loop_timer); + vm.timer.update(&this.event_loop_timer, &time_before_call); if (this.has_js_ref) { this.setEnableKeepingEventLoopAlive(vm, true); @@ -478,10 +526,7 @@ pub const TimerObject = struct { }, .ACTIVE => { // The developer called timer.refresh() synchronously in the callback. - vm.timer.remove(&this.event_loop_timer); - - this.event_loop_timer.next = time_before_call; - vm.timer.insert(&this.event_loop_timer); + vm.timer.update(&this.event_loop_timer, &time_before_call); // Balance out the ref count. // the transition from "FIRED" -> "ACTIVE" caused it to increment. @@ -620,8 +665,7 @@ pub const TimerObject = struct { this.ref(); } - this.event_loop_timer.next = now; - vm.timer.insert(&this.event_loop_timer); + vm.timer.update(&this.event_loop_timer, &now); this.has_cleared_timer = false; if (this.has_js_ref) { @@ -857,6 +901,7 @@ pub const WTFTimer = struct { run_loop_timer: *RunLoopTimer, event_loop_timer: EventLoopTimer, repeat: bool, + lock: bun.Lock = .{}, pub usingnamespace bun.New(@This()); @@ -864,7 +909,10 @@ pub const WTFTimer = struct { const this = WTFTimer.new(.{ .vm = js_vm, .event_loop_timer = .{ - .next = timespec.msFromNow(std.math.maxInt(i64)), + .next = .{ + .sec = std.math.maxInt(i64), + .nsec = 0, + }, .tag = .WTFTimer, .state = .CANCELLED, }, @@ -875,8 +923,17 @@ pub const WTFTimer = struct { return this; } + var auto_incrementing_integer_for_dedupe = std.atomic.Value(i64).init(0); + pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { - this.cancel(); + if (seconds == 0) { + const ASAP = bun.timespec{ + .nsec = 1024 + auto_incrementing_integer_for_dedupe.fetchAdd(1, .monotonic), + .sec = 1024, + }; + this.vm.timer.update(&this.event_loop_timer, &ASAP); + return; + } const modf = std.math.modf(seconds); var interval = bun.timespec.now(); @@ -887,12 +944,13 @@ pub const WTFTimer = struct { interval.nsec -= std.time.ns_per_s; } - this.event_loop_timer.next = interval; - this.vm.timer.insert(&this.event_loop_timer); + this.vm.timer.update(&this.event_loop_timer, &interval); this.repeat = repeat; } pub fn cancel(this: *WTFTimer) void { + this.lock.lock(); + defer this.lock.unlock(); if (this.event_loop_timer.state == .ACTIVE) { this.vm.timer.remove(&this.event_loop_timer); } @@ -934,7 +992,9 @@ pub const WTFTimer = struct { this.cancel(); } - export fn WTFTimer__secondsUntilTimer(this: *const WTFTimer) f64 { + export fn WTFTimer__secondsUntilTimer(this: *WTFTimer) f64 { + this.lock.lock(); + defer this.lock.unlock(); if (this.event_loop_timer.state == .ACTIVE) { const until = this.event_loop_timer.next.duration(&bun.timespec.now()); const sec: f64, const nsec: f64 = .{ @floatFromInt(until.sec), @floatFromInt(until.nsec) }; diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 9dfceca67adf60..fb7ac108cf30bb 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -2270,21 +2270,29 @@ pub const Subprocess = struct { jsc_vm.onSubprocessSpawn(subprocess.process); } - while (subprocess.hasPendingActivityNonThreadsafe()) { - if (subprocess.stdin == .buffer) { - subprocess.stdin.buffer.watch(); - } + // We cannot release heap access while JS is running + { + const old_vm = jsc_vm.uwsLoop().internal_loop_data.jsc_vm; + jsc_vm.uwsLoop().internal_loop_data.jsc_vm = null; + defer { + jsc_vm.uwsLoop().internal_loop_data.jsc_vm = old_vm; + } + while (subprocess.hasPendingActivityNonThreadsafe()) { + if (subprocess.stdin == .buffer) { + subprocess.stdin.buffer.watch(); + } - if (subprocess.stderr == .pipe) { - subprocess.stderr.pipe.watch(); - } + if (subprocess.stderr == .pipe) { + subprocess.stderr.pipe.watch(); + } - if (subprocess.stdout == .pipe) { - subprocess.stdout.pipe.watch(); - } + if (subprocess.stdout == .pipe) { + subprocess.stdout.pipe.watch(); + } - jsc_vm.tick(); - jsc_vm.eventLoop().autoTick(); + jsc_vm.tick(); + jsc_vm.eventLoop().autoTick(); + } } subprocess.updateHasPendingActivity(); diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index e1b0e4b6b3aae2..eefae43f3e70b7 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -783,7 +783,7 @@ pub const VirtualMachine = struct { entry_point: ServerEntryPoint = undefined, origin: URL = URL{}, node_fs: ?*Node.NodeFS = null, - timer: Bun.Timer.All = .{}, + timer: Bun.Timer.All, event_loop_handle: ?*PlatformEventLoop = null, pending_unref_counter: i32 = 0, preload: []const string = &[_][]const u8{}, @@ -1885,6 +1885,7 @@ pub const VirtualMachine = struct { .console = console, .log = log, .origin = bundler.options.origin, + .timer = JSC.BunTimer.All.init(), .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), @@ -1992,6 +1993,7 @@ pub const VirtualMachine = struct { .console = console, .log = log, .origin = bundler.options.origin, + .timer = JSC.BunTimer.All.init(), .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), @@ -2156,6 +2158,7 @@ pub const VirtualMachine = struct { .bundler = bundler, .console = console, .log = log, + .timer = JSC.BunTimer.All.init(), .origin = bundler.options.origin, .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, @@ -2249,6 +2252,7 @@ pub const VirtualMachine = struct { .console = console, .log = log, .origin = bundler.options.origin, + .timer = JSC.BunTimer.All.init(), .saved_source_map_table = SavedSourceMap.HashTable.init(bun.default_allocator), .source_mappings = undefined, .macros = MacroMap.init(allocator), diff --git a/src/bun.js/node/node_fs_stat_watcher.zig b/src/bun.js/node/node_fs_stat_watcher.zig index 55418ffca86b14..3d4b581aec939e 100644 --- a/src/bun.js/node/node_fs_stat_watcher.zig +++ b/src/bun.js/node/node_fs_stat_watcher.zig @@ -86,19 +86,17 @@ pub const StatWatcherScheduler = struct { /// Set the timer (this function is not thread safe, should be called only from the main thread) fn setTimer(this: *StatWatcherScheduler, interval: i32) void { - // if the timer is active we need to remove it - if (this.event_loop_timer.state == .ACTIVE) { - this.vm.timer.remove(&this.event_loop_timer); - } - // if the interval is 0 means that we stop the timer if (interval == 0) { + // if the timer is active we need to remove it + if (this.event_loop_timer.state == .ACTIVE) { + this.vm.timer.remove(&this.event_loop_timer); + } return; } // reschedule the timer - this.event_loop_timer.next = bun.timespec.msFromNow(interval); - this.vm.timer.insert(&this.event_loop_timer); + this.vm.timer.update(&this.event_loop_timer, &bun.timespec.msFromNow(interval)); } /// Schedule a task to set the timer in the main thread diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 4be73143aa7ef1..e517357710adae 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -132,13 +132,9 @@ pub const TestRunner = struct { pub fn scheduleTimeout(this: *TestRunner, milliseconds: u32) void { const then = bun.timespec.msFromNow(@intCast(milliseconds)); const vm = JSC.VirtualMachine.get(); - if (this.event_loop_timer.state == .ACTIVE) { - vm.timer.remove(&this.event_loop_timer); - } - this.event_loop_timer.next = then; this.event_loop_timer.tag = .TestRunner; - vm.timer.insert(&this.event_loop_timer); + vm.timer.update(&this.event_loop_timer, &then); } pub fn enqueue(this: *TestRunner, task: *TestRunnerTask) void { From 3340ac684e03c54f1d4c189a1b749c3d6da91226 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 12 Dec 2024 04:52:05 -0800 Subject: [PATCH 18/68] oopsie --- src/bun.js/api/Timer.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 26657e5ef2c08e..7dc2a6ec7f03ce 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -204,7 +204,7 @@ pub const All = struct { now.* = timespec.now(); has_set_now.* = true; } - if (!timer.next.greater(now)) { + if (timer.next.greater(now)) { return null; } From e3113589d3b6749d9584bc8e429e13b19110f4bb Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 19 Dec 2024 19:04:33 -0800 Subject: [PATCH 19/68] Add binding for performOpportunisticallyScheduledTasks --- src/bun.js/bindings/bindings.cpp | 5 ++ src/bun.js/bindings/bindings.zig | 4 ++ src/bun.js/bindings/headers.zig | 1 + src/bun.js/bindings/wtf_timer_inspection.cpp | 50 ++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 src/bun.js/bindings/wtf_timer_inspection.cpp diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 7df8634f0296fd..a63568af1d29d4 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -6016,6 +6016,11 @@ CPP_DECL void JSC__VM__setControlFlowProfiler(JSC__VM* vm, bool isEnabled) } } +CPP_DECL void JSC__VM__performOpportunisticallyScheduledTasks(JSC__VM* vm, double until) +{ + vm->performOpportunisticallyScheduledTasks(MonotonicTime::now() + Seconds(until), {}); +} + extern "C" EncodedJSValue JSC__createError(JSC::JSGlobalObject* globalObject, const BunString* str) { return JSValue::encode(JSC::createError(globalObject, str->toWTFString(BunString::ZeroCopy))); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 39ccf2c7cae08e..c61b98957ae4fa 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -6497,6 +6497,10 @@ pub const VM = extern struct { return cppFn("blockBytesAllocated", .{vm}); } + pub fn performOpportunisticallyScheduledTasks(vm: *VM, until: f64) void { + cppFn("performOpportunisticallyScheduledTasks", .{ vm, until }); + } + pub const Extern = [_][]const u8{ "setControlFlowProfiler", "collectAsync", diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index 5836a77370f160..7bbd080bb72f5b 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -327,6 +327,7 @@ pub extern fn JSC__VM__setExecutionTimeLimit(arg0: *bindings.VM, arg1: f64) void pub extern fn JSC__VM__shrinkFootprint(arg0: *bindings.VM) void; pub extern fn JSC__VM__throwError(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; pub extern fn JSC__VM__whenIdle(arg0: *bindings.VM, ArgFn1: ?*const fn (...) callconv(.C) void) void; +pub extern fn JSC__VM__performOpportunisticallyScheduledTasks(arg0: *bindings.VM, arg1: f64) void; pub extern fn JSC__ThrowScope__clearException(arg0: [*c]bindings.ThrowScope) void; pub extern fn JSC__ThrowScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__ThrowScope; pub extern fn JSC__ThrowScope__exception(arg0: [*c]bindings.ThrowScope) [*c]bindings.Exception; diff --git a/src/bun.js/bindings/wtf_timer_inspection.cpp b/src/bun.js/bindings/wtf_timer_inspection.cpp new file mode 100644 index 00000000000000..a08d38bf3c36ae --- /dev/null +++ b/src/bun.js/bindings/wtf_timer_inspection.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +static uint64_t last_asap_update = 0; +static ssize_t generation = -1; + +struct bun_timespec { + ssize_t sec; + ssize_t nsec; +}; + +extern uint64_t wtf_timer_main_tid; + +extern "C" { +void WTFTimer__inspect_update(const void* timer, double seconds, bool repeat, const bun_timespec* ts) +{ + uint64_t tid; + pthread_threadid_np(nullptr, &tid); + if (wtf_timer_main_tid != tid && ts->sec == 1024) { + fprintf(stderr, "update %zd from off main, tid %" PRIu64 "\n", ts->nsec, tid); + } + + uint64_t now = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW); + if (ts->sec == 1024) { + if (generation != -1) { + fprintf(stderr, "%zd never fired after %" PRIu64 " us\n", generation, (now - last_asap_update) / 1'000); + } + generation = ts->nsec; + } + + if (seconds == 0.0 && !repeat) { + last_asap_update = now; + } +} + +void WTFTimer__inspect_fire(const bun_timespec* ts) +{ + if (ts->sec == 1024) { + // asap + generation = -1; + uint64_t now = clock_gettime_nsec_np(_CLOCK_MONOTONIC_RAW); + uint64_t diff = now - last_asap_update; + fprintf(stderr, "asap timer %zd fired after %" PRIu64 " us\n", ts->nsec, diff / 1'000); + } +} +} From 339d2d33823183c665a6fae76859be20424acd83 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 19 Dec 2024 19:05:09 -0800 Subject: [PATCH 20/68] Clean up WTFTimer.update --- src/bun.js/api/Timer.zig | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 7dc2a6ec7f03ce..b72b9852d47908 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -926,23 +926,22 @@ pub const WTFTimer = struct { var auto_incrementing_integer_for_dedupe = std.atomic.Value(i64).init(0); pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { - if (seconds == 0) { - const ASAP = bun.timespec{ + const interval: bun.timespec = if (seconds == 0.0) blk: { + break :blk .{ .nsec = 1024 + auto_incrementing_integer_for_dedupe.fetchAdd(1, .monotonic), .sec = 1024, }; - this.vm.timer.update(&this.event_loop_timer, &ASAP); - return; - } - - const modf = std.math.modf(seconds); - var interval = bun.timespec.now(); - interval.sec += @intFromFloat(modf.ipart); - interval.nsec += @intFromFloat(modf.fpart * std.time.ns_per_s); - if (interval.nsec >= std.time.ns_per_s) { - interval.sec += 1; - interval.nsec -= std.time.ns_per_s; - } + } else blk: { + const modf = std.math.modf(seconds); + var interval = bun.timespec.now(); + interval.sec += @intFromFloat(modf.ipart); + interval.nsec += @intFromFloat(modf.fpart * std.time.ns_per_s); + if (interval.nsec >= std.time.ns_per_s) { + interval.sec += 1; + interval.nsec -= std.time.ns_per_s; + } + break :blk interval; + }; this.vm.timer.update(&this.event_loop_timer, &interval); this.repeat = repeat; From 204edcbc2a8dacf3dc17710357eac60c0ef2fdd1 Mon Sep 17 00:00:00 2001 From: 190n <190n@users.noreply.github.com> Date: Fri, 20 Dec 2024 03:12:04 +0000 Subject: [PATCH 21/68] `bun run clang-tidy` --- src/bun.js/bindings/wtf_timer_inspection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/bindings/wtf_timer_inspection.cpp b/src/bun.js/bindings/wtf_timer_inspection.cpp index a08d38bf3c36ae..1fada963d3e01d 100644 --- a/src/bun.js/bindings/wtf_timer_inspection.cpp +++ b/src/bun.js/bindings/wtf_timer_inspection.cpp @@ -19,7 +19,7 @@ extern "C" { void WTFTimer__inspect_update(const void* timer, double seconds, bool repeat, const bun_timespec* ts) { uint64_t tid; - pthread_threadid_np(nullptr, &tid); + pthread_tryjoin_np(nullptr, &tid); if (wtf_timer_main_tid != tid && ts->sec == 1024) { fprintf(stderr, "update %zd from off main, tid %" PRIu64 "\n", ts->nsec, tid); } From eea51d9842b8651b27152f08da547ecce78ee2e3 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 22 Dec 2024 10:22:21 -0800 Subject: [PATCH 22/68] Update wtf_timer_inspection.cpp --- src/bun.js/bindings/wtf_timer_inspection.cpp | 51 +------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/src/bun.js/bindings/wtf_timer_inspection.cpp b/src/bun.js/bindings/wtf_timer_inspection.cpp index 1fada963d3e01d..8337712ea57f00 100644 --- a/src/bun.js/bindings/wtf_timer_inspection.cpp +++ b/src/bun.js/bindings/wtf_timer_inspection.cpp @@ -1,50 +1 @@ -#include -#include -#include -#include -#include -#include - -static uint64_t last_asap_update = 0; -static ssize_t generation = -1; - -struct bun_timespec { - ssize_t sec; - ssize_t nsec; -}; - -extern uint64_t wtf_timer_main_tid; - -extern "C" { -void WTFTimer__inspect_update(const void* timer, double seconds, bool repeat, const bun_timespec* ts) -{ - uint64_t tid; - pthread_tryjoin_np(nullptr, &tid); - if (wtf_timer_main_tid != tid && ts->sec == 1024) { - fprintf(stderr, "update %zd from off main, tid %" PRIu64 "\n", ts->nsec, tid); - } - - uint64_t now = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW); - if (ts->sec == 1024) { - if (generation != -1) { - fprintf(stderr, "%zd never fired after %" PRIu64 " us\n", generation, (now - last_asap_update) / 1'000); - } - generation = ts->nsec; - } - - if (seconds == 0.0 && !repeat) { - last_asap_update = now; - } -} - -void WTFTimer__inspect_fire(const bun_timespec* ts) -{ - if (ts->sec == 1024) { - // asap - generation = -1; - uint64_t now = clock_gettime_nsec_np(_CLOCK_MONOTONIC_RAW); - uint64_t diff = now - last_asap_update; - fprintf(stderr, "asap timer %zd fired after %" PRIu64 " us\n", ts->nsec, diff / 1'000); - } -} -} +// From 7a1cc620f4796ba6ac984d38391a14d8a6bd71c4 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 22 Dec 2024 22:36:15 -0800 Subject: [PATCH 23/68] Update SetupWebKit.cmake --- cmake/tools/SetupWebKit.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index b876c54da52e4d..b31c17cec88e98 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION 3845bf370ff4e9a5c0b96036255142c7904be963) + set(WEBKIT_VERSION 2941ad15d33ce56be1698e68db4e76f0bc1bd493) endif() if(WEBKIT_LOCAL) From b10ec9790a6e83ab52610643e3260430330871b0 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 22 Dec 2024 23:12:26 -0800 Subject: [PATCH 24/68] imminent timer --- src/bun.js/api/Timer.zig | 73 +++++++++++++++++++++++++-------------- src/bun.js/event_loop.zig | 9 +++-- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index b72b9852d47908..56b9573be38cd5 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -160,15 +160,28 @@ pub const All = struct { return VirtualMachine.get().timer.last_id; } - pub fn getTimeout(this: *const All, spec: *timespec) bool { + pub fn getTimeout(this: *All, spec: *timespec, vm: *VirtualMachine) bool { if (this.active_timer_count == 0) { return false; } - if (this.timers.peek()) |min| { - const now = timespec.now(); + var now: timespec = undefined; + var has_set_now: bool = false; + while (this.timers.peek()) |min| { + if (!has_set_now) { + now = timespec.now(); + has_set_now = true; + } + switch (now.order(&min.next)) { .gt, .eq => { + // Side-effect: potentially call the StopIfNecessary timer. + if (min.tag == .WTFTimer) { + _ = this.timers.deleteMin(); + _ = min.fire(&now, vm); + continue; + } + spec.* = .{ .nsec = 0, .sec = 0 }; return true; }, @@ -177,6 +190,8 @@ pub const All = struct { return true; }, } + + unreachable; } return false; @@ -900,6 +915,7 @@ pub const WTFTimer = struct { vm: *VirtualMachine, run_loop_timer: *RunLoopTimer, event_loop_timer: EventLoopTimer, + event_loop: *JSC.EventLoop, repeat: bool, lock: bun.Lock = .{}, @@ -908,6 +924,7 @@ pub const WTFTimer = struct { pub fn init(run_loop_timer: *RunLoopTimer, js_vm: *VirtualMachine) *WTFTimer { const this = WTFTimer.new(.{ .vm = js_vm, + .event_loop = js_vm.eventLoop(), .event_loop_timer = .{ .next = .{ .sec = std.math.maxInt(i64), @@ -923,25 +940,32 @@ pub const WTFTimer = struct { return this; } - var auto_incrementing_integer_for_dedupe = std.atomic.Value(i64).init(0); + pub fn run(this: *WTFTimer, vm: *VirtualMachine) void { + if (this.event_loop_timer.state == .ACTIVE) { + vm.timer.remove(&this.event_loop_timer); + } + this.runWithoutRemoving(); + } + + inline fn runWithoutRemoving(this: *const WTFTimer) void { + WTFTimer__fire(this.run_loop_timer); + } pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { - const interval: bun.timespec = if (seconds == 0.0) blk: { - break :blk .{ - .nsec = 1024 + auto_incrementing_integer_for_dedupe.fetchAdd(1, .monotonic), - .sec = 1024, - }; - } else blk: { - const modf = std.math.modf(seconds); - var interval = bun.timespec.now(); - interval.sec += @intFromFloat(modf.ipart); - interval.nsec += @intFromFloat(modf.fpart * std.time.ns_per_s); - if (interval.nsec >= std.time.ns_per_s) { - interval.sec += 1; - interval.nsec -= std.time.ns_per_s; - } - break :blk interval; - }; + if (seconds == 0.0) { + this.event_loop.imminent_gc_timer.store(this, .monotonic); + return; + } + + this.event_loop.imminent_gc_timer.store(null, .monotonic); + const modf = std.math.modf(seconds); + var interval = bun.timespec.now(); + interval.sec += @intFromFloat(modf.ipart); + interval.nsec += @intFromFloat(modf.fpart * std.time.ns_per_s); + if (interval.nsec >= std.time.ns_per_s) { + interval.sec += 1; + interval.nsec -= std.time.ns_per_s; + } this.vm.timer.update(&this.event_loop_timer, &interval); this.repeat = repeat; @@ -955,11 +979,10 @@ pub const WTFTimer = struct { } } - pub fn fire(this: *WTFTimer, now: *const bun.timespec, js_vm: *VirtualMachine) EventLoopTimer.Arm { - _ = now; - _ = js_vm; + pub fn fire(this: *WTFTimer, _: *const bun.timespec, _: *VirtualMachine) EventLoopTimer.Arm { this.event_loop_timer.state = .FIRED; - WTFTimer__fire(this.run_loop_timer); + this.event_loop.imminent_gc_timer.store(null, .monotonic); + this.runWithoutRemoving(); return if (this.repeat) .{ .rearm = this.event_loop_timer.next } else @@ -984,7 +1007,7 @@ pub const WTFTimer = struct { } export fn WTFTimer__isActive(this: *const WTFTimer) bool { - return this.event_loop_timer.state == .ACTIVE; + return this.event_loop_timer.state == .ACTIVE or (this.event_loop.imminent_gc_timer.load(.monotonic) orelse return false) == this; } export fn WTFTimer__cancel(this: *WTFTimer) void { diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index efe8e7126e5f0f..a615e7ddf3c6f3 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -816,6 +816,7 @@ pub const EventLoop = struct { debug: Debug = .{}, entered_event_loop_count: isize = 0, concurrent_ref: std.atomic.Value(i32) = std.atomic.Value(i32).init(0), + imminent_gc_timer: std.atomic.Value(?*JSC.BunTimer.WTFTimer) = .{ .raw = null }, signal_handler: if (Environment.isPosix) ?*PosixSignalHandle else void = if (Environment.isPosix) null else {}, @@ -1368,6 +1369,10 @@ pub const EventLoop = struct { } } + if (this.imminent_gc_timer.swap(null, .monotonic)) |timer| { + timer.run(this.virtual_machine); + } + var concurrent = this.concurrent_tasks.popBatch(); const count = concurrent.count; if (count == 0) @@ -1442,7 +1447,7 @@ pub const EventLoop = struct { var event_loop_sleep_timer = if (comptime Environment.isDebug) std.time.Timer.start() catch unreachable else {}; // for the printer, this is defined: var timespec: bun.timespec = if (Environment.isDebug) .{ .sec = 0, .nsec = 0 } else undefined; - loop.tickWithTimeout(if (ctx.timer.getTimeout(×pec)) ×pec else null); + loop.tickWithTimeout(if (ctx.timer.getTimeout(×pec, ctx)) ×pec else null); if (comptime Environment.isDebug) { log("tick {}, timeout: {}", .{ bun.fmt.fmtDuration(event_loop_sleep_timer.read()), bun.fmt.fmtDuration(timespec.ns()) }); @@ -1527,7 +1532,7 @@ pub const EventLoop = struct { this.processGCTimer(); var timespec: bun.timespec = undefined; - loop.tickWithTimeout(if (ctx.timer.getTimeout(×pec)) ×pec else null); + loop.tickWithTimeout(if (ctx.timer.getTimeout(×pec, ctx)) ×pec else null); } else { loop.tickWithoutIdle(); } From bf844f62b6bd27735df8317d3e38332bd5c197be Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 22 Dec 2024 23:38:36 -0800 Subject: [PATCH 25/68] micro-optimize --- src/bun.js/api/Timer.zig | 14 ++++++++------ src/bun.js/event_loop.zig | 6 ++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 56b9573be38cd5..829e57022eec98 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -915,7 +915,7 @@ pub const WTFTimer = struct { vm: *VirtualMachine, run_loop_timer: *RunLoopTimer, event_loop_timer: EventLoopTimer, - event_loop: *JSC.EventLoop, + imminent: *std.atomic.Value(?*WTFTimer), repeat: bool, lock: bun.Lock = .{}, @@ -924,7 +924,7 @@ pub const WTFTimer = struct { pub fn init(run_loop_timer: *RunLoopTimer, js_vm: *VirtualMachine) *WTFTimer { const this = WTFTimer.new(.{ .vm = js_vm, - .event_loop = js_vm.eventLoop(), + .imminent = &js_vm.eventLoop().imminent_gc_timer, .event_loop_timer = .{ .next = .{ .sec = std.math.maxInt(i64), @@ -952,12 +952,13 @@ pub const WTFTimer = struct { } pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { + // There's only one of these. + this.imminent.store(if (seconds == 0) null else this, .monotonic); + if (seconds == 0.0) { - this.event_loop.imminent_gc_timer.store(this, .monotonic); return; } - this.event_loop.imminent_gc_timer.store(null, .monotonic); const modf = std.math.modf(seconds); var interval = bun.timespec.now(); interval.sec += @intFromFloat(modf.ipart); @@ -974,6 +975,7 @@ pub const WTFTimer = struct { pub fn cancel(this: *WTFTimer) void { this.lock.lock(); defer this.lock.unlock(); + this.imminent.store(null, .monotonic); if (this.event_loop_timer.state == .ACTIVE) { this.vm.timer.remove(&this.event_loop_timer); } @@ -981,7 +983,7 @@ pub const WTFTimer = struct { pub fn fire(this: *WTFTimer, _: *const bun.timespec, _: *VirtualMachine) EventLoopTimer.Arm { this.event_loop_timer.state = .FIRED; - this.event_loop.imminent_gc_timer.store(null, .monotonic); + this.imminent.store(null, .monotonic); this.runWithoutRemoving(); return if (this.repeat) .{ .rearm = this.event_loop_timer.next } @@ -1007,7 +1009,7 @@ pub const WTFTimer = struct { } export fn WTFTimer__isActive(this: *const WTFTimer) bool { - return this.event_loop_timer.state == .ACTIVE or (this.event_loop.imminent_gc_timer.load(.monotonic) orelse return false) == this; + return this.event_loop_timer.state == .ACTIVE or (this.imminent.load(.monotonic) orelse return false) == this; } export fn WTFTimer__cancel(this: *WTFTimer) void { diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index a615e7ddf3c6f3..2bf67f459553aa 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -1369,8 +1369,10 @@ pub const EventLoop = struct { } } - if (this.imminent_gc_timer.swap(null, .monotonic)) |timer| { - timer.run(this.virtual_machine); + if (this.entered_event_loop_count < 2) { + if (this.imminent_gc_timer.swap(null, .monotonic)) |timer| { + timer.run(this.virtual_machine); + } } var concurrent = this.concurrent_tasks.popBatch(); From b10929d9015dd62a4be8e2dc8115ae163ded13b6 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 00:25:56 -0800 Subject: [PATCH 26/68] Disable WTFTimer in bytecode cache --- src/bun.js/api/Timer.zig | 6 +++++- src/bun.js/javascript.zig | 2 ++ src/bundler/bundle_v2.zig | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 829e57022eec98..8a9313889e4f0c 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -996,7 +996,11 @@ pub const WTFTimer = struct { this.destroy(); } - export fn WTFTimer__create(run_loop_timer: *RunLoopTimer) *WTFTimer { + export fn WTFTimer__create(run_loop_timer: *RunLoopTimer) ?*anyopaque { + if (VirtualMachine.is_bundler_thread_for_bytecode_cache) { + return null; + } + return init(run_loop_timer, VirtualMachine.get()); } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index d885ce39d14573..c1cf383753765b 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -911,6 +911,8 @@ pub const VirtualMachine = struct { return BodyValueRef.init(body, &this.body_value_hive_allocator); } + pub threadlocal var is_bundler_thread_for_bytecode_cache: bool = false; + pub fn uwsLoop(this: *const VirtualMachine) *uws.Loop { if (comptime Environment.isPosix) { if (Environment.allow_assert) { diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 8f47276d6edbac..4c55c8f58a6bbb 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -12701,6 +12701,7 @@ pub const LinkerContext = struct { .js; if (loader.isJavaScriptLike()) { + JSC.VirtualMachine.is_bundler_thread_for_bytecode_cache = true; JSC.initialize(false); var fdpath: bun.PathBuffer = undefined; var source_provider_url = try bun.String.createFormat("{s}" ++ bun.bytecode_extension, .{chunk.final_rel_path}); From 19707e23c78dfc5a1f0eac1d8a666440795ed04d Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 00:26:23 -0800 Subject: [PATCH 27/68] Don't use SIGUSR1 on linux --- test/js/node/test/parallel/test-signal-handler.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/js/node/test/parallel/test-signal-handler.js b/test/js/node/test/parallel/test-signal-handler.js index 05ec4e7f73faf5..010f772580646e 100644 --- a/test/js/node/test/parallel/test-signal-handler.js +++ b/test/js/node/test/parallel/test-signal-handler.js @@ -30,9 +30,13 @@ if (!common.isMainThread) console.log(`process.pid: ${process.pid}`); -process.on('SIGUSR1', common.mustCall()); +// On Bun in Linux, SIGUSR1 is reserved for the GC. +// So we need to use a different signal. +const SIGNAL = process.platform === 'linux' ? 'SIGUSR2' : 'SIGUSR1'; -process.on('SIGUSR1', common.mustCall(function() { + +process.on(SIGNAL, common.mustCall()); +process.on(SIGNAL, common.mustCall(function() { setTimeout(function() { console.log('End.'); process.exit(0); @@ -44,7 +48,7 @@ setInterval(function() { console.log(`running process...${++i}`); if (i === 5) { - process.kill(process.pid, 'SIGUSR1'); + process.kill(process.pid, SIGNAL); } }, 1); From 0a3d43f522357d2f7a38f1ceb25edceaaafdbe1d Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 00:26:36 -0800 Subject: [PATCH 28/68] Fix commander test --- test/regression/issue/14982/14982.test.ts | 1 + .../issue/14982/{test-test.ts => commander-hang.fixture-test.ts} | 0 2 files changed, 1 insertion(+) rename test/regression/issue/14982/{test-test.ts => commander-hang.fixture-test.ts} (100%) diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts index 0141479a0e3e25..84f5bd21146e9d 100644 --- a/test/regression/issue/14982/14982.test.ts +++ b/test/regression/issue/14982/14982.test.ts @@ -8,6 +8,7 @@ describe("issue 14982", () => { stdin: "inherit", stdout: "pipe", stderr: "inherit", + cwd: __dirname, env: bunEnv, }); await process.exited; diff --git a/test/regression/issue/14982/test-test.ts b/test/regression/issue/14982/commander-hang.fixture-test.ts similarity index 100% rename from test/regression/issue/14982/test-test.ts rename to test/regression/issue/14982/commander-hang.fixture-test.ts From 91f95210b2c985d926f5629122f534a1e3dba2a1 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 23 Dec 2024 00:29:21 -0800 Subject: [PATCH 29/68] avoid SIGUSR1 on linux --- test/js/node/http/node-http-ref-fixture.js | 5 +++-- .../js/node/process/process-signal-handler.fixture.js | 11 ++++++----- test/js/node/test/parallel/test-signal-handler.js | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/test/js/node/http/node-http-ref-fixture.js b/test/js/node/http/node-http-ref-fixture.js index 78ef0984296023..b5fd7d55d28ffc 100644 --- a/test/js/node/http/node-http-ref-fixture.js +++ b/test/js/node/http/node-http-ref-fixture.js @@ -1,8 +1,9 @@ import { createServer } from "http"; +const SIGNAL = process.platform === "linux" ? "SIGUSR2" : "SIGUSR1"; var server = createServer((req, res) => { res.end(); }).listen(0, async (err, hostname, port) => { - process.on("SIGUSR1", async () => { + process.on(SIGNAL, async () => { server.unref(); // check that the server is still running @@ -15,5 +16,5 @@ var server = createServer((req, res) => { if (resp.status !== 200) { process.exit(42); } - process.kill(process.pid, "SIGUSR1"); + process.kill(process.pid, SIGNAL); }); diff --git a/test/js/node/process/process-signal-handler.fixture.js b/test/js/node/process/process-signal-handler.fixture.js index 77d9d09f4c59c5..38c3d01a601787 100644 --- a/test/js/node/process/process-signal-handler.fixture.js +++ b/test/js/node/process/process-signal-handler.fixture.js @@ -54,15 +54,16 @@ const SIGUSR2 = os.constants.signals.SIGUSR2; switch (process.argv.at(-1)) { case "SIGUSR1": { - process.on("SIGUSR1", function () { - checkSignal("SIGUSR1", arguments); + const SIGNAL = os.constants.signals[process.platform === "linux" ? "SIGUSR2" : "SIGUSR1"]; + process.on(SIGNAL, function () { + checkSignal(SIGNAL, arguments); done(); }); - process.on("SIGUSR1", function () { - checkSignal("SIGUSR1", arguments); + process.on(SIGNAL, function () { + checkSignal(SIGNAL, arguments); done(); }); - raise(SIGUSR1); + raise(SIGNAL); break; } case "SIGUSR2": { diff --git a/test/js/node/test/parallel/test-signal-handler.js b/test/js/node/test/parallel/test-signal-handler.js index 010f772580646e..68c97586377214 100644 --- a/test/js/node/test/parallel/test-signal-handler.js +++ b/test/js/node/test/parallel/test-signal-handler.js @@ -34,7 +34,6 @@ console.log(`process.pid: ${process.pid}`); // So we need to use a different signal. const SIGNAL = process.platform === 'linux' ? 'SIGUSR2' : 'SIGUSR1'; - process.on(SIGNAL, common.mustCall()); process.on(SIGNAL, common.mustCall(function() { setTimeout(function() { From b68ac34ab1d7b397cb6c7569704bb47a57e38138 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 3 Jan 2025 18:01:25 -0800 Subject: [PATCH 30/68] Fix imminent timer --- src/bun.js/api/Timer.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 33063adcc4b83f..7501f4080c5c84 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -964,7 +964,7 @@ pub const WTFTimer = struct { pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { // There's only one of these. - this.imminent.store(if (seconds == 0) null else this, .monotonic); + this.imminent.store(if (seconds == 0) this else null, .monotonic); if (seconds == 0.0) { return; From e35e05fd9760415fa823b9d8b1e96a19e8319f61 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 14:43:29 -0800 Subject: [PATCH 31/68] Remove TODO --- src/bun.js/bindings/BunJSCEventLoop.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bun.js/bindings/BunJSCEventLoop.cpp b/src/bun.js/bindings/BunJSCEventLoop.cpp index 05a7096374c2ef..7a3cf95b2a01ee 100644 --- a/src/bun.js/bindings/BunJSCEventLoop.cpp +++ b/src/bun.js/bindings/BunJSCEventLoop.cpp @@ -5,9 +5,6 @@ extern "C" int Bun__JSC_onBeforeWait(JSC::VM* vm) { - // TODO: use JSC timers, run the incremental sweeper. - // That will fix this. - // In the meantime, we're disabling this due to https://github.com/oven-sh/bun/issues/14982 if (vm->heap.hasAccess()) { vm->heap.releaseAccess(); return 1; From 7cbf97ac4e4892da96b6685f548f54775d4049b2 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 15:21:47 -0800 Subject: [PATCH 32/68] Specify USE_BUN_EVENT_LOOP when building local WebKit --- Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f1a8be26462ff0..4e7bf5f907e5c2 100644 --- a/Makefile +++ b/Makefile @@ -1261,6 +1261,7 @@ jsc-build-mac-compile: -DBUN_FAST_TLS=ON \ -DENABLE_FTL_JIT=ON \ -DUSE_BUN_JSC_ADDITIONS=ON \ + -DUSE_BUN_EVENT_LOOP=ON \ -G Ninja \ $(CMAKE_FLAGS_WITHOUT_RELEASE) \ -DPTHREAD_JIT_PERMISSIONS_API=1 \ @@ -1284,6 +1285,7 @@ jsc-build-mac-compile-lto: -DUSE_THIN_ARCHIVES=OFF \ -DBUN_FAST_TLS=ON \ -DUSE_BUN_JSC_ADDITIONS=ON \ + -DUSE_BUN_EVENT_LOOP=ON \ -DCMAKE_C_FLAGS="-flto=full" \ -DCMAKE_CXX_FLAGS="-flto=full" \ -DENABLE_FTL_JIT=ON \ @@ -1310,6 +1312,7 @@ jsc-build-mac-compile-debug: -DENABLE_MALLOC_HEAP_BREAKDOWN=ON \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DUSE_BUN_JSC_ADDITIONS=ON \ + -DUSE_BUN_EVENT_LOOP=ON \ -DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \ -DALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS=ON \ -G Ninja \ @@ -1334,6 +1337,7 @@ jsc-build-linux-compile-config: -DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \ -DUSE_THIN_ARCHIVES=OFF \ -DUSE_BUN_JSC_ADDITIONS=ON \ + -DUSE_BUN_EVENT_LOOP=ON \ -DENABLE_FTL_JIT=ON \ -DENABLE_REMOTE_INSPECTOR=ON \ -DJSEXPORT_PRIVATE=WTF_EXPORT_DECLARATION \ @@ -1357,6 +1361,7 @@ jsc-build-linux-compile-config-debug: -DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \ -DUSE_THIN_ARCHIVES=OFF \ -DUSE_BUN_JSC_ADDITIONS=ON \ + -DUSE_BUN_EVENT_LOOP=ON \ -DENABLE_FTL_JIT=ON \ -DENABLE_REMOTE_INSPECTOR=ON \ -DJSEXPORT_PRIVATE=WTF_EXPORT_DECLARATION \ @@ -1375,14 +1380,14 @@ jsc-build-linux-compile-config-debug: jsc-build-linux-compile-build: mkdir -p $(WEBKIT_RELEASE_DIR) && \ cd $(WEBKIT_RELEASE_DIR) && \ - CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON" \ + CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON -DUSE_BUN_EVENT_LOOP=ON" \ cmake --build $(WEBKIT_RELEASE_DIR) --config relwithdebuginfo --target jsc .PHONY: jsc-build-linux-compile-build-debug jsc-build-linux-compile-build-debug: mkdir -p $(WEBKIT_DEBUG_DIR) && \ cd $(WEBKIT_DEBUG_DIR) && \ - CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON" \ + CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON -DUSE_BUN_EVENT_LOOP=ON" \ cmake --build $(WEBKIT_DEBUG_DIR) --config Debug --target jsc From 0378bedba1341aef7cab95a4727c5cf1a6ba60e6 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 15:37:09 -0800 Subject: [PATCH 33/68] Possibly remove unnecessary headers --- src/bun.js/bindings/EventLoopTaskNoContext.h | 4 +++- src/bun.js/bindings/webcrypto/PhonyWorkQueue.h | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bun.js/bindings/EventLoopTaskNoContext.h b/src/bun.js/bindings/EventLoopTaskNoContext.h index ee4ef6eab6db82..e3865620d252ce 100644 --- a/src/bun.js/bindings/EventLoopTaskNoContext.h +++ b/src/bun.js/bindings/EventLoopTaskNoContext.h @@ -1,5 +1,7 @@ #pragma once -#include "root.h" + +#include +#include namespace Bun { diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h index 8232b0adf50f64..d3dbabaf21e58e 100644 --- a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h @@ -1,9 +1,8 @@ #pragma once -#include "root.h" - #include #include +#include namespace Bun { From 39c70832a0469e3906abfe25296cf20842be4545 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 15:37:15 -0800 Subject: [PATCH 34/68] Use clang 18 in Makefile --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 4e7bf5f907e5c2..70189a8dcd2a3b 100644 --- a/Makefile +++ b/Makefile @@ -91,9 +91,9 @@ ZIG ?= $(shell which zig 2>/dev/null || echo -e "error: Missing zig. Please make # This is easier to happen than you'd expect. # Using realpath here causes issues because clang uses clang++ as a symlink # so if that's resolved, it won't build for C++ -REAL_CC = $(shell which clang-16 2>/dev/null || which clang 2>/dev/null) -REAL_CXX = $(shell which clang++-16 2>/dev/null || which clang++ 2>/dev/null) -CLANG_FORMAT = $(shell which clang-format-16 2>/dev/null || which clang-format 2>/dev/null) +REAL_CC = $(shell which clang-18 2>/dev/null || which clang 2>/dev/null) +REAL_CXX = $(shell which clang++-18 2>/dev/null || which clang++ 2>/dev/null) +CLANG_FORMAT = $(shell which clang-format-18 2>/dev/null || which clang-format 2>/dev/null) CC = $(REAL_CC) CXX = $(REAL_CXX) @@ -117,14 +117,14 @@ CC_WITH_CCACHE = $(CCACHE_PATH) $(CC) ifeq ($(OS_NAME),darwin) # Find LLVM ifeq ($(wildcard $(LLVM_PREFIX)),) - LLVM_PREFIX = $(shell brew --prefix llvm@16) + LLVM_PREFIX = $(shell brew --prefix llvm@18) endif ifeq ($(wildcard $(LLVM_PREFIX)),) LLVM_PREFIX = $(shell brew --prefix llvm) endif ifeq ($(wildcard $(LLVM_PREFIX)),) # This is kinda ugly, but I can't find a better way to error :( - LLVM_PREFIX = $(shell echo -e "error: Unable to find llvm. Please run 'brew install llvm@16' or set LLVM_PREFIX=/path/to/llvm") + LLVM_PREFIX = $(shell echo -e "error: Unable to find llvm. Please run 'brew install llvm@18' or set LLVM_PREFIX=/path/to/llvm") endif LDFLAGS += -L$(LLVM_PREFIX)/lib @@ -164,7 +164,7 @@ CMAKE_FLAGS_WITHOUT_RELEASE = -DCMAKE_C_COMPILER=$(CC) \ -DCMAKE_OSX_DEPLOYMENT_TARGET=$(MIN_MACOS_VERSION) \ $(CMAKE_CXX_COMPILER_LAUNCHER_FLAG) \ -DCMAKE_AR=$(AR) \ - -DCMAKE_RANLIB=$(which llvm-16-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null) \ + -DCMAKE_RANLIB=$(which llvm-18-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null) \ -DCMAKE_CXX_STANDARD=20 \ -DCMAKE_C_STANDARD=17 \ -DCMAKE_CXX_STANDARD_REQUIRED=ON \ @@ -191,7 +191,7 @@ endif ifeq ($(OS_NAME),linux) LIBICONV_PATH = -AR = $(shell which llvm-ar-16 2>/dev/null || which llvm-ar 2>/dev/null || which ar 2>/dev/null) +AR = $(shell which llvm-ar-18 2>/dev/null || which llvm-ar 2>/dev/null || which ar 2>/dev/null) endif OPTIMIZATION_LEVEL=-O3 $(MARCH_NATIVE) @@ -286,7 +286,7 @@ STRIP=/usr/bin/strip endif ifeq ($(OS_NAME),linux) -STRIP=$(shell which llvm-strip 2>/dev/null || which llvm-strip-16 2>/dev/null || which strip 2>/dev/null || echo "Missing strip") +STRIP=$(shell which llvm-strip 2>/dev/null || which llvm-strip-18 2>/dev/null || which strip 2>/dev/null || echo "Missing strip") endif @@ -674,7 +674,7 @@ endif .PHONY: assert-deps assert-deps: @echo "Checking if the required utilities are available..." - @if [ $(CLANG_VERSION) -lt "15" ]; then echo -e "ERROR: clang version >=15 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@16"; exit 1; fi + @if [ $(CLANG_VERSION) -lt "15" ]; then echo -e "ERROR: clang version >=15 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@18"; exit 1; fi @cmake --version >/dev/null 2>&1 || (echo -e "ERROR: cmake is required."; exit 1) @$(PYTHON) --version >/dev/null 2>&1 || (echo -e "ERROR: python is required."; exit 1) @$(ESBUILD) --version >/dev/null 2>&1 || (echo -e "ERROR: esbuild is required."; exit 1) From 50ed8d5753fb074d92821581e5cd092f5f1a9488 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 17:18:59 -0800 Subject: [PATCH 35/68] Fix remaining references to old clang in Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 70189a8dcd2a3b..d2940c28196f95 100644 --- a/Makefile +++ b/Makefile @@ -674,7 +674,7 @@ endif .PHONY: assert-deps assert-deps: @echo "Checking if the required utilities are available..." - @if [ $(CLANG_VERSION) -lt "15" ]; then echo -e "ERROR: clang version >=15 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@18"; exit 1; fi + @if [ $(CLANG_VERSION) -lt "18" ]; then echo -e "ERROR: clang version >=18 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@18"; exit 1; fi @cmake --version >/dev/null 2>&1 || (echo -e "ERROR: cmake is required."; exit 1) @$(PYTHON) --version >/dev/null 2>&1 || (echo -e "ERROR: python is required."; exit 1) @$(ESBUILD) --version >/dev/null 2>&1 || (echo -e "ERROR: esbuild is required."; exit 1) From 0dad62e5c4054974bc911d0f56bca4cc4ac13ea5 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 17:19:20 -0800 Subject: [PATCH 36/68] Port bun.Lock usage to bun.Mutex --- src/bun.js/api/Timer.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 75df0665cf4ed8..fc7a8697067594 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -28,7 +28,7 @@ const TimerHeap = heap.Intrusive(EventLoopTimer, void, EventLoopTimer.less); pub const All = struct { last_id: i32 = 1, - lock: bun.Lock = .{}, + lock: bun.Mutex = .{}, thread_id: std.Thread.Id, timers: TimerHeap = .{ .context = {}, @@ -936,7 +936,7 @@ pub const WTFTimer = struct { event_loop_timer: EventLoopTimer, imminent: *std.atomic.Value(?*WTFTimer), repeat: bool, - lock: bun.Lock = .{}, + lock: bun.Mutex = .{}, pub usingnamespace bun.New(@This()); From 740d4d9e4d9098d17679f883fee8180b4310f272 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 17:19:35 -0800 Subject: [PATCH 37/68] Remove unused extern declarations --- src/bun.js/bindings/headers.zig | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig index a8edcb5531d0ec..ef6ff0fab7d810 100644 --- a/src/bun.js/bindings/headers.zig +++ b/src/bun.js/bindings/headers.zig @@ -316,13 +316,6 @@ pub extern fn JSC__VM__shrinkFootprint(arg0: *bindings.VM) void; pub extern fn JSC__VM__throwError(arg0: *bindings.VM, arg1: *bindings.JSGlobalObject, JSValue2: JSC__JSValue) void; pub extern fn JSC__VM__whenIdle(arg0: *bindings.VM, ArgFn1: ?*const fn (...) callconv(.C) void) void; pub extern fn JSC__VM__performOpportunisticallyScheduledTasks(arg0: *bindings.VM, arg1: f64) void; -pub extern fn JSC__ThrowScope__clearException(arg0: [*c]bindings.ThrowScope) void; -pub extern fn JSC__ThrowScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__ThrowScope; -pub extern fn JSC__ThrowScope__exception(arg0: [*c]bindings.ThrowScope) [*c]bindings.Exception; -pub extern fn JSC__ThrowScope__release(arg0: [*c]bindings.ThrowScope) void; -pub extern fn JSC__CatchScope__clearException(arg0: [*c]bindings.CatchScope) void; -pub extern fn JSC__CatchScope__declare(arg0: *bindings.VM, arg1: [*c]u8, arg2: [*c]u8, arg3: usize) bJSC__CatchScope; -pub extern fn JSC__CatchScope__exception(arg0: [*c]bindings.CatchScope) [*c]bindings.Exception; pub extern fn FFI__ptr__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; pub extern fn Reader__u8__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; pub extern fn Reader__u16__put(arg0: *bindings.JSGlobalObject, JSValue1: JSC__JSValue) void; From 1db3e9f04e11b38a0b36e2a25f928725ed1b9f56 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 16 Jan 2025 17:19:54 -0800 Subject: [PATCH 38/68] Fix C++ compile errors --- src/bun.js/bindings/EventLoopTaskNoContext.h | 3 +-- src/bun.js/bindings/ScriptExecutionContext.h | 3 ++- src/bun.js/bindings/webcore/ContextDestructionObserver.h | 3 +-- src/bun.js/bindings/webcrypto/PhonyWorkQueue.h | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bun.js/bindings/EventLoopTaskNoContext.h b/src/bun.js/bindings/EventLoopTaskNoContext.h index e3865620d252ce..b86e8547f3e03c 100644 --- a/src/bun.js/bindings/EventLoopTaskNoContext.h +++ b/src/bun.js/bindings/EventLoopTaskNoContext.h @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include "root.h" namespace Bun { diff --git a/src/bun.js/bindings/ScriptExecutionContext.h b/src/bun.js/bindings/ScriptExecutionContext.h index 6122948614cdbb..51b49cada1f2cf 100644 --- a/src/bun.js/bindings/ScriptExecutionContext.h +++ b/src/bun.js/bindings/ScriptExecutionContext.h @@ -2,7 +2,6 @@ #include "root.h" #include "ActiveDOMObject.h" -#include "ContextDestructionObserver.h" #include #include #include @@ -33,6 +32,8 @@ class MessagePort; class ScriptExecutionContext; class EventLoopTask; +class ContextDestructionObserver; + using ScriptExecutionContextIdentifier = uint32_t; DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(ScriptExecutionContext); diff --git a/src/bun.js/bindings/webcore/ContextDestructionObserver.h b/src/bun.js/bindings/webcore/ContextDestructionObserver.h index f206ad80354e16..c90a25bd0adc98 100644 --- a/src/bun.js/bindings/webcore/ContextDestructionObserver.h +++ b/src/bun.js/bindings/webcore/ContextDestructionObserver.h @@ -3,11 +3,10 @@ #pragma once #include "root.h" +#include "ScriptExecutionContext.h" namespace WebCore { -class ScriptExecutionContext; - class ContextDestructionObserver { public: diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h index d3dbabaf21e58e..dc6879ce955bf9 100644 --- a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h @@ -1,8 +1,8 @@ #pragma once +#include "root.h" #include #include -#include namespace Bun { From 9524dc9e6c1e8968ca67a369d54de4abedaecd63 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 17 Jan 2025 14:55:20 -0800 Subject: [PATCH 39/68] Bump WebKit to include USE_BUN_EVENT_LOOP --- cmake/tools/SetupWebKit.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index d00d3a3e96eecb..0e2c1b09e8640a 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION 9e3b60e4a6438d20ee6f8aa5bec6b71d2b7d213f) + set(WEBKIT_VERSION fca5c31290625e0dc75991d6604daa923981c66a) endif() string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX) From 114639eb43a27b0c78a5e72e07bda4e155c1bdff Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 17 Jan 2025 17:24:12 -0800 Subject: [PATCH 40/68] Set is_bundler_thread_for_bytecode_cache for all JSC.initialize callsites in bundler thread --- src/bundler/bundle_v2.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 81c94b0cb6aca7..e6bb7be06d5c68 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -13440,6 +13440,7 @@ pub const LinkerContext = struct { .js; if (loader.isJavaScriptLike()) { + JSC.VirtualMachine.is_bundler_thread_for_bytecode_cache = true; JSC.initialize(false); var fdpath: bun.PathBuffer = undefined; var source_provider_url = try bun.String.createFormat("{s}" ++ bun.bytecode_extension, .{chunk.final_rel_path}); From 0af25fe83de8ddb47ef71dc129180195ec5e6122 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 17 Jan 2025 18:28:47 -0800 Subject: [PATCH 41/68] Bump WebKit for oven-sh/WebKit#80 --- cmake/tools/SetupWebKit.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/tools/SetupWebKit.cmake b/cmake/tools/SetupWebKit.cmake index 0e2c1b09e8640a..28621043068055 100644 --- a/cmake/tools/SetupWebKit.cmake +++ b/cmake/tools/SetupWebKit.cmake @@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use") option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading") if(NOT WEBKIT_VERSION) - set(WEBKIT_VERSION fca5c31290625e0dc75991d6604daa923981c66a) + set(WEBKIT_VERSION e6cb36cabed465c28c7bcbb28d86e8466ea36e8d) endif() string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX) From deabec87928a8c242cee00462cb78462aed6a39b Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 17 Jan 2025 18:36:31 -0800 Subject: [PATCH 42/68] Increase timeout for #14982 test --- test/regression/issue/14982/14982.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts index 84f5bd21146e9d..c87745208d06ae 100644 --- a/test/regression/issue/14982/14982.test.ts +++ b/test/regression/issue/14982/14982.test.ts @@ -14,5 +14,5 @@ describe("issue 14982", () => { await process.exited; expect(process.exitCode).toBe(0); expect(await new Response(process.stdout).text()).toBe("Test command\n"); - }, 1000); + }, 5000); }); From 15a7f64cfce58688274698df2bd6f8e278c5c681 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 17 Jan 2025 21:25:07 -0800 Subject: [PATCH 43/68] Possibly fix Worker refcount issue --- src/bun.js/bindings/webcore/Worker.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp index 3b5d322b0bf64e..f5b888361bf816 100644 --- a/src/bun.js/bindings/webcore/Worker.cpp +++ b/src/bun.js/bindings/webcore/Worker.cpp @@ -198,6 +198,8 @@ ExceptionOr> Worker::create(ScriptExecutionContext& context, const S execArgv ? static_cast(execArgv->size()) : 0, preloadModules.size() ? preloadModules.data() : nullptr, static_cast(preloadModules.size())); + // now referenced by Zig + worker->ref(); preloadModuleStrings->clear(); @@ -417,9 +419,8 @@ void Worker::forEachWorker(const Functionref(); worker->dispatchExit(exitCode); + // no longer referenced by Zig worker->deref(); if (globalObject) { From aa768a80d46262a8b88f3feccd4b90c8a8c4d6e4 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 12:02:01 -0800 Subject: [PATCH 44/68] Remove unneeded file --- src/bun.js/bindings/wtf_timer_inspection.cpp | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/bun.js/bindings/wtf_timer_inspection.cpp diff --git a/src/bun.js/bindings/wtf_timer_inspection.cpp b/src/bun.js/bindings/wtf_timer_inspection.cpp deleted file mode 100644 index 8337712ea57f00..00000000000000 --- a/src/bun.js/bindings/wtf_timer_inspection.cpp +++ /dev/null @@ -1 +0,0 @@ -// From 94840d6f6e1bf5e3b9809746cefaa77de02e2462 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 12:02:22 -0800 Subject: [PATCH 45/68] Fix SubtleCrypto tasks not keeping event loop alive --- src/bun.js/event_loop.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 6ff0309dacef86..4b85c15f0884b3 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -323,12 +323,18 @@ pub const ConcurrentCppTask = struct { const cpp_task = this.cpp_task; this.destroy(); cpp_task.run(); + if (JSC.VirtualMachine.getMainThreadVM()) |vm| { + vm.event_loop.unrefConcurrently(); + } } pub usingnamespace bun.New(@This()); pub export fn ConcurrentCppTask__createAndRun(cpp_task: *EventLoopTaskNoContext) void { JSC.markBinding(@src()); + if (JSC.VirtualMachine.getMainThreadVM()) |vm| { + vm.event_loop.refConcurrently(); + } const cpp = ConcurrentCppTask.new(.{ .cpp_task = cpp_task }); JSC.WorkPool.schedule(&cpp.workpool_task); } From 403f9d69fefbf2710e35453b64e196d1d0da8ff0 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 12:50:05 -0800 Subject: [PATCH 46/68] More properly fix not refing event loop --- src/bun.js/bindings/EventLoopTaskNoContext.cpp | 5 +++++ src/bun.js/bindings/EventLoopTaskNoContext.h | 10 ++++++++-- src/bun.js/bindings/webcrypto/CryptoAlgorithm.cpp | 4 +--- .../bindings/webcrypto/CryptoAlgorithmECDH.cpp | 2 +- .../bindings/webcrypto/CryptoAlgorithmSHA1.cpp | 7 ++----- .../bindings/webcrypto/CryptoAlgorithmSHA224.cpp | 6 ++---- .../bindings/webcrypto/CryptoAlgorithmSHA256.cpp | 7 +++---- .../bindings/webcrypto/CryptoAlgorithmSHA384.cpp | 7 ++----- .../bindings/webcrypto/CryptoAlgorithmSHA512.cpp | 7 ++----- src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp | 4 ++-- src/bun.js/bindings/webcrypto/PhonyWorkQueue.h | 2 +- src/bun.js/event_loop.zig | 13 +++++++++++-- 12 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/bun.js/bindings/EventLoopTaskNoContext.cpp b/src/bun.js/bindings/EventLoopTaskNoContext.cpp index 2695ecb84f5a04..473bc3f11f2c69 100644 --- a/src/bun.js/bindings/EventLoopTaskNoContext.cpp +++ b/src/bun.js/bindings/EventLoopTaskNoContext.cpp @@ -9,4 +9,9 @@ extern "C" void Bun__EventLoopTaskNoContext__performTask(EventLoopTaskNoContext* task->performTask(); } +extern "C" void* Bun__EventLoopTaskNoContext__createdInBunVm(const EventLoopTaskNoContext* task) +{ + return task->createdInBunVm(); +} + } // namespace Bun diff --git a/src/bun.js/bindings/EventLoopTaskNoContext.h b/src/bun.js/bindings/EventLoopTaskNoContext.h index b86e8547f3e03c..0f3491ce7676e6 100644 --- a/src/bun.js/bindings/EventLoopTaskNoContext.h +++ b/src/bun.js/bindings/EventLoopTaskNoContext.h @@ -1,5 +1,6 @@ #pragma once +#include "ZigGlobalObject.h" #include "root.h" namespace Bun { @@ -9,8 +10,9 @@ class EventLoopTaskNoContext { WTF_MAKE_ISO_ALLOCATED(EventLoopTaskNoContext); public: - EventLoopTaskNoContext(Function&& task) - : m_task(WTFMove(task)) + EventLoopTaskNoContext(JSC::JSGlobalObject* globalObject, Function&& task) + : m_createdInBunVm(defaultGlobalObject(globalObject)->bunVM()) + , m_task(WTFMove(task)) { } @@ -20,10 +22,14 @@ class EventLoopTaskNoContext { delete this; } + void* createdInBunVm() const { return m_createdInBunVm; } + private: + void* m_createdInBunVm; Function m_task; }; extern "C" void Bun__EventLoopTaskNoContext__performTask(EventLoopTaskNoContext* task); +extern "C" void* Bun__EventLoopTaskNoContext__createdInBunVm(const EventLoopTaskNoContext* task); } // namespace Bun diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithm.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithm.cpp index f6350fe65d4f1f..318a8e15bef4df 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithm.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithm.cpp @@ -95,12 +95,10 @@ ExceptionOr CryptoAlgorithm::getKeyLength(const CryptoAlgorithmParameter template static void dispatchAlgorithmOperation(WorkQueue& workQueue, ScriptExecutionContext& context, ResultCallbackType&& callback, CryptoAlgorithm::ExceptionCallback&& exceptionCallback, OperationType&& operation) { - context.refEventLoop(); - workQueue.dispatch( + workQueue.dispatch(context.globalObject(), [operation = WTFMove(operation), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), contextIdentifier = context.identifier()]() mutable { auto result = operation(); ScriptExecutionContext::postTaskTo(contextIdentifier, [result = crossThreadCopy(WTFMove(result)), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](auto& context) mutable { - context.unrefEventLoop(); if (result.hasException()) { exceptionCallback(result.releaseException().code(), ""_s); return; diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmECDH.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmECDH.cpp index a26290f7aa56e9..acb047cc722bac 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmECDH.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmECDH.cpp @@ -110,7 +110,7 @@ void CryptoAlgorithmECDH::deriveBits(const CryptoAlgorithmParameters& parameters // This is a special case that can't use dispatchOperation() because it bundles // the result validation and callback dispatch into unifiedCallback. - workQueue.dispatch( + workQueue.dispatch(context.globalObject(), [baseKey = WTFMove(baseKey), publicKey = ecParameters.publicKey, length, unifiedCallback = WTFMove(unifiedCallback), contextIdentifier = context.identifier()]() mutable { auto derivedKey = platformDeriveBits(downcast(baseKey.get()), downcast(*publicKey)); ScriptExecutionContext::postTaskTo(contextIdentifier, [derivedKey = WTFMove(derivedKey), length, unifiedCallback = WTFMove(unifiedCallback)](auto&) mutable { diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA1.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA1.cpp index e2691e87a04c95..fb919908a2ae4d 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA1.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA1.cpp @@ -61,13 +61,10 @@ void CryptoAlgorithmSHA1::digest(Vector&& message, VectorCallback&& cal return; } - context.refEventLoop(); - - workQueue.dispatch([digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { + workQueue.dispatch(context.globalObject(), [digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { digest->addBytes(message.data(), message.size()); auto result = digest->computeHash(); - ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto& context) { - context.unrefEventLoop(); + ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto&) { callback(result); }); }); diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA224.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA224.cpp index 9333c304adf380..7080ab025544a2 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA224.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA224.cpp @@ -61,12 +61,10 @@ void CryptoAlgorithmSHA224::digest(Vector&& message, VectorCallback&& c return; } - context.refEventLoop(); - workQueue.dispatch([digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { + workQueue.dispatch(context.globalObject(), [digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { digest->addBytes(message.data(), message.size()); auto result = digest->computeHash(); - ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto& context) { - context.unrefEventLoop(); + ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto&) { callback(result); }); }); diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA256.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA256.cpp index c04dfc790c9110..d55e874155c64e 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA256.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA256.cpp @@ -60,12 +60,11 @@ void CryptoAlgorithmSHA256::digest(Vector&& message, VectorCallback&& c }); return; } - context.refEventLoop(); - workQueue.dispatch([digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { + + workQueue.dispatch(context.globalObject(), [digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { digest->addBytes(message.data(), message.size()); auto result = digest->computeHash(); - ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto& context) { - context.unrefEventLoop(); + ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto&) { callback(result); }); }); diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA384.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA384.cpp index 0297099f985af7..a4237487d6ab9c 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA384.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA384.cpp @@ -61,13 +61,10 @@ void CryptoAlgorithmSHA384::digest(Vector&& message, VectorCallback&& c return; } - context.refEventLoop(); - - workQueue.dispatch([digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { + workQueue.dispatch(context.globalObject(), [digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { digest->addBytes(message.data(), message.size()); auto result = digest->computeHash(); - ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto& context) { - context.unrefEventLoop(); + ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto&) { callback(result); }); }); diff --git a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA512.cpp b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA512.cpp index edb1f8b492b38f..e902cfa1d5e835 100644 --- a/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA512.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA512.cpp @@ -61,13 +61,10 @@ void CryptoAlgorithmSHA512::digest(Vector&& message, VectorCallback&& c return; } - context.refEventLoop(); - workQueue.dispatch([digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { + workQueue.dispatch(context.globalObject(), [digest = WTFMove(digest), message = WTFMove(message), callback = WTFMove(callback), contextIdentifier = context.identifier()]() mutable { digest->addBytes(message.data(), message.size()); auto result = digest->computeHash(); - - ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto& context) { - context.unrefEventLoop(); + ScriptExecutionContext::postTaskTo(contextIdentifier, [callback = WTFMove(callback), result = WTFMove(result)](auto&) { callback(result); }); }); diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp index 1657db4bcfac49..325ce6ad0273e6 100644 --- a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp @@ -13,9 +13,9 @@ Ref PhonyWorkQueue::create(WTF::ASCIILiteral name) extern "C" void ConcurrentCppTask__createAndRun(EventLoopTaskNoContext* task); -void PhonyWorkQueue::dispatch(WTF::Function&& function) +void PhonyWorkQueue::dispatch(JSC::JSGlobalObject* globalObject, WTF::Function&& function) { - ConcurrentCppTask__createAndRun(new EventLoopTaskNoContext(WTFMove(function))); + ConcurrentCppTask__createAndRun(new EventLoopTaskNoContext(globalObject, WTFMove(function))); } } // namespace Bun diff --git a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h index dc6879ce955bf9..7d225bee3d74c9 100644 --- a/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h +++ b/src/bun.js/bindings/webcrypto/PhonyWorkQueue.h @@ -13,7 +13,7 @@ class PhonyWorkQueue : public WTF::RefCounted { public: static Ref create(WTF::ASCIILiteral name); - void dispatch(Function&&); + void dispatch(JSC::JSGlobalObject* globalObject, Function&&); }; }; // namespace Bun diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 4b85c15f0884b3..9a631b4f608e55 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -311,19 +311,28 @@ pub const ConcurrentCppTask = struct { const EventLoopTaskNoContext = opaque { extern fn Bun__EventLoopTaskNoContext__performTask(task: *EventLoopTaskNoContext) void; + extern fn Bun__EventLoopTaskNoContext__createdInBunVm(task: *const EventLoopTaskNoContext) ?*JSC.VirtualMachine; /// Deallocates `this` pub fn run(this: *EventLoopTaskNoContext) void { Bun__EventLoopTaskNoContext__performTask(this); } + + /// Get the VM that created this task + pub fn getVM(this: *const EventLoopTaskNoContext) ?*JSC.VirtualMachine { + return Bun__EventLoopTaskNoContext__createdInBunVm(this); + } }; pub fn runFromWorkpool(task: *JSC.WorkPoolTask) void { var this: *ConcurrentCppTask = @fieldParentPtr("workpool_task", task); + // Extract all the info we need from `this` and `cpp_task` before we call functions that + // free them const cpp_task = this.cpp_task; + const maybe_vm = cpp_task.getVM(); this.destroy(); cpp_task.run(); - if (JSC.VirtualMachine.getMainThreadVM()) |vm| { + if (maybe_vm) |vm| { vm.event_loop.unrefConcurrently(); } } @@ -332,7 +341,7 @@ pub const ConcurrentCppTask = struct { pub export fn ConcurrentCppTask__createAndRun(cpp_task: *EventLoopTaskNoContext) void { JSC.markBinding(@src()); - if (JSC.VirtualMachine.getMainThreadVM()) |vm| { + if (cpp_task.getVM()) |vm| { vm.event_loop.refConcurrently(); } const cpp = ConcurrentCppTask.new(.{ .cpp_task = cpp_task }); From e462d938e28baa8aa8cef28738b0b7e787880194 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 13:43:41 -0800 Subject: [PATCH 47/68] Fix process-signal-handler.fixture.js --- .../node/process/process-signal-handler.fixture.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/js/node/process/process-signal-handler.fixture.js b/test/js/node/process/process-signal-handler.fixture.js index 38c3d01a601787..8d2990fd025e47 100644 --- a/test/js/node/process/process-signal-handler.fixture.js +++ b/test/js/node/process/process-signal-handler.fixture.js @@ -49,21 +49,21 @@ function done2() { } } -const SIGUSR1 = os.constants.signals.SIGUSR1; const SIGUSR2 = os.constants.signals.SIGUSR2; switch (process.argv.at(-1)) { case "SIGUSR1": { - const SIGNAL = os.constants.signals[process.platform === "linux" ? "SIGUSR2" : "SIGUSR1"]; - process.on(SIGNAL, function () { - checkSignal(SIGNAL, arguments); + const signalName = process.platform === "linux" ? "SIGUSR2" : "SIGUSR1"; + const signalNumber = os.constants.signals[signalName]; + process.on(signalName, function () { + checkSignal(signalName, arguments); done(); }); - process.on(SIGNAL, function () { - checkSignal(SIGNAL, arguments); + process.on(signalName, function () { + checkSignal(signalName, arguments); done(); }); - raise(SIGNAL); + raise(signalNumber); break; } case "SIGUSR2": { From e420329c1ff65acfeacb67a2587382fd980e0fe4 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 15:06:04 -0800 Subject: [PATCH 48/68] Revert autokiller change --- src/bun.js/javascript.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index c61ebf501d28c7..78769995f691e5 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -736,7 +736,7 @@ const AutoKiller = struct { while (this.processes.popOrNull()) |process| { if (!process.key.hasExited()) { log("process.kill {d}", .{process.key.pid}); - count += @as(u32, @intFromBool(process.key.kill(@intFromEnum(bun.SignalCode.SIGKILL)) == .result)); + count += @as(u32, @intFromBool(process.key.kill(bun.SignalCode.default) == .result)); } } return count; From 7b313be7c26cc32d56a1bbc1b07ea9a4d1b3463e Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 18:43:32 -0800 Subject: [PATCH 49/68] Revert TestRunner.scheduleTimeout to call remove/insert instead of update --- src/bun.js/test/jest.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index fc2de9f51c9427..b2d2e9917d446a 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -134,7 +134,12 @@ pub const TestRunner = struct { const vm = JSC.VirtualMachine.get(); this.event_loop_timer.tag = .TestRunner; - vm.timer.update(&this.event_loop_timer, &then); + if (this.event_loop_timer.state == .ACTIVE) { + vm.timer.remove(&this.event_loop_timer); + } + + this.event_loop_timer.next = then; + vm.timer.insert(&this.event_loop_timer); } pub fn enqueue(this: *TestRunner, task: *TestRunnerTask) void { From 65ab1d32ab46aa0ce3bff64b49f00b1511701589 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 19:00:42 -0800 Subject: [PATCH 50/68] Fix test-aborted.test.ts --- test/js/node/util/test-aborted.test.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/test/js/node/util/test-aborted.test.ts b/test/js/node/util/test-aborted.test.ts index d498681f317a25..11af6f00e04d5f 100644 --- a/test/js/node/util/test-aborted.test.ts +++ b/test/js/node/util/test-aborted.test.ts @@ -37,15 +37,32 @@ test("aborted works when provided a resource that was not already aborted", asyn test("aborted with gc cleanup", async () => { const ac = new AbortController(); - const abortedPromise = aborted(ac.signal, {}); + let finalized = false; + // make a FinalizationRegistry to tell us when the second argument to aborted() + // has been garbage collected + const registry = new FinalizationRegistry(() => { + finalized = true; + }); + const abortedPromise = (() => { + const gcMe = {}; + registry.register(gcMe, undefined); + const abortedPromise = aborted(ac.signal, gcMe); + return abortedPromise; + // gcMe is now out of scope and eligible to be collected + })(); + abortedPromise.then(() => { + throw new Error("this promise should never resolve"); + }); - await new Promise(resolve => setImmediate(resolve)); - Bun.gc(true); + // wait for the object to be GC'd by ticking the event loop and forcing garbage collection + while (!finalized) { + await new Promise(resolve => setImmediate(resolve)); + Bun.gc(true); + } ac.abort(); expect(ac.signal.aborted).toBe(true); expect(getEventListeners(ac.signal, "abort").length).toBe(0); - return expect(await abortedPromise).toBeUndefined(); }); test("fails with error if not provided abort signal", async () => { From 11edf7cb54c5d8e6dd227c2725276788c042d2bd Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 19:18:20 -0800 Subject: [PATCH 51/68] Move commander dependency to outer test folder --- test/bun.lock | 5 +++- test/package.json | 1 + test/regression/issue/14982/bun.lockb | Bin 3481 -> 0 bytes test/regression/issue/14982/package.json | 14 ----------- test/regression/issue/14982/tsconfig.json | 27 ---------------------- 5 files changed, 5 insertions(+), 42 deletions(-) delete mode 100755 test/regression/issue/14982/bun.lockb delete mode 100644 test/regression/issue/14982/package.json delete mode 100644 test/regression/issue/14982/tsconfig.json diff --git a/test/bun.lock b/test/bun.lock index 3fa67d59477377..a27a556ad12c0b 100644 --- a/test/bun.lock +++ b/test/bun.lock @@ -21,6 +21,7 @@ "axios": "1.6.8", "body-parser": "1.20.2", "comlink": "4.4.1", + "commander": "12.1.0", "devalue": "5.1.1", "es-module-lexer": "1.3.0", "esbuild": "0.18.6", @@ -862,7 +863,7 @@ "comlink": ["comlink@4.4.1", "", {}, "sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q=="], - "commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "component-emitter": ["component-emitter@1.3.1", "", {}, "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ=="], @@ -2422,6 +2423,8 @@ "webpack-cli/colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], + "webpack-cli/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], diff --git a/test/package.json b/test/package.json index edc248dadfa608..a229421e039d0f 100644 --- a/test/package.json +++ b/test/package.json @@ -26,6 +26,7 @@ "axios": "1.6.8", "body-parser": "1.20.2", "comlink": "4.4.1", + "commander": "12.1.0", "devalue": "5.1.1", "es-module-lexer": "1.3.0", "esbuild": "0.18.6", diff --git a/test/regression/issue/14982/bun.lockb b/test/regression/issue/14982/bun.lockb deleted file mode 100755 index 7d6d29d881383c259c015fbc6ebc3951923d69ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3481 zcmd5;Yfuwc6iy&MNEMU@$7+$F6_uFHgAjtmpdIatDF{0FMnke8!DIuw8y=}usE5HBFaUfr{~R0_*D&|?o{rIDho29Qr$WP$-aOuSTwRi~xZ|B) zvrd(S-Wpl1n6ox&-^BPJr@rZC>gL*t6PpURWjEWljV>B5TR~<5?Q-qir0zR-OoAWU!7RMtGR00tUbT-6=*8N~0 zLmsWY4Gi<=!*_*rA;SODfKMp!@cL4VW`;z+Tz%1ents^H*19sC#}fy(C<0B@hV#yl z@9s^i{Jnie#X0k8$$KX!zS!)VQgeOqTj#2-k5S13mt7kYbn$=>FRmLpwkX=HdShtV zta0wCvaP$*nk;EU-o0dw{;axr@!Pi+RMnR58ynw2%>U_5XUfJSpIhr%JCj$wL{5(y z@gRHa{_^lCzxnXuI&i$yp=rlO4T_Gt{nnJlA9l;+`_~m$wb;`m9tBr*e!V35_3Q!S zjCHML5o=bJgf5M%5ntX}-Z(7X`Em59>+SPW4*T$;dSVmR9IJ0TYg?G;YATRT4rnS% zIha;+HZg8BX*HHgHeX_Q9@U;XV;4N4D9A*SF6_ zQPWBj+P1T=imOs{*YAi(FOsBNV{SJloJ_oOFOS_7S6LHzW7>zwr(RLiE#EY|u+Kb2 z$>O~qME-f@a8j7%rhBIkFX}sNq8;^##S5qFEBnoCyq5e+n_Kk#$POQV)0o8kKfrEeNrvs#Oj!E_2s2b_LIohKp0ElE5USvL4E%$|`U&fx0O1lH5lg6) z0<5&KVuCknB>{vwDI|%s7uHblCYDfZ3C+J?q9J!=m3-bmd-M0LH$yt|NSc^hz>+j& zv`=Sg8 Date: Mon, 20 Jan 2025 19:50:47 -0800 Subject: [PATCH 52/68] Increase #14982 timeout even more --- test/regression/issue/14982/14982.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/regression/issue/14982/14982.test.ts b/test/regression/issue/14982/14982.test.ts index c87745208d06ae..c0a683d518b378 100644 --- a/test/regression/issue/14982/14982.test.ts +++ b/test/regression/issue/14982/14982.test.ts @@ -14,5 +14,5 @@ describe("issue 14982", () => { await process.exited; expect(process.exitCode).toBe(0); expect(await new Response(process.stdout).text()).toBe("Test command\n"); - }, 5000); + }, 15000); }); From fd2d5c082b44eb483f5fa9a1251774eefe921551 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 20 Jan 2025 21:45:46 -0800 Subject: [PATCH 53/68] Add missing UV timer initialization on Windows --- src/bun.js/api/Timer.zig | 3 +++ src/bun.js/javascript.zig | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index fc7a8697067594..46c2f0847676af 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -94,6 +94,9 @@ pub const All = struct { timer.next = time.*; this.timers.insert(timer); + if (Environment.isWindows) { + this.ensureUVTimer(@alignCast(@fieldParentPtr("timer", this))); + } } fn ensureUVTimer(this: *All, vm: *VirtualMachine) void { diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 78769995f691e5..11cf0bae56606e 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -2051,9 +2051,11 @@ pub const VirtualMachine = struct { vm.regular_event_loop.next_immediate_tasks = EventLoop.Queue.init( default_allocator, ); + vm.regular_event_loop.virtual_machine = vm; vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; + vm.eventLoop().ensureWaker(); vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = opts.store_fd; @@ -2077,7 +2079,6 @@ pub const VirtualMachine = struct { null, ); vm.regular_event_loop.global = vm.global; - vm.regular_event_loop.virtual_machine = vm; vm.jsc = vm.global.vm(); vm.smol = opts.smol; vm.dns_result_order = opts.dns_result_order; From 142206655f883a1cc14e1e922e929c32dae484b7 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Tue, 21 Jan 2025 12:02:18 -0800 Subject: [PATCH 54/68] Init event loop before VM in more places --- src/bun.js/javascript.zig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 11cf0bae56606e..9b03e352a8b791 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1931,9 +1931,11 @@ pub const VirtualMachine = struct { vm.regular_event_loop.next_immediate_tasks = EventLoop.Queue.init( default_allocator, ); + vm.regular_event_loop.virtual_machine = vm; vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; + vm.eventLoop().ensureWaker(); vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = false; @@ -1962,7 +1964,6 @@ pub const VirtualMachine = struct { null, ); vm.regular_event_loop.global = vm.global; - vm.regular_event_loop.virtual_machine = vm; vm.jsc = vm.global.vm(); vm.configureDebugger(opts.debugger); @@ -2211,9 +2212,11 @@ pub const VirtualMachine = struct { vm.regular_event_loop.next_immediate_tasks = EventLoop.Queue.init( default_allocator, ); + vm.regular_event_loop.virtual_machine = vm; vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; + vm.eventLoop().ensureWaker(); vm.hot_reload = worker.parent.hot_reload; vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = opts.store_fd; @@ -2242,7 +2245,6 @@ pub const VirtualMachine = struct { worker.cpp_worker, ); vm.regular_event_loop.global = vm.global; - vm.regular_event_loop.virtual_machine = vm; vm.jsc = vm.global.vm(); vm.transpiler.setAllocator(allocator); vm.body_value_hive_allocator = BodyValueHiveAllocator.init(bun.typedAllocator(JSC.WebCore.Body.Value)); @@ -2302,9 +2304,11 @@ pub const VirtualMachine = struct { vm.regular_event_loop.next_immediate_tasks = EventLoop.Queue.init( default_allocator, ); + vm.regular_event_loop.virtual_machine = vm; vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; + vm.eventLoop().ensureWaker(); vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = opts.store_fd; @@ -2320,7 +2324,6 @@ pub const VirtualMachine = struct { vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); - vm.regular_event_loop.virtual_machine = vm; vm.smol = opts.smol; if (opts.smol) From 4b5941f476682977d190a8b37c99c682ef055a6e Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 22 Jan 2025 17:06:39 -0800 Subject: [PATCH 55/68] Fix bogus pointers stored in event loop --- src/bun.js/javascript.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 9b03e352a8b791..db9e5e5fbefbad 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1965,6 +1965,7 @@ pub const VirtualMachine = struct { ); vm.regular_event_loop.global = vm.global; vm.jsc = vm.global.vm(); + uws.Loop.get().internal_loop_data.jsc_vm = vm.jsc; vm.configureDebugger(opts.debugger); vm.body_value_hive_allocator = BodyValueHiveAllocator.init(bun.typedAllocator(JSC.WebCore.Body.Value)); @@ -2081,6 +2082,7 @@ pub const VirtualMachine = struct { ); vm.regular_event_loop.global = vm.global; vm.jsc = vm.global.vm(); + uws.Loop.get().internal_loop_data.jsc_vm = vm.jsc; vm.smol = opts.smol; vm.dns_result_order = opts.dns_result_order; @@ -2246,6 +2248,7 @@ pub const VirtualMachine = struct { ); vm.regular_event_loop.global = vm.global; vm.jsc = vm.global.vm(); + uws.Loop.get().internal_loop_data.jsc_vm = vm.jsc; vm.transpiler.setAllocator(allocator); vm.body_value_hive_allocator = BodyValueHiveAllocator.init(bun.typedAllocator(JSC.WebCore.Body.Value)); From 170d35185c7047fdb94d818ef033b8b7a9fbccda Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 23 Jan 2025 17:18:52 -0800 Subject: [PATCH 56/68] Fix comment --- test/regression/issue/14982/commander-hang.fixture.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/regression/issue/14982/commander-hang.fixture.ts b/test/regression/issue/14982/commander-hang.fixture.ts index c93dde80dc1f29..c29795dcbe4bcf 100644 --- a/test/regression/issue/14982/commander-hang.fixture.ts +++ b/test/regression/issue/14982/commander-hang.fixture.ts @@ -1,4 +1,4 @@ import { program } from "commander"; -// loads ./test-test.ts +// loads ./commander-hang.fixture-test.ts program.name("test").command("test", "Test command").parse(); From 46921effe4f75ef2d25ebd923a69133de79d1c79 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 23 Jan 2025 17:19:22 -0800 Subject: [PATCH 57/68] seq_cst --- src/bun.js/api/Timer.zig | 2 +- src/bun.js/event_loop.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bun.js/api/Timer.zig b/src/bun.js/api/Timer.zig index 46c2f0847676af..b5918d0c336876 100644 --- a/src/bun.js/api/Timer.zig +++ b/src/bun.js/api/Timer.zig @@ -975,7 +975,7 @@ pub const WTFTimer = struct { pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void { // There's only one of these. - this.imminent.store(if (seconds == 0) this else null, .monotonic); + this.imminent.store(if (seconds == 0) this else null, .seq_cst); if (seconds == 0.0) { return; diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index e456dfdb603e3f..9b5bb002848ecd 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -1411,7 +1411,7 @@ pub const EventLoop = struct { } if (this.entered_event_loop_count < 2) { - if (this.imminent_gc_timer.swap(null, .monotonic)) |timer| { + if (this.imminent_gc_timer.swap(null, .seq_cst)) |timer| { timer.run(this.virtual_machine); } } From ea53a8860189384614140e8b8671036294940f8b Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Thu, 23 Jan 2025 17:32:24 -0800 Subject: [PATCH 58/68] Consolidate event loop initialization before VM --- src/bun.js/bindings/exports.zig | 2 ++ src/bun.js/javascript.zig | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 66906609504224..10ba9fca8ef8c7 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -52,12 +52,14 @@ pub const ZigGlobalObject = extern struct { pub const Interface: type = NewGlobalObject(JS.VirtualMachine); pub fn create( + vm: *JSC.VirtualMachine, console: *anyopaque, context_id: i32, mini_mode: bool, eval_mode: bool, worker_ptr: ?*anyopaque, ) *JSGlobalObject { + vm.eventLoop().ensureWaker(); const global = shim.cppFn("create", .{ console, context_id, mini_mode, eval_mode, worker_ptr }); // JSC might mess with the stack size. diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index db9e5e5fbefbad..44b410e8b6db85 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1935,7 +1935,6 @@ pub const VirtualMachine = struct { vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; - vm.eventLoop().ensureWaker(); vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = false; @@ -1957,6 +1956,7 @@ pub const VirtualMachine = struct { VMHolder.main_thread_vm = vm; } vm.global = ZigGlobalObject.create( + vm, vm.console, if (opts.is_main_thread) -1 else std.math.maxInt(i32), false, @@ -2057,7 +2057,6 @@ pub const VirtualMachine = struct { vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; - vm.eventLoop().ensureWaker(); vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = opts.store_fd; @@ -2074,6 +2073,7 @@ pub const VirtualMachine = struct { vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); vm.global = ZigGlobalObject.create( + vm, vm.console, if (opts.is_main_thread) -1 else std.math.maxInt(i32), opts.smol, @@ -2218,7 +2218,6 @@ pub const VirtualMachine = struct { vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; vm.regular_event_loop.concurrent_tasks = .{}; vm.event_loop = &vm.regular_event_loop; - vm.eventLoop().ensureWaker(); vm.hot_reload = worker.parent.hot_reload; vm.transpiler.macro_context = null; vm.transpiler.resolver.store_fd = opts.store_fd; @@ -2240,6 +2239,7 @@ pub const VirtualMachine = struct { vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler); vm.global = ZigGlobalObject.create( + vm, vm.console, @as(i32, @intCast(worker.execution_context_id)), worker.mini, From b5d1f68c83e87e384c7d822837bcbccaebc7a102 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 14:12:31 -0800 Subject: [PATCH 59/68] Implement refConcurrently/unrefConcurrently with tasks instead of atomic counter --- src/bun.js/event_loop.zig | 51 +++++++++++++++------------------------ src/bun.js/javascript.zig | 3 +-- 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 9b5bb002848ecd..2f421d3ee8b486 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -545,6 +545,8 @@ pub const Task = TaggedPointerUnion(.{ WriteFile, WriteFileTask, Writev, + EventLoop.RefConcurrentlyTask, + EventLoop.UnrefConcurrentlyTask, }); const UnboundedQueue = @import("./unbounded_queue.zig").UnboundedQueue; pub const ConcurrentTask = struct { @@ -1350,6 +1352,14 @@ pub const EventLoop = struct { var any: *StatFS = task.get(StatFS).?; any.runFromJSThread(); }, + @field(Task.Tag, typeBaseName(@typeName(RefConcurrentlyTask))) => { + const loop = this.virtual_machine.event_loop_handle.?; + loop.ref(); + }, + @field(Task.Tag, typeBaseName(@typeName(UnrefConcurrentlyTask))) => { + const loop = this.virtual_machine.event_loop_handle.?; + loop.unref(); + }, else => { bun.Output.panic("Unexpected tag: {s}", .{@tagName(task.tag())}); @@ -1375,35 +1385,7 @@ pub const EventLoop = struct { _ = this.tickConcurrentWithCount(); } - /// Check whether refConcurrently has been called but the change has not yet been applied to the - /// underlying event loop's `active` counter - pub fn hasPendingRefs(this: *const EventLoop) bool { - return this.concurrent_ref.load(.seq_cst) > 0; - } - - fn updateCounts(this: *EventLoop) void { - const delta = this.concurrent_ref.swap(0, .seq_cst); - const loop = this.virtual_machine.event_loop_handle.?; - if (comptime Environment.isWindows) { - if (delta > 0) { - loop.active_handles += @intCast(delta); - } else { - loop.active_handles -= @intCast(-delta); - } - } else { - if (delta > 0) { - loop.num_polls += @intCast(delta); - loop.active += @intCast(delta); - } else { - loop.num_polls -= @intCast(-delta); - loop.active -= @intCast(-delta); - } - } - } - pub fn tickConcurrentWithCount(this: *EventLoop) usize { - this.updateCounts(); - if (comptime Environment.isPosix) { if (this.signal_handler) |signal_handler| { signal_handler.drain(this); @@ -1745,14 +1727,21 @@ pub const EventLoop = struct { this.wakeup(); } + pub const RefConcurrentlyTask = struct { + var instance: @This() = .{}; + }; + pub fn refConcurrently(this: *EventLoop) void { - _ = this.concurrent_ref.fetchAdd(1, .seq_cst); + this.enqueueTaskConcurrent(ConcurrentTask.create(Task.init(&RefConcurrentlyTask.instance))); this.wakeup(); } + pub const UnrefConcurrentlyTask = struct { + var instance: @This() = .{}; + }; + pub fn unrefConcurrently(this: *EventLoop) void { - // TODO maybe this should be AcquireRelease - _ = this.concurrent_ref.fetchSub(1, .seq_cst); + this.enqueueTaskConcurrent(ConcurrentTask.create(Task.init(&UnrefConcurrentlyTask.instance))); this.wakeup(); } }; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 9adf470d670748..5e3c5edcb0fb5d 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1028,8 +1028,7 @@ pub const VirtualMachine = struct { vm.active_tasks + vm.event_loop.tasks.count + vm.event_loop.immediate_tasks.count + - vm.event_loop.next_immediate_tasks.count + - @intFromBool(vm.event_loop.hasPendingRefs()) > 0); + vm.event_loop.next_immediate_tasks.count) > 0; } pub fn wakeup(this: *VirtualMachine) void { From e9221b23fff0da6fffa25cbed2acc36777a9a43f Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 14:29:49 -0800 Subject: [PATCH 60/68] Delete newly-unused field --- src/bun.js/event_loop.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 2f421d3ee8b486..7cab1b4f551853 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -842,7 +842,6 @@ pub const EventLoop = struct { debug: Debug = .{}, entered_event_loop_count: isize = 0, - concurrent_ref: std.atomic.Value(i32) = std.atomic.Value(i32).init(0), imminent_gc_timer: std.atomic.Value(?*JSC.BunTimer.WTFTimer) = .{ .raw = null }, signal_handler: if (Environment.isPosix) ?*PosixSignalHandle else void = if (Environment.isPosix) null, From 7c41382823f65453469b60cea6abf89ace2c4f8d Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 14:52:28 -0800 Subject: [PATCH 61/68] Fix ignoring concurrent_tasks in isEventLoopAlive --- src/bun.js/javascript.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 5e3c5edcb0fb5d..d0c0c88391b648 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1028,7 +1028,8 @@ pub const VirtualMachine = struct { vm.active_tasks + vm.event_loop.tasks.count + vm.event_loop.immediate_tasks.count + - vm.event_loop.next_immediate_tasks.count) > 0; + vm.event_loop.next_immediate_tasks.count + + vm.event_loop.concurrent_tasks.count) > 0; } pub fn wakeup(this: *VirtualMachine) void { From 7ecefc280167fd531471aa07b4fa8599cfe44220 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 14:57:03 -0800 Subject: [PATCH 62/68] Document expected output in napi test_promise_with_threadsafe_function --- test/napi/napi.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/napi/napi.test.ts b/test/napi/napi.test.ts index 3068b9c507fe87..9842f190e33c21 100644 --- a/test/napi/napi.test.ts +++ b/test/napi/napi.test.ts @@ -241,7 +241,8 @@ describe("napi", () => { describe("napi_threadsafe_function", () => { it("keeps the event loop alive without async_work", () => { - checkSameOutput("test_promise_with_threadsafe_function", []); + const result = checkSameOutput("test_promise_with_threadsafe_function", []); + expect(result).toBe("tsfn_callback\n0\nresolved to 1234\nresolved to 1234\ntsfn_finalize_callback"); }); it("does not hang on finalize", () => { From d13a1001d0eb748625ee02d5fb22e28806195363 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 18:04:07 -0800 Subject: [PATCH 63/68] Make some worker events fire only once --- src/js/node/worker_threads.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/node/worker_threads.ts b/src/js/node/worker_threads.ts index 4cd282398f67b4..8d5eabb642e158 100644 --- a/src/js/node/worker_threads.ts +++ b/src/js/node/worker_threads.ts @@ -234,11 +234,11 @@ class Worker extends EventEmitter { } throw e; } - this.#worker.addEventListener("close", this.#onClose.bind(this)); + this.#worker.addEventListener("close", this.#onClose.bind(this), { once: true }); this.#worker.addEventListener("error", this.#onError.bind(this)); this.#worker.addEventListener("message", this.#onMessage.bind(this)); this.#worker.addEventListener("messageerror", this.#onMessageError.bind(this)); - this.#worker.addEventListener("open", this.#onOpen.bind(this)); + this.#worker.addEventListener("open", this.#onOpen.bind(this), { once: true }); if (this.#urlToRevoke) { const url = this.#urlToRevoke; From c6e62c3eb957ff3c6a45a13e0fd135c20e10e010 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 18:05:12 -0800 Subject: [PATCH 64/68] Avoid never resolving worker.terminate() promise --- src/bun.js/bindings/webcore/Worker.cpp | 27 +++++++++++++------------- src/bun.js/bindings/webcore/Worker.h | 17 ++++++++++++---- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp index f5b888361bf816..ed2ccb2230aa65 100644 --- a/src/bun.js/bindings/webcore/Worker.cpp +++ b/src/bun.js/bindings/webcore/Worker.cpp @@ -136,9 +136,8 @@ void Worker::setKeepAlive(bool keepAlive) bool Worker::updatePtr() { if (!WebWorker__updatePtr(impl_, this)) { - m_wasTerminated = true; - m_isClosing = true; - m_isOnline = false; + m_terminationState = TerminationState::Terminated; + m_onlineAndClosing = ClosingFlag; return false; } @@ -224,7 +223,7 @@ Worker::~Worker() ExceptionOr Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue messageValue, StructuredSerializeOptions&& options) { - if (m_wasTerminated) + if (m_terminationState != TerminationState::NotTerminated) return Exception { InvalidStateError, "Worker has been terminated"_s }; Vector> ports; @@ -253,7 +252,7 @@ ExceptionOr Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue m void Worker::terminate() { // m_contextProxy.terminateWorkerGlobalScope(); - m_wasTerminated = true; + m_terminationState = TerminationState::TerminateRequested; WebWorker__requestTerminate(impl_); } @@ -285,16 +284,17 @@ void Worker::terminate() bool Worker::hasPendingActivity() const { - if (this->m_isOnline) { - return !this->m_isClosing; + auto onlineAndClosing = m_onlineAndClosing.load(); + if (onlineAndClosing & OnlineFlag) { + return !(onlineAndClosing & ClosingFlag); } - return !this->m_wasTerminated; + return m_terminationState != TerminationState::Terminated; } void Worker::dispatchEvent(Event& event) { - if (!m_wasTerminated) + if (m_terminationState == TerminationState::NotTerminated) EventTargetWithInlineData::dispatchEvent(event); } @@ -340,7 +340,7 @@ void Worker::dispatchOnline(Zig::GlobalObject* workerGlobalObject) Locker lock(this->m_pendingTasksMutex); - this->m_isOnline = true; + m_onlineAndClosing.fetch_or(OnlineFlag); auto* thisContext = workerGlobalObject->scriptExecutionContext(); if (!thisContext) { return; @@ -388,20 +388,19 @@ void Worker::dispatchExit(int32_t exitCode) return; ScriptExecutionContext::postTaskTo(ctx->identifier(), [exitCode, protectedThis = Ref { *this }](ScriptExecutionContext& context) -> void { - protectedThis->m_isOnline = false; - protectedThis->m_isClosing = true; + protectedThis->m_onlineAndClosing = ClosingFlag; if (protectedThis->hasEventListeners(eventNames().closeEvent)) { auto event = CloseEvent::create(exitCode == 0, static_cast(exitCode), exitCode == 0 ? "Worker terminated normally"_s : "Worker exited abnormally"_s); protectedThis->dispatchCloseEvent(event); } - protectedThis->m_wasTerminated = true; + protectedThis->m_terminationState = TerminationState::Terminated; }); } void Worker::postTaskToWorkerGlobalScope(Function&& task) { - if (!this->m_isOnline) { + if (!(m_onlineAndClosing & OnlineFlag)) { Locker lock(this->m_pendingTasksMutex); this->m_pendingTasks.append(WTFMove(task)); return; diff --git a/src/bun.js/bindings/webcore/Worker.h b/src/bun.js/bindings/webcore/Worker.h index a83f97bbbee930..21655ae3e85fd2 100644 --- a/src/bun.js/bindings/webcore/Worker.h +++ b/src/bun.js/bindings/webcore/Worker.h @@ -68,7 +68,7 @@ class Worker final : public ThreadSafeRefCounted, public EventTargetWith using ThreadSafeRefCounted::ref; void terminate(); - bool wasTerminated() const { return m_wasTerminated; } + bool wasTerminated() const { return m_terminationState == TerminationState::Terminated; } bool hasPendingActivity() const; bool updatePtr(); @@ -120,6 +120,15 @@ class Worker final : public ThreadSafeRefCounted, public EventTargetWith static void networkStateChanged(bool isOnLine); + static constexpr uint8_t OnlineFlag = 1 << 0; + static constexpr uint8_t ClosingFlag = 1 << 1; + + enum class TerminationState : uint8_t { + NotTerminated, + TerminateRequested, + Terminated, + }; + // RefPtr m_scriptLoader; WorkerOptions m_options; String m_identifier; @@ -132,10 +141,10 @@ class Worker final : public ThreadSafeRefCounted, public EventTargetWith Deque> m_pendingEvents; Lock m_pendingTasksMutex; Deque> m_pendingTasks; - std::atomic m_wasTerminated { false }; + std::atomic m_terminationState { TerminationState::NotTerminated }; bool m_didStartWorkerGlobalScope { false }; - bool m_isOnline { false }; - bool m_isClosing { false }; + // set bits according to OnlineFlag and ClosingFlag + std::atomic m_onlineAndClosing { 0 }; const ScriptExecutionContextIdentifier m_clientIdentifier; void* impl_ { nullptr }; }; From 7572913977413e2f8af4d58ab8dbfdc52a887792 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 18:43:38 -0800 Subject: [PATCH 65/68] Revert "Fix ignoring concurrent_tasks in isEventLoopAlive" This reverts commit 7c41382823f65453469b60cea6abf89ace2c4f8d. --- src/bun.js/javascript.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index d0c0c88391b648..5e3c5edcb0fb5d 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1028,8 +1028,7 @@ pub const VirtualMachine = struct { vm.active_tasks + vm.event_loop.tasks.count + vm.event_loop.immediate_tasks.count + - vm.event_loop.next_immediate_tasks.count + - vm.event_loop.concurrent_tasks.count) > 0; + vm.event_loop.next_immediate_tasks.count) > 0; } pub fn wakeup(this: *VirtualMachine) void { From 14a0ab55eea3ee00e2788f6ad7c303a77a65532b Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 18:43:42 -0800 Subject: [PATCH 66/68] Revert "Delete newly-unused field" This reverts commit e9221b23fff0da6fffa25cbed2acc36777a9a43f. --- src/bun.js/event_loop.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 7cab1b4f551853..2f421d3ee8b486 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -842,6 +842,7 @@ pub const EventLoop = struct { debug: Debug = .{}, entered_event_loop_count: isize = 0, + concurrent_ref: std.atomic.Value(i32) = std.atomic.Value(i32).init(0), imminent_gc_timer: std.atomic.Value(?*JSC.BunTimer.WTFTimer) = .{ .raw = null }, signal_handler: if (Environment.isPosix) ?*PosixSignalHandle else void = if (Environment.isPosix) null, From 173645094a7f4983844c0621aa7137b37c18201d Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 18:44:14 -0800 Subject: [PATCH 67/68] Revert "Implement refConcurrently/unrefConcurrently with tasks instead of atomic counter" This reverts commit b5d1f68c83e87e384c7d822837bcbccaebc7a102. --- src/bun.js/event_loop.zig | 51 ++++++++++++++++++++++++--------------- src/bun.js/javascript.zig | 3 ++- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 2f421d3ee8b486..9b5bb002848ecd 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -545,8 +545,6 @@ pub const Task = TaggedPointerUnion(.{ WriteFile, WriteFileTask, Writev, - EventLoop.RefConcurrentlyTask, - EventLoop.UnrefConcurrentlyTask, }); const UnboundedQueue = @import("./unbounded_queue.zig").UnboundedQueue; pub const ConcurrentTask = struct { @@ -1352,14 +1350,6 @@ pub const EventLoop = struct { var any: *StatFS = task.get(StatFS).?; any.runFromJSThread(); }, - @field(Task.Tag, typeBaseName(@typeName(RefConcurrentlyTask))) => { - const loop = this.virtual_machine.event_loop_handle.?; - loop.ref(); - }, - @field(Task.Tag, typeBaseName(@typeName(UnrefConcurrentlyTask))) => { - const loop = this.virtual_machine.event_loop_handle.?; - loop.unref(); - }, else => { bun.Output.panic("Unexpected tag: {s}", .{@tagName(task.tag())}); @@ -1385,7 +1375,35 @@ pub const EventLoop = struct { _ = this.tickConcurrentWithCount(); } + /// Check whether refConcurrently has been called but the change has not yet been applied to the + /// underlying event loop's `active` counter + pub fn hasPendingRefs(this: *const EventLoop) bool { + return this.concurrent_ref.load(.seq_cst) > 0; + } + + fn updateCounts(this: *EventLoop) void { + const delta = this.concurrent_ref.swap(0, .seq_cst); + const loop = this.virtual_machine.event_loop_handle.?; + if (comptime Environment.isWindows) { + if (delta > 0) { + loop.active_handles += @intCast(delta); + } else { + loop.active_handles -= @intCast(-delta); + } + } else { + if (delta > 0) { + loop.num_polls += @intCast(delta); + loop.active += @intCast(delta); + } else { + loop.num_polls -= @intCast(-delta); + loop.active -= @intCast(-delta); + } + } + } + pub fn tickConcurrentWithCount(this: *EventLoop) usize { + this.updateCounts(); + if (comptime Environment.isPosix) { if (this.signal_handler) |signal_handler| { signal_handler.drain(this); @@ -1727,21 +1745,14 @@ pub const EventLoop = struct { this.wakeup(); } - pub const RefConcurrentlyTask = struct { - var instance: @This() = .{}; - }; - pub fn refConcurrently(this: *EventLoop) void { - this.enqueueTaskConcurrent(ConcurrentTask.create(Task.init(&RefConcurrentlyTask.instance))); + _ = this.concurrent_ref.fetchAdd(1, .seq_cst); this.wakeup(); } - pub const UnrefConcurrentlyTask = struct { - var instance: @This() = .{}; - }; - pub fn unrefConcurrently(this: *EventLoop) void { - this.enqueueTaskConcurrent(ConcurrentTask.create(Task.init(&UnrefConcurrentlyTask.instance))); + // TODO maybe this should be AcquireRelease + _ = this.concurrent_ref.fetchSub(1, .seq_cst); this.wakeup(); } }; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 5e3c5edcb0fb5d..9adf470d670748 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -1028,7 +1028,8 @@ pub const VirtualMachine = struct { vm.active_tasks + vm.event_loop.tasks.count + vm.event_loop.immediate_tasks.count + - vm.event_loop.next_immediate_tasks.count) > 0; + vm.event_loop.next_immediate_tasks.count + + @intFromBool(vm.event_loop.hasPendingRefs()) > 0); } pub fn wakeup(this: *VirtualMachine) void { From 2297e908ae4240f2fc9f5fc015e1e5254f4133a4 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 24 Jan 2025 19:08:38 -0800 Subject: [PATCH 68/68] Make Terminated and TerminateRequested tracked separately --- src/bun.js/bindings/webcore/Worker.cpp | 26 +++++++++++++------------- src/bun.js/bindings/webcore/Worker.h | 17 +++++++---------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp index ed2ccb2230aa65..4ca0db7c35eaf6 100644 --- a/src/bun.js/bindings/webcore/Worker.cpp +++ b/src/bun.js/bindings/webcore/Worker.cpp @@ -136,8 +136,8 @@ void Worker::setKeepAlive(bool keepAlive) bool Worker::updatePtr() { if (!WebWorker__updatePtr(impl_, this)) { - m_terminationState = TerminationState::Terminated; - m_onlineAndClosing = ClosingFlag; + m_onlineClosingFlags = ClosingFlag; + m_terminationFlags.fetch_or(TerminatedFlag); return false; } @@ -223,7 +223,7 @@ Worker::~Worker() ExceptionOr Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue messageValue, StructuredSerializeOptions&& options) { - if (m_terminationState != TerminationState::NotTerminated) + if (m_terminationFlags & TerminatedFlag) return Exception { InvalidStateError, "Worker has been terminated"_s }; Vector> ports; @@ -252,7 +252,7 @@ ExceptionOr Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue m void Worker::terminate() { // m_contextProxy.terminateWorkerGlobalScope(); - m_terminationState = TerminationState::TerminateRequested; + m_terminationFlags.fetch_or(TerminateRequestedFlag); WebWorker__requestTerminate(impl_); } @@ -284,17 +284,17 @@ void Worker::terminate() bool Worker::hasPendingActivity() const { - auto onlineAndClosing = m_onlineAndClosing.load(); - if (onlineAndClosing & OnlineFlag) { - return !(onlineAndClosing & ClosingFlag); + auto onlineClosingFlags = m_onlineClosingFlags.load(); + if (onlineClosingFlags & OnlineFlag) { + return !(onlineClosingFlags & ClosingFlag); } - return m_terminationState != TerminationState::Terminated; + return !(m_terminationFlags & TerminatedFlag); } void Worker::dispatchEvent(Event& event) { - if (m_terminationState == TerminationState::NotTerminated) + if (!m_terminationFlags) EventTargetWithInlineData::dispatchEvent(event); } @@ -340,7 +340,7 @@ void Worker::dispatchOnline(Zig::GlobalObject* workerGlobalObject) Locker lock(this->m_pendingTasksMutex); - m_onlineAndClosing.fetch_or(OnlineFlag); + m_onlineClosingFlags.fetch_or(OnlineFlag); auto* thisContext = workerGlobalObject->scriptExecutionContext(); if (!thisContext) { return; @@ -388,19 +388,19 @@ void Worker::dispatchExit(int32_t exitCode) return; ScriptExecutionContext::postTaskTo(ctx->identifier(), [exitCode, protectedThis = Ref { *this }](ScriptExecutionContext& context) -> void { - protectedThis->m_onlineAndClosing = ClosingFlag; + protectedThis->m_onlineClosingFlags = ClosingFlag; if (protectedThis->hasEventListeners(eventNames().closeEvent)) { auto event = CloseEvent::create(exitCode == 0, static_cast(exitCode), exitCode == 0 ? "Worker terminated normally"_s : "Worker exited abnormally"_s); protectedThis->dispatchCloseEvent(event); } - protectedThis->m_terminationState = TerminationState::Terminated; + protectedThis->m_terminationFlags.fetch_or(TerminatedFlag); }); } void Worker::postTaskToWorkerGlobalScope(Function&& task) { - if (!(m_onlineAndClosing & OnlineFlag)) { + if (!(m_onlineClosingFlags & OnlineFlag)) { Locker lock(this->m_pendingTasksMutex); this->m_pendingTasks.append(WTFMove(task)); return; diff --git a/src/bun.js/bindings/webcore/Worker.h b/src/bun.js/bindings/webcore/Worker.h index 21655ae3e85fd2..9fe3aba7acf93f 100644 --- a/src/bun.js/bindings/webcore/Worker.h +++ b/src/bun.js/bindings/webcore/Worker.h @@ -68,7 +68,7 @@ class Worker final : public ThreadSafeRefCounted, public EventTargetWith using ThreadSafeRefCounted::ref; void terminate(); - bool wasTerminated() const { return m_terminationState == TerminationState::Terminated; } + bool wasTerminated() const { return m_terminationFlags & TerminatedFlag; } bool hasPendingActivity() const; bool updatePtr(); @@ -122,12 +122,8 @@ class Worker final : public ThreadSafeRefCounted, public EventTargetWith static constexpr uint8_t OnlineFlag = 1 << 0; static constexpr uint8_t ClosingFlag = 1 << 1; - - enum class TerminationState : uint8_t { - NotTerminated, - TerminateRequested, - Terminated, - }; + static constexpr uint8_t TerminateRequestedFlag = 1 << 0; + static constexpr uint8_t TerminatedFlag = 1 << 1; // RefPtr m_scriptLoader; WorkerOptions m_options; @@ -141,10 +137,11 @@ class Worker final : public ThreadSafeRefCounted, public EventTargetWith Deque> m_pendingEvents; Lock m_pendingTasksMutex; Deque> m_pendingTasks; - std::atomic m_terminationState { TerminationState::NotTerminated }; bool m_didStartWorkerGlobalScope { false }; - // set bits according to OnlineFlag and ClosingFlag - std::atomic m_onlineAndClosing { 0 }; + // Tracks OnlineFlag and ClosingFlag + std::atomic m_onlineClosingFlags { 0 }; + // Tracks TerminateRequestedFlag and TerminatedFlag + std::atomic m_terminationFlags { 0 }; const ScriptExecutionContextIdentifier m_clientIdentifier; void* impl_ { nullptr }; };