Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8b513f4
Service the regular loop's concurrent queue while a macro is being wa…
robobun Aug 21, 2026
f202cb0
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 21, 2026
b19e793
Tighten comments
robobun Aug 21, 2026
2386c5a
Use into_task for the batch move, cover the un-awaited digest exit
robobun Aug 21, 2026
e6933c1
Fold take_concurrent_tasks into take_concurrent_batch
robobun Aug 21, 2026
6a2a313
Share the ticket issue path between ticket and regular_ticket
robobun Aug 21, 2026
c6e5d93
Cover the other regular-loop producers a macro can await
dylan-conway Aug 22, 2026
5eb0d4d
Route completions by the loop current when the work was initiated
dylan-conway Aug 22, 2026
30dbe52
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 22, 2026
9e92026
Assert the un-awaited digest continuation runs before exit
robobun Aug 22, 2026
c0e7d52
Take LoopKind across the FFI as the enum, not u8
dylan-conway Aug 22, 2026
ea43333
Capture the loop for cross-thread MessagePort and BroadcastChannel de…
dylan-conway Aug 22, 2026
7da4c35
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 22, 2026
5e922f9
Name BunLoopKind values loopKind, not loop
dylan-conway Aug 22, 2026
a5ead42
Make loopKind postTaskTo's second parameter, with no default
dylan-conway Aug 22, 2026
6c974b9
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 22, 2026
a87fb37
Restore multi-line lambda layout at the postTaskTo call sites
dylan-conway Aug 22, 2026
add5509
Inline postTaskToWorkerObject at its call sites
dylan-conway Aug 22, 2026
69704ce
JSCTaskScheduler: keep the two pending containers, store the loop kin…
dylan-conway Aug 22, 2026
61822af
Use the currentLoopKind accessor at the JSWorker request-reply sites
robobun Aug 22, 2026
1e73951
postTaskTo: use the caller's loopKind as given
dylan-conway Aug 22, 2026
33cb02c
JSCTaskScheduler: minimal change — store the loop kind as the map val…
dylan-conway Aug 22, 2026
a622a44
WebCrypto: capture the loop kind at dispatch and pass it to postTaskT…
dylan-conway Aug 22, 2026
f094e2b
event_loop.rs: keep the original drain, add only the finished-macro a…
dylan-conway Aug 22, 2026
80078b9
Rename finished_macro_loop to macro_loop_if_not_running
dylan-conway Aug 22, 2026
8f1658d
Merge branch 'main' into farm/4186ec60/macro-webcrypto-hang
dylan-conway Aug 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/jsc/JSCScheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,21 @@ impl JSCDeferredWorkTask {
}

/// JSC helper threads (DeferredWorkTimer): deliver a deferred-work job to the
/// VM's loop, or run its release path here if the VM is gone.
/// VM's `kind` loop (captured by `JSCTaskScheduler::onAddPendingWork` on the JS
/// thread when the work was registered), or run its release path here if the
/// VM is gone.
Comment thread
robobun marked this conversation as resolved.
#[unsafe(no_mangle)]
unsafe extern "C" fn Bun__queueJSCDeferredWorkTaskConcurrently(
r: *const crate::vm_handle::Shared,
task: *mut JSCDeferredWorkTask,
kind: crate::LoopKind,
) {
crate::mark_binding!();
// SAFETY: C++ passes the reference its JSVMClientData holds.
let handle = unsafe { crate::VmHandle::borrow_ref(r) };
// `create_from` heap-allocates with the auto-delete bit set.
let ct = ConcurrentTask::create_from(task);
if let crate::vm_handle::Posted::Refused(ct) = handle.post(crate::LoopKind::Regular, ct) {
if let crate::vm_handle::Posted::Refused(ct) = handle.post(kind, ct) {
// SAFETY: refused ⇒ we own the ConcurrentTask box; the C++ job's ticket
// was already cancelled by the VM teardown (DeferredWorkTimer is shut
// down before ~VM), so dropping the job pointer here loses nothing.
Expand Down
2 changes: 1 addition & 1 deletion src/jsc/VirtualMachine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ impl VirtualMachine {
+ self.active_tasks
+ el.tasks.readable_length()
+ el.yield_tasks.len()
+ (!el.concurrent_tasks.is_empty() as usize)
+ (el.has_concurrent_tasks() as usize)
+ (el.has_pending_refs() as usize)
> 0)
}
Expand Down
45 changes: 31 additions & 14 deletions src/jsc/VmHandle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,17 @@ enum State {

/// Which of the VM's two embedded loops a completion belongs to, fixed when
/// the ticket is taken on the JS thread (work started while a macro runs
/// completes into the macro loop). `Bun.spawnSync`'s isolated loop is not one
/// of these: its producers post through that loop's own [`JsPoster`].
/// completes into the macro loop); a weak poster passes the kind its JS-side
/// initiator captured the same way (C++ `BunLoopKind`). `Bun.spawnSync`'s
/// isolated loop is not one of these: its producers post through that loop's
/// own [`JsPoster`].
Comment thread
robobun marked this conversation as resolved.
///
/// [`JsPoster`]: bun_event_loop::JsPoster
#[repr(u8)] // C++: `BunLoopKind` (BunLoopKind.h)
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LoopKind {
Regular,
Macro,
Regular = 0,
Macro = 1,
}

/// `state` (read by every native→JS entry on the JS thread) and `vm`, on
Expand Down Expand Up @@ -341,17 +344,18 @@ impl VmHandle {
})
}

/// Queue a C++ `EventLoopTask` from another thread (WebCore's
/// `postTaskConcurrently`), or delete it unrun if the VM is closed.
/// Queue a C++ `EventLoopTask` on the VM's `kind` loop from another
/// thread (WebCore's `postTaskTo` / `postTaskConcurrently`), or delete it
/// unrun if the VM is closed.
Comment thread
robobun marked this conversation as resolved.
///
/// # Safety
/// `task` is a live heap `WebCore::EventLoopTask` the caller hands over.
pub unsafe fn post_cpp_task(&self, task: *mut crate::cpp_task::CppTask) {
pub unsafe fn post_cpp_task(&self, kind: LoopKind, task: *mut crate::cpp_task::CppTask) {
unsafe extern "C" {
fn Bun__deleteEventLoopTask(task: *mut crate::cpp_task::CppTask);
}
let ct = ConcurrentTaskItem::create(bun_event_loop::Task::init(task));
if let Posted::Refused(ct) = self.post(LoopKind::Regular, ct) {
if let Posted::Refused(ct) = self.post(kind, ct) {
// SAFETY: refused ⇒ we own both boxes.
unsafe {
drop(bun_core::heap::take(ct.as_ptr()));
Expand Down Expand Up @@ -518,6 +522,13 @@ impl VirtualMachine {
}
}

/// JS thread: [`VirtualMachine::current_loop_kind`] for C++ (`BunLoopKind`),
/// captured by the initiator of work whose completion is posted weakly.
Comment thread
robobun marked this conversation as resolved.
#[unsafe(no_mangle)]
pub extern "C" fn Bun__VM__currentLoopKind(vm: &VirtualMachine) -> LoopKind {
vm.current_loop_kind()
}

// ── Test suite only: deterministic late completions ───────────────────────
//
// `BUN_DEBUG_TEST_WORKER_TEARDOWN_GATE` (first-level worker VMs; builds with
Expand Down Expand Up @@ -693,8 +704,8 @@ pub unsafe extern "C" fn Bun__VmHandle__release(r: *const Shared) {
drop(unsafe { VmHandle::from_ref(r) });
}

/// Any thread: post a C++ task through a reference and give the reference up
/// (queued, or deleted unrun if the VM is closed).
/// Any thread: post a C++ task to the VM's `kind` loop through a reference and
/// give the reference up (queued, or deleted unrun if the VM is closed).
Comment thread
robobun marked this conversation as resolved.
///
/// # Safety
/// `r` came from `Bun__VmHandle__retain*` and is not used afterwards; `task` is
Expand All @@ -703,11 +714,12 @@ pub unsafe extern "C" fn Bun__VmHandle__release(r: *const Shared) {
pub unsafe extern "C" fn Bun__VmHandle__postAndRelease(
r: *const Shared,
task: *mut crate::cpp_task::CppTask,
kind: LoopKind,
) {
// SAFETY: fn contract.
let handle = unsafe { VmHandle::from_ref(r) };
// SAFETY: fn contract.
unsafe { handle.post_cpp_task(task) };
unsafe { handle.post_cpp_task(kind, task) };
}

/// JS thread: adjust this VM's keep-alive directly.
Expand All @@ -720,14 +732,19 @@ pub extern "C" fn Bun__eventLoop__refKeepAlive(vm: &VirtualMachine, delta: core:
}
}

/// Any thread: adjust the VM's keep-alive (no-op once the VM is closed).
/// Any thread: adjust the keep-alive on the VM's `kind` loop (no-op once the
/// VM is closed).
Comment thread
robobun marked this conversation as resolved.
///
/// # Safety
/// `r` is a live reference its holder keeps for the duration of the call.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Bun__VmHandle__refKeepAlive(r: *const Shared, delta: core::ffi::c_int) {
pub unsafe extern "C" fn Bun__VmHandle__refKeepAlive(
r: *const Shared,
kind: LoopKind,
delta: core::ffi::c_int,
) {
// SAFETY: fn contract.
unsafe { VmHandle::borrow_ref(r) }.add_keep_alive(LoopKind::Regular, delta.signum());
unsafe { VmHandle::borrow_ref(r) }.add_keep_alive(kind, delta.signum());
}

/// Any thread: Node's `can_call_into_js()`.
Expand Down
8 changes: 5 additions & 3 deletions src/jsc/bindings/BunClientData.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// A counted reference to a VM's handle (bun_jsc::VmHandle): what any thread other than the
// VM's own uses to post work to it, keep its loop alive, or ask whether it may still run
// script. retain / retainRef take a count, release gives one up; valid however long it is held.
#include "BunLoopKind.h"
struct BunVmHandleRef;
extern "C" const BunVmHandleRef* Bun__VmHandle__retain(void* bunVM); // JS thread
extern "C" const BunVmHandleRef* Bun__VmHandle__retainRef(const BunVmHandleRef*); // any thread
Expand All @@ -23,9 +24,10 @@ namespace WebCore {
class WorkerMessagingProxy;
class EventLoopTask;
}
// Post through a reference and give it up in one step (a reference taken only to outlive a lock).
extern "C" void Bun__VmHandle__postAndRelease(const BunVmHandleRef*, WebCore::EventLoopTask*);
extern "C" void Bun__VmHandle__refKeepAlive(const BunVmHandleRef*, int delta);
// Post to the VM's `kind` loop through a reference and give it up in one step (a reference taken only
// to outlive a lock).
Comment thread
robobun marked this conversation as resolved.
extern "C" void Bun__VmHandle__postAndRelease(const BunVmHandleRef*, WebCore::EventLoopTask*, BunLoopKind);
extern "C" void Bun__VmHandle__refKeepAlive(const BunVmHandleRef*, BunLoopKind, int delta);
// Node's can_call_into_js(): false once the VM's stop was requested (terminate()/exit/teardown). Any thread.
extern "C" bool Bun__VmHandle__scriptAllowed(const BunVmHandleRef*);
// The handle's state byte, so hot paths test it inline (BUN_VM_HANDLE_STATE_OPEN == bun_jsc::vm_handle::State::Open).
Expand Down
8 changes: 4 additions & 4 deletions src/jsc/bindings/BunDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class BunInspectorConnection : public ThreadSafeRefCounted<BunInspectorConnectio
this->status = ConnectionStatus::Connected;
auto* globalObject = context.jsGlobalObject();
if (this->unrefOnDisconnect) {
Bun__VmHandle__refKeepAlive(WebCore::clientData(JSC::getVM(globalObject))->vmHandle, 1);
Bun__VmHandle__refKeepAlive(WebCore::clientData(JSC::getVM(globalObject))->vmHandle, BunLoopKind::Regular, 1);
}
globalObject->setInspectable(true);
auto& inspector = globalObject->inspectorDebuggable();
Expand Down Expand Up @@ -213,7 +213,7 @@ class BunInspectorConnection : public ThreadSafeRefCounted<BunInspectorConnectio

if (connection->unrefOnDisconnect) {
connection->unrefOnDisconnect = false;
Bun__VmHandle__refKeepAlive(WebCore::clientData(context.vm())->vmHandle, -1);
Bun__VmHandle__refKeepAlive(WebCore::clientData(context.vm())->vmHandle, BunLoopKind::Regular, -1);
}

{
Expand Down Expand Up @@ -476,7 +476,7 @@ class BunInspectorConnection : public ThreadSafeRefCounted<BunInspectorConnectio
notifyPausedThread();

if (this->jsThreadMessageScheduledCount++ == 0) {
ScriptExecutionContext::postTaskTo(scriptExecutionContextIdentifier, [connection = Ref { *this }](ScriptExecutionContext& context) {
ScriptExecutionContext::postTaskTo(scriptExecutionContextIdentifier, BunLoopKind::Regular, [connection = Ref { *this }](ScriptExecutionContext& context) {
connection->receiveMessagesOnInspectorThread(context, static_cast<Zig::GlobalObject*>(context.jsGlobalObject()), true);
});
}
Expand All @@ -492,7 +492,7 @@ class BunInspectorConnection : public ThreadSafeRefCounted<BunInspectorConnectio
notifyPausedThread();

if (this->jsThreadMessageScheduledCount++ == 0) {
ScriptExecutionContext::postTaskTo(scriptExecutionContextIdentifier, [connection = Ref { *this }](ScriptExecutionContext& context) {
ScriptExecutionContext::postTaskTo(scriptExecutionContextIdentifier, BunLoopKind::Regular, [connection = Ref { *this }](ScriptExecutionContext& context) {
connection->receiveMessagesOnInspectorThread(context, static_cast<Zig::GlobalObject*>(context.jsGlobalObject()), true);
});
}
Expand Down
17 changes: 17 additions & 0 deletions src/jsc/bindings/BunLoopKind.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <stdint.h>

// Which of a VM's two embedded event loops a posted completion belongs to
// (bun_jsc::LoopKind). Decided on the VM's own thread when the work is
// initiated: `Regular`, or `Macro` while a macro is being run, so that a
// macro's wait services what the macro started and nothing else. Work that
// no script initiated (the debugger, signals, another thread's own doing)
// is `Regular`.
Comment thread
robobun marked this conversation as resolved.
enum class BunLoopKind : uint8_t {
Regular = 0,
Macro = 1,
};

// JS thread only: the loop the VM is currently running (what a ticket taken now would record).
extern "C" BunLoopKind Bun__VM__currentLoopKind(void* bunVM);
2 changes: 1 addition & 1 deletion src/jsc/bindings/JSCFFIBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static void Bun__jscFFIThreadsafeDispatch(JSC::FFI::ThreadsafeInvocation& invoca
{
static_assert(sizeof(WebCore::ScriptExecutionContextIdentifier) <= sizeof(void*));
auto contextId = static_cast<WebCore::ScriptExecutionContextIdentifier>(reinterpret_cast<uintptr_t>(invocation.embedderContext()));
WebCore::ScriptExecutionContext::postTaskTo(contextId, [protectedInvocation = Ref { invocation }](WebCore::ScriptExecutionContext&) mutable { JSC::FFI::runThreadsafeInvocation(protectedInvocation.get()); });
WebCore::ScriptExecutionContext::postTaskTo(contextId, BunLoopKind::Regular, [protectedInvocation = Ref { invocation }](WebCore::ScriptExecutionContext&) mutable { JSC::FFI::runThreadsafeInvocation(protectedInvocation.get()); });
}

extern "C" JSC::EncodedJSValue Bun__CreateJSCFFICallback(
Expand Down
38 changes: 21 additions & 17 deletions src/jsc/bindings/JSCTaskScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ using Task = JSC::DeferredWorkTimer::Task;
namespace Bun {
using namespace JSC;

extern "C" void Bun__queueJSCDeferredWorkTaskConcurrently(const ::BunVmHandleRef*, void* task);
extern "C" void Bun__queueJSCDeferredWorkTaskConcurrently(const ::BunVmHandleRef*, void* task, BunLoopKind);

class JSCDeferredWorkTask {
public:
Expand All @@ -37,13 +37,13 @@ class JSCDeferredWorkTask {
// event-loop ref is balanced after the caller releases the lock.
static bool dropPendingTicketLocked(Bun::JSCTaskScheduler& scheduler, Ticket* ticket) WTF_REQUIRES_LOCK(scheduler.m_lock)
{
bool isKeepingEventLoopAlive = scheduler.m_pendingTicketsKeepingEventLoopAlive.removeIf([ticket](auto pendingTicket) {
return pendingTicket.ptr() == ticket;
bool isKeepingEventLoopAlive = scheduler.m_pendingTicketsKeepingEventLoopAlive.removeIf([ticket](auto& pendingTicket) {
return pendingTicket.key.ptr() == ticket;
});
// -- At this point, ticket may be an invalid pointer.
if (!isKeepingEventLoopAlive) {
scheduler.m_pendingTicketsOther.removeIf([ticket](auto pendingTicket) {
return pendingTicket.ptr() == ticket;
scheduler.m_pendingTicketsOther.removeIf([ticket](auto& pendingTicket) {
return pendingTicket.key.ptr() == ticket;
});
}
return isKeepingEventLoopAlive;
Expand All @@ -52,19 +52,21 @@ static bool dropPendingTicketLocked(Bun::JSCTaskScheduler& scheduler, Ticket* ti
void JSCTaskScheduler::onAddPendingWork(WebCore::JSVMClientData* clientData, Ref<Ticket>&& ticket, JSC::DeferredWorkTimer::WorkType kind)
{
auto& scheduler = clientData->deferredWorkTimer;
BunLoopKind loopKind = Bun__VM__currentLoopKind(clientData->bunVM);
Locker<Lock> holder { scheduler.m_lock };
if (scheduler.m_isShuttingDown) [[unlikely]]
return;
if (kind == DeferredWorkTimer::WorkType::ImminentlyScheduled) {
Bun__VmHandle__refKeepAlive(clientData->vmHandle, 1);
scheduler.m_pendingTicketsKeepingEventLoopAlive.add(WTF::move(ticket));
Bun__eventLoop__refKeepAlive(clientData->bunVM, 1);
scheduler.m_pendingTicketsKeepingEventLoopAlive.add(WTF::move(ticket), loopKind);
} else {
scheduler.m_pendingTicketsOther.add(WTF::move(ticket));
scheduler.m_pendingTicketsOther.add(WTF::move(ticket), loopKind);
}
}
void JSCTaskScheduler::onScheduleWorkSoon(WebCore::JSVMClientData* clientData, Ref<Ticket>&& ticket, Task&& task)
{
auto& scheduler = clientData->deferredWorkTimer;
BunLoopKind loopKind = BunLoopKind::Regular;
{
Locker<Lock> holder { scheduler.m_lock };
// The event loop is past its last tick: don't bother posting. Reached from
Expand All @@ -76,15 +78,17 @@ void JSCTaskScheduler::onScheduleWorkSoon(WebCore::JSVMClientData* clientData, R
bool wasKeepingAlive = dropPendingTicketLocked(scheduler, ticket.ptr());
holder.unlockEarly();
if (wasKeepingAlive)
Bun__VmHandle__refKeepAlive(clientData->vmHandle, -1);
Bun__VmHandle__refKeepAlive(clientData->vmHandle, BunLoopKind::Regular, -1);
return;
}
auto it = scheduler.m_pendingTicketsKeepingEventLoopAlive.find(ticket.ptr());
loopKind = it != scheduler.m_pendingTicketsKeepingEventLoopAlive.end() ? it->value : scheduler.m_pendingTicketsOther.get(ticket.ptr());
}
// Outside m_lock (markShuttingDown, on the VM's thread, needs it): a post that
// still races the shutdown lands on the VM handle, which either queues it for
// the teardown to release unrun or refuses it and runs the job's release path.
auto* job = new JSCDeferredWorkTask(WTF::move(ticket), WTF::move(task));
Bun__queueJSCDeferredWorkTaskConcurrently(clientData->vmHandle, job);
Bun__queueJSCDeferredWorkTaskConcurrently(clientData->vmHandle, job, loopKind);
}

void JSCTaskScheduler::onCancelPendingWork(WebCore::JSVMClientData* clientData, Ticket& ticket)
Expand All @@ -96,25 +100,25 @@ void JSCTaskScheduler::onCancelPendingWork(WebCore::JSVMClientData* clientData,
bool wasKeepingAlive = dropPendingTicketLocked(scheduler, &ticket);
holder.unlockEarly();
if (wasKeepingAlive)
Bun__VmHandle__refKeepAlive(vmHandle, -1);
Bun__VmHandle__refKeepAlive(vmHandle, BunLoopKind::Regular, -1);
}

static void runPendingWork(const ::BunVmHandleRef* vmHandle, Bun::JSCTaskScheduler& scheduler, JSCDeferredWorkTask* job)
{
Locker<Lock> holder { scheduler.m_lock };
auto pendingTicket = scheduler.m_pendingTicketsKeepingEventLoopAlive.take(job->ticket);
if (!pendingTicket) {
pendingTicket = scheduler.m_pendingTicketsOther.take(job->ticket);
bool wasPending = scheduler.m_pendingTicketsKeepingEventLoopAlive.remove(job->ticket.ptr());
if (!wasPending) {
wasPending = scheduler.m_pendingTicketsOther.remove(job->ticket.ptr());
} else {
Bun__VmHandle__refKeepAlive(vmHandle, -1);
Bun__VmHandle__refKeepAlive(vmHandle, BunLoopKind::Regular, -1);
}
holder.unlockEarly();

// Deferred work runs script (FinalizationRegistry callbacks, wasm
// completions); not once the VM's stop was requested. Like any other
// event-loop callback boundary, an exception a task lets escape is
// reported as uncaught here rather than left on the VM for the next entry.
if (pendingTicket && !pendingTicket->isCancelled() && Bun__VmHandle__scriptAllowed(vmHandle)) {
if (wasPending && !job->ticket->isCancelled() && Bun__VmHandle__scriptAllowed(vmHandle)) {
auto& vm = job->vm();
auto* globalObject = job->ticket->target()->globalObject();
auto scope = DECLARE_TOP_EXCEPTION_SCOPE(vm);
Expand Down Expand Up @@ -148,7 +152,7 @@ extern "C" void Bun__deleteDeferredWorkTask(Bun::JSCDeferredWorkTask* job)
bool wasKeepingAlive = dropPendingTicketLocked(scheduler, job->ticket.ptr());
holder.unlockEarly();
if (wasKeepingAlive)
Bun__VmHandle__refKeepAlive(clientData->vmHandle, -1);
Bun__VmHandle__refKeepAlive(clientData->vmHandle, BunLoopKind::Regular, -1);
}
delete job;
}
Expand Down
6 changes: 4 additions & 2 deletions src/jsc/bindings/JSCTaskScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class JSVMClientData;
}

#include <JavaScriptCore/DeferredWorkTimer.h>
#include "BunLoopKind.h"

namespace Bun {

Expand Down Expand Up @@ -34,8 +35,9 @@ class JSCTaskScheduler {
public:
Lock m_lock;
bool m_isShuttingDown WTF_GUARDED_BY_LOCK(m_lock) { false };
UncheckedKeyHashSet<Ref<JSC::DeferredWorkTimer::Ticket>> m_pendingTicketsKeepingEventLoopAlive;
UncheckedKeyHashSet<Ref<JSC::DeferredWorkTimer::Ticket>> m_pendingTicketsOther;
// Value: the loop that was current when JSC registered the work; its completion is posted there.
UncheckedKeyHashMap<Ref<JSC::DeferredWorkTimer::Ticket>, BunLoopKind> m_pendingTicketsKeepingEventLoopAlive;
UncheckedKeyHashMap<Ref<JSC::DeferredWorkTimer::Ticket>, BunLoopKind> m_pendingTicketsOther;
};

}
6 changes: 3 additions & 3 deletions src/jsc/bindings/ScriptExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ void ScriptExecutionContext::willDestroyActiveDOMObject(ActiveDOMObject& activeD
m_activeDOMObjects.remove(activeDOMObject);
}

bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identifier, Function<void(ScriptExecutionContext&)>&& task)
bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identifier, BunLoopKind loopKind, Function<void(ScriptExecutionContext&)>&& task)
{
// The map lock covers the lookup only. The context may be destroyed the moment the
// lock is released, so nothing of it is used afterwards except a count taken on its
Expand All @@ -194,7 +194,7 @@ bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identif
return false;
retained = Bun__VmHandle__retainRef(context->m_vmHandle);
}
Bun__VmHandle__postAndRelease(retained, new EventLoopTask(WTF::move(task)));
Bun__VmHandle__postAndRelease(retained, new EventLoopTask(WTF::move(task)), loopKind);
return true;
}

Expand Down Expand Up @@ -268,7 +268,7 @@ bool ScriptExecutionContext::ensureOnContextThread(ScriptExecutionContextIdentif
}
if (retained) {
// Off its thread: as postTaskTo(), through the handle, outside the lock.
Bun__VmHandle__postAndRelease(retained, new EventLoopTask(WTF::move(task)));
Bun__VmHandle__postAndRelease(retained, new EventLoopTask(WTF::move(task)), BunLoopKind::Regular);
return true;
}
// On its own thread the context cannot be destroyed under us.
Expand Down
Loading
Loading