mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1355746 - Part 2. Polish IdleTaskRunner and reuse it for background parsing. r=smaug
This patch is mainly to make IdleTaskRunner reusable by nsHtml5TreeOpExecutor. The only necessary work to that purpose is to remove the dependency of sShuttingDown, which was a static variable in nsJSEnvironment.cpp. The idea is to have a "ShouldCancel" as a callback for the consumer to return sShuttingDown. In addition to sShuttingDown, we use std::function<bool()> as the runner main callback type. MozReview-Commit-ID: FT2X1unSvPS --HG-- extra : rebase_source : cfd99aba19f014327875683f5ea85d183c8af674 extra : intermediate-source : 99af874c7b1d278057194894d406474b8af07349 extra : source : 792359c898f68241e1373820ea8fd3ba18b09994
This commit is contained in:
parent
e13aeee5fd
commit
a221ac674f
@ -1602,7 +1602,7 @@ nsJSContext::GetMaxCCSliceTimeSinceClear()
|
||||
}
|
||||
|
||||
static bool
|
||||
ICCRunnerFired(TimeStamp aDeadline, void* aData)
|
||||
ICCRunnerFired(TimeStamp aDeadline)
|
||||
{
|
||||
if (sDidShutdown) {
|
||||
return false;
|
||||
@ -1643,8 +1643,8 @@ nsJSContext::BeginCycleCollectionCallback()
|
||||
|
||||
// Create an ICC timer even if ICC is globally disabled, because we could be manually triggering
|
||||
// an incremental collection, and we want to be sure to finish it.
|
||||
sICCRunner = CollectorRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
|
||||
kIdleICCSliceBudget, true);
|
||||
sICCRunner = IdleTaskRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
|
||||
kIdleICCSliceBudget, true, []{ return sShuttingDown; });
|
||||
}
|
||||
|
||||
static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0");
|
||||
@ -1856,11 +1856,9 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
nsJSContext::KillGCTimer();
|
||||
// Now start the actual GC after initial timer has fired.
|
||||
sInterSliceGCRunner = CollectorRunner::Create(InterSliceGCRunnerFired,
|
||||
NS_INTERSLICE_GC_DELAY,
|
||||
sActiveIntersliceGCBudget,
|
||||
false,
|
||||
aClosure);
|
||||
sInterSliceGCRunner = IdleTaskRunner::Create([aClosure](TimeStamp aDeadline) {
|
||||
return InterSliceGCRunnerFired(aDeadline, aClosure);
|
||||
}, NS_INTERSLICE_GC_DELAY, sActiveIntersliceGCBudget, false, []{ return sShuttingDown; });
|
||||
}
|
||||
|
||||
// static
|
||||
@ -1884,7 +1882,7 @@ ShouldTriggerCC(uint32_t aSuspected)
|
||||
}
|
||||
|
||||
static bool
|
||||
CCRunnerFired(TimeStamp aDeadline, void* aData)
|
||||
CCRunnerFired(TimeStamp aDeadline)
|
||||
{
|
||||
if (sDidShutdown) {
|
||||
return false;
|
||||
@ -2036,13 +2034,13 @@ nsJSContext::RunNextCollectorTimer()
|
||||
|
||||
if (sCCRunner) {
|
||||
if (ReadyToTriggerExpensiveCollectorTimer()) {
|
||||
CCRunnerFired(TimeStamp(), nullptr);
|
||||
CCRunnerFired(TimeStamp());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (sICCRunner) {
|
||||
ICCRunnerFired(TimeStamp(), nullptr);
|
||||
ICCRunnerFired(TimeStamp());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2149,8 +2147,9 @@ nsJSContext::MaybePokeCC()
|
||||
nsCycleCollector_dispatchDeferredDeletion();
|
||||
|
||||
sCCRunner =
|
||||
CollectorRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
|
||||
kForgetSkippableSliceDuration, true);
|
||||
IdleTaskRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
|
||||
kForgetSkippableSliceDuration, true,
|
||||
[]{ return sShuttingDown; });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2330,8 +2329,9 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
|
||||
nsJSContext::KillInterSliceGCRunner();
|
||||
if (!sShuttingDown && !aDesc.isComplete_) {
|
||||
sInterSliceGCRunner =
|
||||
CollectorRunner::Create(InterSliceGCRunnerFired, NS_INTERSLICE_GC_DELAY,
|
||||
sActiveIntersliceGCBudget, false);
|
||||
IdleTaskRunner::Create([](TimeStamp aDeadline) {
|
||||
return InterSliceGCRunnerFired(aDeadline, nullptr);
|
||||
}, NS_INTERSLICE_GC_DELAY, sActiveIntersliceGCBudget, false, []{ return sShuttingDown; });
|
||||
}
|
||||
|
||||
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsIViewSourceChannel.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/IdleTaskRunner.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -61,7 +62,7 @@ class nsHtml5ExecutorReflusher : public Runnable
|
||||
};
|
||||
|
||||
static mozilla::LinkedList<nsHtml5TreeOpExecutor>* gBackgroundFlushList = nullptr;
|
||||
static nsITimer* gFlushTimer = nullptr;
|
||||
StaticRefPtr<IdleTaskRunner> gBackgroundFlushRunner;
|
||||
|
||||
nsHtml5TreeOpExecutor::nsHtml5TreeOpExecutor()
|
||||
: nsHtml5DocumentBuilder(false)
|
||||
@ -85,9 +86,9 @@ nsHtml5TreeOpExecutor::~nsHtml5TreeOpExecutor()
|
||||
if (gBackgroundFlushList->isEmpty()) {
|
||||
delete gBackgroundFlushList;
|
||||
gBackgroundFlushList = nullptr;
|
||||
if (gFlushTimer) {
|
||||
gFlushTimer->Cancel();
|
||||
NS_RELEASE(gFlushTimer);
|
||||
if (gBackgroundFlushRunner) {
|
||||
gBackgroundFlushRunner->Cancel();
|
||||
gBackgroundFlushRunner = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -245,9 +246,10 @@ nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason)
|
||||
return aReason;
|
||||
}
|
||||
|
||||
void
|
||||
FlushTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
static bool
|
||||
BackgroundFlushCallback(TimeStamp /*aDeadline*/)
|
||||
{
|
||||
NS_WARNING("Executing BackgroundFlushCallback()....");
|
||||
RefPtr<nsHtml5TreeOpExecutor> ex = gBackgroundFlushList->popFirst();
|
||||
if (ex) {
|
||||
ex->RunFlushLoop();
|
||||
@ -255,9 +257,11 @@ FlushTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
if (gBackgroundFlushList && gBackgroundFlushList->isEmpty()) {
|
||||
delete gBackgroundFlushList;
|
||||
gBackgroundFlushList = nullptr;
|
||||
gFlushTimer->Cancel();
|
||||
NS_RELEASE(gFlushTimer);
|
||||
gBackgroundFlushRunner->Cancel();
|
||||
gBackgroundFlushRunner = nullptr;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -277,16 +281,17 @@ nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync()
|
||||
if (!isInList()) {
|
||||
gBackgroundFlushList->insertBack(this);
|
||||
}
|
||||
if (!gFlushTimer) {
|
||||
nsCOMPtr<nsITimer> t = do_CreateInstance("@mozilla.org/timer;1");
|
||||
t.swap(gFlushTimer);
|
||||
// The timer value 50 should not hopefully slow down background pages too
|
||||
// much, yet lets event loop to process enough between ticks.
|
||||
// See bug 734015.
|
||||
gFlushTimer->InitWithNamedFuncCallback(FlushTimerCallback, nullptr,
|
||||
50, nsITimer::TYPE_REPEATING_SLACK,
|
||||
"FlushTimerCallback");
|
||||
if (gBackgroundFlushRunner) {
|
||||
NS_WARNING("We've already scheduled a task for background list flush.");
|
||||
return;
|
||||
}
|
||||
// Now we set up a repetitive idle scheduler for flushing background list.
|
||||
gBackgroundFlushRunner =
|
||||
IdleTaskRunner::Create(&BackgroundFlushCallback,
|
||||
250, // The hard deadline: 250ms.
|
||||
nsContentSink::sInteractiveTime / 1000, // Required budget.
|
||||
true, // repeating
|
||||
[]{ return false; }); // MaybeContinueProcess
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,25 +10,28 @@
|
||||
namespace mozilla {
|
||||
|
||||
already_AddRefed<IdleTaskRunner>
|
||||
IdleTaskRunner::Create(IdleTaskRunnerCallback aCallback, uint32_t aDelay,
|
||||
int64_t aBudget, bool aRepeating, void* aData)
|
||||
IdleTaskRunner::Create(const CallbackType& aCallback, uint32_t aDelay,
|
||||
int64_t aBudget, bool aRepeating,
|
||||
const MayContinueProcessingCallbackType& aMaybeContinueProcessing)
|
||||
{
|
||||
if (sShuttingDown) {
|
||||
if (aMaybeContinueProcessing && aMaybeContinueProcessing()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<IdleTaskRunner> runner =
|
||||
new IdleTaskRunner(aCallback, aDelay, aBudget, aRepeating, aData);
|
||||
new IdleTaskRunner(aCallback, aDelay, aBudget, aRepeating, aMaybeContinueProcessing);
|
||||
runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
|
||||
return runner.forget();
|
||||
}
|
||||
|
||||
IdleTaskRunner::IdleTaskRunner(IdleTaskRunnerCallback aCallback,
|
||||
IdleTaskRunner::IdleTaskRunner(const CallbackType& aCallback,
|
||||
uint32_t aDelay, int64_t aBudget,
|
||||
bool aRepeating, void* aData)
|
||||
bool aRepeating,
|
||||
const MayContinueProcessingCallbackType& aMaybeContinueProcessing)
|
||||
: mCallback(aCallback), mDelay(aDelay)
|
||||
, mBudget(TimeDuration::FromMilliseconds(aBudget))
|
||||
, mRepeating(aRepeating), mTimerActive(false), mData(aData)
|
||||
, mRepeating(aRepeating), mTimerActive(false)
|
||||
, mMaybeContinueProcessing(aMaybeContinueProcessing)
|
||||
{
|
||||
}
|
||||
|
||||
@ -40,18 +43,25 @@ IdleTaskRunner::Run()
|
||||
}
|
||||
|
||||
// Deadline is null when called from timer.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
bool deadLineWasNull = mDeadline.IsNull();
|
||||
bool didRun = false;
|
||||
if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
|
||||
bool allowIdleDispatch = false;
|
||||
if (deadLineWasNull || ((now + mBudget) < mDeadline)) {
|
||||
CancelTimer();
|
||||
didRun = mCallback(mDeadline, mData);
|
||||
}
|
||||
|
||||
if (mCallback && (mRepeating || !didRun)) {
|
||||
didRun = mCallback(mDeadline);
|
||||
// If we didn't do meaningful work, don't schedule using immediate
|
||||
// idle dispatch, since that could lead to a loop until the idle
|
||||
// period ends.
|
||||
Schedule(didRun);
|
||||
allowIdleDispatch = didRun;
|
||||
} else if (now >= mDeadline) {
|
||||
allowIdleDispatch = true;
|
||||
}
|
||||
|
||||
if (mCallback && (mRepeating || !didRun)) {
|
||||
Schedule(allowIdleDispatch);
|
||||
} else {
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -114,11 +124,12 @@ IdleTaskRunner::Schedule(bool aAllowIdleDispatch)
|
||||
return;
|
||||
}
|
||||
|
||||
if (sShuttingDown) {
|
||||
if (mMaybeContinueProcessing && mMaybeContinueProcessing()) {
|
||||
Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
TimeStamp deadline = mDeadline;
|
||||
mDeadline = TimeStamp();
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
|
||||
@ -145,7 +156,14 @@ IdleTaskRunner::Schedule(bool aAllowIdleDispatch)
|
||||
|
||||
// We weren't allowed to do idle dispatch immediately, do it after a
|
||||
// short timeout.
|
||||
mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, 16,
|
||||
uint32_t lateScheduleDelayMs;
|
||||
if (deadline.IsNull()) {
|
||||
lateScheduleDelayMs = 16;
|
||||
} else {
|
||||
lateScheduleDelayMs =
|
||||
(uint32_t)((deadline - now).ToMilliseconds());
|
||||
}
|
||||
mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, lateScheduleDelayMs,
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
@ -11,16 +11,27 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Return true if some meaningful work was done.
|
||||
typedef bool (*IdleTaskRunnerCallback) (TimeStamp aDeadline, void* aData);
|
||||
|
||||
// Repeating callback runner for CC and GC.
|
||||
// A general purpose repeating callback runner (it can be configured
|
||||
// to a one-time runner, too.) If it is running repeatedly,
|
||||
// one has to either explicitly Cancel() the runner or have
|
||||
// MayContinueProcessing() callback return false to completely remove
|
||||
// the runner.
|
||||
class IdleTaskRunner final : public IdleRunnable
|
||||
{
|
||||
public:
|
||||
// Return true if some meaningful work was done.
|
||||
using CallbackType = std::function<bool(TimeStamp aDeadline)>;
|
||||
|
||||
// A callback for "continue process" decision. Return false to
|
||||
// stop processing. This can be an alternative to Cancel() or
|
||||
// work together in different way.
|
||||
using MayContinueProcessingCallbackType = std::function<bool()>;
|
||||
|
||||
public:
|
||||
static already_AddRefed<IdleTaskRunner>
|
||||
Create(IdleTaskRunnerCallback aCallback, uint32_t aDelay,
|
||||
int64_t aBudget, bool aRepeating, void* aData = nullptr);
|
||||
Create(const CallbackType& aCallback, uint32_t aDelay,
|
||||
int64_t aBudget, bool aRepeating,
|
||||
const MayContinueProcessingCallbackType& aMaybeContinueProcessing);
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
@ -31,22 +42,23 @@ public:
|
||||
void Schedule(bool aAllowIdleDispatch);
|
||||
|
||||
private:
|
||||
explicit IdleTaskRunner(IdleTaskRunnerCallback aCallback,
|
||||
explicit IdleTaskRunner(const CallbackType& aCallback,
|
||||
uint32_t aDelay, int64_t aBudget,
|
||||
bool aRepeating, void* aData);
|
||||
bool aRepeating,
|
||||
const MayContinueProcessingCallbackType& aMaybeContinueProcessing);
|
||||
~IdleTaskRunner();
|
||||
void CancelTimer();
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsITimer> mScheduleTimer;
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
IdleTaskRunnerCallback mCallback;
|
||||
CallbackType mCallback;
|
||||
uint32_t mDelay;
|
||||
TimeStamp mDeadline;
|
||||
TimeDuration mBudget;
|
||||
bool mRepeating;
|
||||
bool mTimerActive;
|
||||
void* mData;
|
||||
MayContinueProcessingCallbackType mMaybeContinueProcessing;
|
||||
};
|
||||
|
||||
} // end of unnamed namespace.
|
||||
|
Loading…
Reference in New Issue
Block a user