зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1650629: Correctly wait when requested and report whether work was done by ProcessNextEvent when using TaskController. r=mstange
Differential Revision: https://phabricator.services.mozilla.com/D83004
This commit is contained in:
Родитель
56aa86bead
Коммит
43311c24a3
|
@ -11,6 +11,7 @@
|
|||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include "mozilla/AbstractEventQueue.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/SchedulerGroup.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
@ -80,6 +81,9 @@ bool TaskController::InitializeInternal() {
|
|||
mMTProcessingRunnable = NS_NewRunnableFunction(
|
||||
"TaskController::ExecutePendingMTTasks()",
|
||||
[]() { TaskController::Get()->ProcessPendingMTTask(); });
|
||||
mMTBlockingProcessingRunnable = NS_NewRunnableFunction(
|
||||
"TaskController::ExecutePendingMTTasks()",
|
||||
[]() { TaskController::Get()->ProcessPendingMTTask(true); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -134,6 +138,7 @@ void TaskController::AddTask(already_AddRefed<Task>&& aTask) {
|
|||
void TaskController::WaitForTaskOrMessage() {
|
||||
MutexAutoLock lock(mGraphMutex);
|
||||
while (!mMayHaveMainThreadTask) {
|
||||
AUTO_PROFILER_LABEL("TaskController::WaitForTaskOrMessage", IDLE);
|
||||
mMainThreadCV.Wait();
|
||||
}
|
||||
}
|
||||
|
@ -144,12 +149,40 @@ void TaskController::ExecuteNextTaskOnlyMainThread() {
|
|||
ExecuteNextTaskOnlyMainThreadInternal(lock);
|
||||
}
|
||||
|
||||
void TaskController::ProcessPendingMTTask() {
|
||||
void TaskController::ProcessPendingMTTask(bool aMayWait) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(mGraphMutex);
|
||||
mHasScheduledMTRunnable = false;
|
||||
|
||||
ExecuteNextTaskOnlyMainThreadInternal(lock);
|
||||
for (;;) {
|
||||
// We only ever process one event here. However we may sometimes
|
||||
// not actually process a real event because of suspended tasks.
|
||||
// This loop allows us to wait until we've processed something
|
||||
// in that scenario.
|
||||
|
||||
mMTTaskRunnableProcessedTask = ExecuteNextTaskOnlyMainThreadInternal(lock);
|
||||
|
||||
if (mMTTaskRunnableProcessedTask || !aMayWait) {
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsIThread> mainIThread;
|
||||
NS_GetMainThread(getter_AddRefs(mainIThread));
|
||||
nsThread* mainThread = static_cast<nsThread*>(mainIThread.get());
|
||||
mainThread->SetRunningEventDelay(TimeDuration(), TimeStamp());
|
||||
|
||||
BackgroundHangMonitor().NotifyWait();
|
||||
|
||||
{
|
||||
// ProcessNextEvent will also have attempted to wait, however we may have
|
||||
// given it a Runnable when all the tasks in our task graph were suspended
|
||||
// but we weren't able to cheaply determine that.
|
||||
AUTO_PROFILER_LABEL("TaskController::ProcessPendingMTTask", IDLE);
|
||||
mMainThreadCV.Wait();
|
||||
}
|
||||
|
||||
// See bug 1651842
|
||||
mainThread->SetRunningEventDelay(TimeDuration(), TimeStamp::Now());
|
||||
BackgroundHangMonitor().NotifyActivity();
|
||||
}
|
||||
|
||||
if (mMayHaveMainThreadTask) {
|
||||
EnsureMainThreadTasksScheduled();
|
||||
|
@ -247,7 +280,7 @@ nsIRunnable* TaskController::GetRunnableForMTTask(bool aReallyWait) {
|
|||
mMainThreadCV.Wait();
|
||||
}
|
||||
|
||||
return mMTProcessingRunnable;
|
||||
return aReallyWait ? mMTBlockingProcessingRunnable : mMTProcessingRunnable;
|
||||
}
|
||||
|
||||
bool TaskController::HasMainThreadPendingTasks() {
|
||||
|
@ -330,11 +363,12 @@ bool TaskController::HasMainThreadPendingTasks() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void TaskController::ExecuteNextTaskOnlyMainThreadInternal(
|
||||
bool TaskController::ExecuteNextTaskOnlyMainThreadInternal(
|
||||
const MutexAutoLock& aProofOfLock) {
|
||||
// Block to make it easier to jump to our cleanup.
|
||||
bool taskRan = false;
|
||||
do {
|
||||
bool taskRan = DoExecuteNextTaskOnlyMainThreadInternal(aProofOfLock);
|
||||
taskRan = DoExecuteNextTaskOnlyMainThreadInternal(aProofOfLock);
|
||||
if (taskRan) {
|
||||
break;
|
||||
}
|
||||
|
@ -357,7 +391,7 @@ void TaskController::ExecuteNextTaskOnlyMainThreadInternal(
|
|||
|
||||
// When we unlocked, someone may have queued a new task on us. So try to
|
||||
// see whether we can run things again.
|
||||
Unused << DoExecuteNextTaskOnlyMainThreadInternal(aProofOfLock);
|
||||
taskRan = DoExecuteNextTaskOnlyMainThreadInternal(aProofOfLock);
|
||||
} while (false);
|
||||
|
||||
if (mIdleTaskManager) {
|
||||
|
@ -375,6 +409,8 @@ void TaskController::ExecuteNextTaskOnlyMainThreadInternal(
|
|||
mIdleTaskManager->State().RanOutOfTasks(unlock);
|
||||
}
|
||||
}
|
||||
|
||||
return taskRan;
|
||||
}
|
||||
|
||||
bool TaskController::DoExecuteNextTaskOnlyMainThreadInternal(
|
||||
|
|
|
@ -283,7 +283,7 @@ class TaskController {
|
|||
void ExecuteNextTaskOnlyMainThread();
|
||||
|
||||
// Process all pending main thread tasks.
|
||||
void ProcessPendingMTTask();
|
||||
void ProcessPendingMTTask(bool aMayWait = false);
|
||||
|
||||
// This allows reprioritization of a task already in the task graph.
|
||||
// This may be called on any thread.
|
||||
|
@ -296,10 +296,14 @@ class TaskController {
|
|||
|
||||
bool HasMainThreadPendingTasks();
|
||||
|
||||
// Let users know whether the last main thread task runnable did work.
|
||||
bool MTTaskRunnableProcessedTask() { return mMTTaskRunnableProcessedTask; }
|
||||
|
||||
private:
|
||||
// This gets the next (highest priority) task that is only allowed to execute
|
||||
// on the main thread, if any, and executes it.
|
||||
void ExecuteNextTaskOnlyMainThreadInternal(const MutexAutoLock& aProofOfLock);
|
||||
// Returns true if it succeeded.
|
||||
bool ExecuteNextTaskOnlyMainThreadInternal(const MutexAutoLock& aProofOfLock);
|
||||
|
||||
// The guts of ExecuteNextTaskOnlyMainThreadInternal, which get idle handling
|
||||
// wrapped around them. Returns whether a task actually ran.
|
||||
|
@ -338,10 +342,13 @@ class TaskController {
|
|||
// This ensures we keep running the main thread if we processed a task there.
|
||||
bool mMayHaveMainThreadTask = true;
|
||||
|
||||
// This stores whether the last main thread task runnable did work.
|
||||
bool mMTTaskRunnableProcessedTask = false;
|
||||
|
||||
// Whether we have scheduled a runnable on the main thread event loop.
|
||||
// This is used for nsIRunnable compatibility.
|
||||
bool mHasScheduledMTRunnable = false;
|
||||
RefPtr<nsIRunnable> mMTProcessingRunnable;
|
||||
RefPtr<nsIRunnable> mMTBlockingProcessingRunnable;
|
||||
|
||||
// XXX - Thread observer to notify when a new event has been dispatched
|
||||
nsIThreadObserver* mObserver = nullptr;
|
||||
|
|
|
@ -1233,7 +1233,9 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) {
|
|||
|
||||
event->Run();
|
||||
|
||||
if (!usingTaskController) {
|
||||
if (usingTaskController) {
|
||||
*aResult = TaskController::Get()->MTTaskRunnableProcessedTask();
|
||||
} else {
|
||||
mEvents->DidRunEvent();
|
||||
mPerformanceCounterState.RunnableDidRun(std::move(snapshot.ref()));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче