mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
* Fix memory leak * Remove an extra copy * Further fixes --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
104 lines
3.1 KiB
C++
104 lines
3.1 KiB
C++
#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_ISO_ALLOCATED(JSCDeferredWorkTask);
|
|
};
|
|
|
|
WTF_MAKE_ISO_ALLOCATED_IMPL(JSCDeferredWorkTask);
|
|
|
|
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);
|
|
}
|
|
|
|
}
|