diff options
Diffstat (limited to 'src/bun.js/bindings/JSCTaskScheduler.cpp')
-rw-r--r-- | src/bun.js/bindings/JSCTaskScheduler.cpp | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/bun.js/bindings/JSCTaskScheduler.cpp b/src/bun.js/bindings/JSCTaskScheduler.cpp new file mode 100644 index 000000000..436be4c0a --- /dev/null +++ b/src/bun.js/bindings/JSCTaskScheduler.cpp @@ -0,0 +1,101 @@ +#include "config.h" +#include <JavaScriptCore/VM.h> +#include "JSCTaskScheduler.h" +#include "BunClientData.h" + +using Ticket = JSC::DeferredWorkTimer::Ticket; +using Task = JSC::DeferredWorkTimer::Task; +using TicketData = JSC::DeferredWorkTimer::TicketData; + +namespace Bun { +using namespace JSC; + +extern "C" void Bun__queueJSCDeferredWorkTaskConcurrently(void* bunVM, void* task); +extern "C" void Bun__eventLoop__incrementRefConcurrently(void* bunVM, int delta); + +class JSCDeferredWorkTask { +public: + JSCDeferredWorkTask(Ticket ticket, Task&& task) + : ticket(ticket) + , task(WTFMove(task)) + { + } + + Ticket ticket; + Task task; + + WTF_MAKE_FAST_ALLOCATED; +}; + +static JSC::VM& getVM(Ticket ticket) +{ + return ticket->scriptExecutionOwner.get()->vm(); +} + +void JSCTaskScheduler::onAddPendingWork(std::unique_ptr<TicketData> ticket, JSC::DeferredWorkTimer::WorkKind kind) +{ + JSC::VM& vm = getVM(ticket.get()); + auto clientData = WebCore::clientData(vm); + auto& scheduler = clientData->deferredWorkTimer; + LockHolder holder { scheduler.m_lock }; + if (kind != DeferredWorkTimer::WorkKind::Other) { + + Bun__eventLoop__incrementRefConcurrently(clientData->bunVM, 1); + scheduler.m_pendingTicketsKeepingEventLoopAlive.add(WTFMove(ticket)); + } else { + scheduler.m_pendingTicketsOther.add(WTFMove(ticket)); + } +} +void JSCTaskScheduler::onScheduleWorkSoon(Ticket ticket, Task&& task) +{ + auto* job = new JSCDeferredWorkTask(ticket, WTFMove(task)); + Bun__queueJSCDeferredWorkTaskConcurrently(WebCore::clientData(getVM(ticket))->bunVM, job); +} + +void JSCTaskScheduler::onCancelPendingWork(Ticket ticket) +{ + auto& scheduler = WebCore::clientData(getVM(ticket))->deferredWorkTimer; + + LockHolder holder { scheduler.m_lock }; + bool isKeepingEventLoopAlive = scheduler.m_pendingTicketsKeepingEventLoopAlive.removeIf([ticket](const auto& pendingTicket) { + return pendingTicket.get() == ticket; + }); + + if (isKeepingEventLoopAlive) { + holder.unlockEarly(); + JSC::VM& vm = getVM(ticket); + Bun__eventLoop__incrementRefConcurrently(WebCore::clientData(vm)->bunVM, -1); + } else { + scheduler.m_pendingTicketsOther.removeIf([ticket](const auto& pendingTicket) { + return pendingTicket.get() == ticket; + }); + } +} + +static void runPendingWork(void* bunVM, Bun::JSCTaskScheduler& scheduler, JSCDeferredWorkTask* job) +{ + LockHolder holder { scheduler.m_lock }; + auto pendingTicket = scheduler.m_pendingTicketsKeepingEventLoopAlive.take(job->ticket); + if (!pendingTicket) { + pendingTicket = scheduler.m_pendingTicketsOther.take(job->ticket); + } else { + Bun__eventLoop__incrementRefConcurrently(bunVM, -1); + } + holder.unlockEarly(); + + if (pendingTicket && !pendingTicket->isCancelled()) { + job->task(job->ticket); + } + + delete job; +} + +extern "C" void Bun__runDeferredWork(Bun::JSCDeferredWorkTask* job) +{ + auto& vm = getVM(job->ticket); + auto clientData = WebCore::clientData(vm); + + runPendingWork(clientData->bunVM, clientData->deferredWorkTimer, job); +} + +} |