Compare commits

...

4 Commits

Author SHA1 Message Date
Jarred Sumner
da1edb7e2b Update web_worker.zig 2025-09-26 22:53:24 -07:00
Jarred Sumner
6869f14cab Update web_worker.zig 2025-09-26 22:12:36 -07:00
Jarred Sumner
1b6162a5c1 Update InternalLoopData.zig 2025-09-26 20:59:51 -07:00
Jarred Sumner
b4938186e4 Add threadsafety assertion for event loop ref / unref 2025-09-26 20:56:39 -07:00
3 changed files with 40 additions and 2 deletions

View File

@@ -548,9 +548,9 @@ pub fn setRef(this: *WebWorker, value: bool) callconv(.c) void {
pub fn setRefInternal(this: *WebWorker, value: bool) void {
if (value) {
this.parent_poll_ref.ref(this.parent);
this.parent_poll_ref.refConcurrently(this.parent);
} else {
this.parent_poll_ref.unref(this.parent);
this.parent_poll_ref.unrefConcurrently(this.parent);
}
}
@@ -558,6 +558,11 @@ pub fn setRefInternal(this: *WebWorker, value: bool) void {
pub fn exit(this: *WebWorker) void {
this.exit_called = true;
this.notifyNeedTermination();
if (this.vm) |vm| {
if (!vm.isShuttingDown()) {
vm.jsc_vm.notifyNeedTermination();
}
}
}
/// Request a terminate from any thread.

View File

@@ -33,6 +33,26 @@ pub const InternalLoopData = extern struct {
return this.sweep_timer_count > 0;
}
pub inline fn assertCorrectThread(this: *const InternalLoopData) void {
if (comptime bun.Environment.isDebug or bun.Environment.enable_asan) {
if (this.jsc_vm) |vm| {
const is_correct_js_vm = brk: {
// VirtualMachine.get() is a threadlocal variable. So if it
// doesn't exist or doesn't match, we're on a different
// thread.
if (jsc.VirtualMachine.getOrNull()) |vm_| {
break :brk vm_.jsc_vm == vm;
}
break :brk false;
};
if (!is_correct_js_vm) {
@panic("Threadsafety violation: EventLoop can only be ref'd or unref'd from the owning thread. Doing that on another thread is not thread safe, and will cause bugs.");
}
}
}
}
pub fn setParentEventLoop(this: *InternalLoopData, parent: jsc.EventLoopHandle) void {
switch (parent) {
.js => |ptr| {

View File

@@ -42,23 +42,33 @@ pub const PosixLoop = extern struct {
pub fn inc(this: *PosixLoop) void {
log("inc {d} + 1 = {d}", .{ this.num_polls, this.num_polls + 1 });
this.num_polls += 1;
assertCorrectThread(this);
}
inline fn assertCorrectThread(this: *const PosixLoop) void {
if (comptime bun.Environment.isDebug or bun.Environment.enable_asan) {
this.internal_loop_data.assertCorrectThread();
}
}
pub fn dec(this: *PosixLoop) void {
log("dec {d} - 1 = {d}", .{ this.num_polls, this.num_polls - 1 });
this.num_polls -= 1;
assertCorrectThread(this);
}
pub fn ref(this: *PosixLoop) void {
log("ref {d} + 1 = {d} | {d} + 1 = {d}", .{ this.num_polls, this.num_polls + 1, this.active, this.active + 1 });
this.num_polls += 1;
this.active += 1;
assertCorrectThread(this);
}
pub fn unref(this: *PosixLoop) void {
log("unref {d} - 1 = {d} | {d} - 1 = {d}", .{ this.num_polls, this.num_polls - 1, this.active, this.active -| 1 });
this.num_polls -= 1;
this.active -|= 1;
assertCorrectThread(this);
}
pub fn isActive(this: *const Loop) bool {
@@ -69,18 +79,21 @@ pub const PosixLoop = extern struct {
pub fn addActive(this: *PosixLoop, value: u32) void {
log("add {d} + {d} = {d}", .{ this.active, value, this.active +| value });
this.active +|= value;
assertCorrectThread(this);
}
// This exists as a method so that we can stick a debugger in here
pub fn subActive(this: *PosixLoop, value: u32) void {
log("sub {d} - {d} = {d}", .{ this.active, value, this.active -| value });
this.active -|= value;
assertCorrectThread(this);
}
pub fn unrefCount(this: *PosixLoop, count: i32) void {
log("unref x {d}", .{count});
this.num_polls -= count;
this.active -|= @as(u32, @intCast(count));
assertCorrectThread(this);
}
pub fn get() *Loop {