Implement a callback system for interrupting timed slice budgets for bug #1351790

Trying this again.
This commit is contained in:
win7-7 2026-01-22 21:57:23 +02:00 committed by wuggy
commit 51277f511c
2 changed files with 64 additions and 29 deletions

View file

@ -34,12 +34,18 @@ struct JS_PUBLIC_API(WorkBudget)
*/
class JS_PUBLIC_API(SliceBudget)
{
typedef bool (*InterruptRequestCallback)(void*);
static const int64_t unlimitedDeadline = INT64_MAX;
static const intptr_t unlimitedStartCounter = INTPTR_MAX;
bool checkOverBudget();
SliceBudget();
SliceBudget()
: timeBudget(UnlimitedTimeBudget), workBudget(UnlimitedWorkBudget), callbackBudget(nullptr)
{
reset();
}
public:
// Memory of the originally requested budget. If isUnlimited, neither of
@ -56,22 +62,51 @@ class JS_PUBLIC_API(SliceBudget)
static const int64_t UnlimitedTimeBudget = -1;
static const int64_t UnlimitedWorkBudget = -1;
SliceBudget* callbackBudget;
// If callbackBudget is nullptr, the following fields are uninitialized and unused.
InterruptRequestCallback interruptRequested;
void* callbackData;
/* Use to create an unlimited budget. */
static SliceBudget unlimited() { return SliceBudget(); }
explicit SliceBudget(TimeBudget time,
SliceBudget& callbackBudget_, InterruptRequestCallback callback,
void* callbackData)
: timeBudget(time), workBudget(UnlimitedWorkBudget)
, callbackBudget(&callbackBudget_), interruptRequested(callback)
, callbackData(callbackData)
{
reset();
}
/* Instantiate as SliceBudget(TimeBudget(n)). */
explicit SliceBudget(TimeBudget time);
explicit SliceBudget(TimeBudget time)
: timeBudget(time), workBudget(UnlimitedWorkBudget), callbackBudget(nullptr)
{
reset();
}
/* Instantiate as SliceBudget(WorkBudget(n)). */
explicit SliceBudget(WorkBudget work);
explicit SliceBudget(WorkBudget work)
: timeBudget(UnlimitedTimeBudget), workBudget(work), callbackBudget(nullptr)
{
reset();
}
void reset();
void makeUnlimited() {
deadline = unlimitedDeadline;
counter = unlimitedStartCounter;
if (callbackBudget)
callbackBudget->makeUnlimited();
}
void step(intptr_t amt = 1) {
counter -= amt;
if (callbackBudget)
callbackBudget->step(amt);
}
bool isOverBudget() {

View file

@ -2938,33 +2938,23 @@ ArenaLists::queueForegroundThingsForSweep(FreeOp* fop)
gcScriptArenasToUpdate = arenaListsToSweep[AllocKind::SCRIPT];
}
SliceBudget::SliceBudget()
: timeBudget(UnlimitedTimeBudget), workBudget(UnlimitedWorkBudget)
void
SliceBudget::reset()
{
makeUnlimited();
}
MOZ_ASSERT_IF(timeBudget.budget < 0, !callbackBudget);
if (timeBudget.budget >= 0) {
SliceBudget::SliceBudget(TimeBudget time)
: timeBudget(time), workBudget(UnlimitedWorkBudget)
{
if (time.budget < 0) {
makeUnlimited();
} else {
// Note: TimeBudget(0) is equivalent to WorkBudget(CounterReset).
deadline = PRMJ_Now() + time.budget * PRMJ_USEC_PER_MSEC;
deadline = PRMJ_Now() + timeBudget.budget * PRMJ_USEC_PER_MSEC;
counter = CounterReset;
}
}
SliceBudget::SliceBudget(WorkBudget work)
: timeBudget(UnlimitedTimeBudget), workBudget(work)
{
if (work.budget < 0) {
makeUnlimited();
} else {
deadline = 0;
counter = work.budget;
}
if (callbackBudget)
callbackBudget->reset();
} else if (workBudget.budget >= 0) {
deadline = 0;
counter = workBudget.budget;
} else {
makeUnlimited();
}
}
int
@ -2981,10 +2971,20 @@ SliceBudget::describe(char* buffer, size_t maxlen) const
bool
SliceBudget::checkOverBudget()
{
bool over = PRMJ_Now() >= deadline;
if (!over)
int64_t now = PRMJ_Now();
bool over = now >= deadline;
if (over)
return true;
if (!callbackBudget || !callbackBudget->isOverBudget()) {
counter = CounterReset;
return over;
return false;
}
callbackBudget->reset();
if (interruptRequested(callbackData)) {
deadline = now;
return true;
}
return false;
}
void