freeWithoutDeinit

This commit is contained in:
Alistair Smith
2025-06-03 21:24:15 -07:00
parent 89f1925f83
commit 0a4ca0f036
2 changed files with 40 additions and 15 deletions

View File

@@ -69,6 +69,8 @@ namespace WebCore {
WTF_MAKE_TZONE_ALLOCATED_IMPL(Worker);
extern "C" void WebWorker__derefFromCpp(void* worker);
extern "C" void WebWorker__notifyNeedTermination(
void* worker);
@@ -228,6 +230,12 @@ Worker::~Worker()
Locker locker { allWorkersLock };
allWorkers().remove(m_clientIdentifier);
}
if (impl_) {
auto* impl = impl_;
impl_ = nullptr;
WebWorker__derefFromCpp(impl);
}
// m_contextProxy.workerObjectDestroyed();
}
@@ -259,11 +267,17 @@ ExceptionOr<void> Worker::postMessage(JSC::JSGlobalObject& state, JSC::JSValue m
return {};
}
void Worker::terminate()
{
// m_contextProxy.terminateWorkerGlobalScope();
m_terminationFlags.fetch_or(TerminateRequestedFlag);
WebWorker__notifyNeedTermination(impl_);
if (ScriptExecutionContext::getScriptExecutionContext(m_clientIdentifier)) {
auto* impl = impl_;
impl_ = nullptr;
WebWorker__notifyNeedTermination(impl);
}
}
// const char* Worker::activeDOMObjectName() const
@@ -466,6 +480,7 @@ void Worker::forEachWorker(const Function<Function<void(ScriptExecutionContext&)
extern "C" void WebWorker__dispatchExit(Zig::GlobalObject* globalObject, Worker* worker, int32_t exitCode)
{
worker->dispatchExit(exitCode);
// no longer referenced by Zig
worker->deref();

View File

@@ -8,6 +8,10 @@ const JSValue = jsc.JSValue;
const Async = bun.Async;
const WTFStringImpl = @import("../string.zig").WTFStringImpl;
const WebWorker = @This();
const RefCount = bun.ptr.ThreadSafeRefCount(@This(), "ref_count", deinit, .{});
pub const new = bun.TrivialNew(@This());
pub const ref = RefCount.ref;
pub const deref = RefCount.deref;
/// null when haven't started yet
vm: ?*jsc.VirtualMachine = null,
@@ -18,6 +22,8 @@ execution_context_id: u32 = 0,
parent_context_id: u32 = 0,
parent: *jsc.VirtualMachine,
ref_count: RefCount,
/// To be resolved on the Worker thread at startup, in spin().
unresolved_specifier: []const u8,
preloads: [][]const u8 = &.{},
@@ -224,8 +230,8 @@ pub fn create(
}
}
var worker = bun.default_allocator.create(WebWorker) catch bun.outOfMemory();
worker.* = WebWorker{
const worker = WebWorker.new(.{
.ref_count = .init(),
.cpp_worker = cpp_worker,
.parent = parent,
.parent_context_id = parent_context_id,
@@ -245,10 +251,9 @@ pub fn create(
.argv = if (argv_ptr) |ptr| ptr[0..argv_len] else &.{},
.execArgv = if (inherit_execArgv) null else (if (execArgv_ptr) |ptr| ptr[0..execArgv_len] else &.{}),
.preloads = preloads.items,
};
});
worker.parent_poll_ref.ref(parent);
worker.ref();
return worker;
}
@@ -264,6 +269,7 @@ pub fn startWithErrorHandling(
pub fn start(
this: *WebWorker,
) anyerror!void {
errdefer this.deref();
if (this.name.len > 0) {
Output.Source.configureNamedThread(this.name);
} else {
@@ -356,15 +362,17 @@ pub fn start(
/// Deinit will clean up vm and everything.
/// Early deinit may be called from caller thread, but full vm deinit will only be called within worker's thread.
fn deinit(this: *WebWorker) void {
fn freeWithoutDeinit(this: *WebWorker) void {
log("[{d}] deinit", .{this.execution_context_id});
this.parent_poll_ref.unrefConcurrently(this.parent);
bun.default_allocator.free(this.unresolved_specifier);
for (this.preloads) |preload| {
bun.default_allocator.free(preload);
}
bun.default_allocator.free(this.preloads);
bun.default_allocator.destroy(this);
}
fn deinit(this: *WebWorker) void {
bun.destroy(this);
}
fn flushLogs(this: *WebWorker) void {
@@ -437,6 +445,10 @@ fn unhandledError(this: *WebWorker, _: anyerror) void {
this.flushLogs();
}
pub export fn WebWorker__derefFromCpp(this: *WebWorker) void {
this.deref();
}
fn spin(this: *WebWorker) void {
log("[{d}] spin start", .{this.execution_context_id});
@@ -552,11 +564,7 @@ pub fn exit(this: *WebWorker) void {
/// Request a terminate from any thread.
pub fn notifyNeedTermination(this: *WebWorker) callconv(.c) void {
const status = this.status.load(.acquire);
Output.println("notifyNeedTermination: {s}", .{@tagName(status)});
if (status == .terminated) {
if (this.status.load(.acquire) == .terminated) {
return;
}
@@ -616,16 +624,18 @@ pub fn exitAndDeinit(this: *WebWorker) noreturn {
}
bun.uws.onThreadExit();
this.deinit();
this.freeWithoutDeinit();
if (vm_to_deinit) |vm| {
vm.deinit(); // NOTE: deinit here isn't implemented, so freeing workers will leak the vm.
}
bun.deleteAllPoolsForThreadExit();
if (arena) |*arena_| {
arena_.deinit();
}
this.deref();
bun.exitThread();
}