mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 16:17:29 +09:00
Issue #3050 - Backport 1379814: Prevent HelperThreads master-task deadlock
This commit is contained in:
parent
01553c6695
commit
5bab33a357
2 changed files with 66 additions and 35 deletions
|
|
@ -860,19 +860,30 @@ GlobalHelperThreadState::waitForAllThreads()
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool
|
bool
|
||||||
GlobalHelperThreadState::checkTaskThreadLimit(size_t maxThreads) const
|
GlobalHelperThreadState::checkTaskThreadLimit(size_t maxThreads, bool isMaster) const
|
||||||
{
|
{
|
||||||
if (maxThreads >= threadCount)
|
if (maxThreads >= threadCount)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
size_t idle = 0;
|
||||||
for (auto& thread : *threads) {
|
for (auto& thread : *threads) {
|
||||||
if (thread.currentTask.isSome() && thread.currentTask->is<T>())
|
if (thread.currentTask.isSome()) {
|
||||||
count++;
|
if (thread.currentTask->is<T>())
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
idle++;
|
||||||
|
}
|
||||||
if (count >= maxThreads)
|
if (count >= maxThreads)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At least the current thread is idle.
|
||||||
|
MOZ_ASSERT(idle > 0);
|
||||||
|
|
||||||
|
if (isMaster && idle <= 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1091,7 +1102,8 @@ GlobalHelperThreadState::pendingIonCompileHasSufficientPriority(
|
||||||
bool
|
bool
|
||||||
GlobalHelperThreadState::canStartParseTask(const AutoLockHelperThreadState& lock)
|
GlobalHelperThreadState::canStartParseTask(const AutoLockHelperThreadState& lock)
|
||||||
{
|
{
|
||||||
return !parseWorklist(lock).empty() && checkTaskThreadLimit<ParseTask*>(maxParseThreads());
|
return !parseWorklist(lock).empty() &&
|
||||||
|
checkTaskThreadLimit<ParseTask*>(maxParseThreads(), /* isMaster = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -1892,49 +1904,68 @@ HelperThread::threadLoop()
|
||||||
while (true) {
|
while (true) {
|
||||||
MOZ_ASSERT(idle());
|
MOZ_ASSERT(idle());
|
||||||
|
|
||||||
// Block until a task is available. Save the value of whether we are
|
js::oom::ThreadType task;
|
||||||
// going to do an Ion compile, in case the value returned by the method
|
|
||||||
// changes.
|
|
||||||
bool ionCompile = false;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (terminate)
|
if (terminate)
|
||||||
return;
|
return;
|
||||||
if ((ionCompile = HelperThreadState().pendingIonCompileHasSufficientPriority(lock)) ||
|
|
||||||
HelperThreadState().canStartWasmCompile(lock) ||
|
// Select the task type to run. Task priority is determined
|
||||||
HelperThreadState().canStartPromiseTask(lock) ||
|
// exclusively here.
|
||||||
HelperThreadState().canStartParseTask(lock) ||
|
//
|
||||||
HelperThreadState().canStartCompressionTask(lock) ||
|
// The selectors may depend on the HelperThreadState not changing
|
||||||
HelperThreadState().canStartGCHelperTask(lock) ||
|
// between task selection and task execution, in particular, on new
|
||||||
HelperThreadState().canStartGCParallelTask(lock))
|
// tasks not being added (because of the lifo structure of the work
|
||||||
{
|
// lists). Unlocking the HelperThreadState between task selection
|
||||||
|
// and execution is not well-defined.
|
||||||
|
if (HelperThreadState().canStartGCParallelTask(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_GCPARALLEL;
|
||||||
|
else if (HelperThreadState().canStartGCHelperTask(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_GCHELPER;
|
||||||
|
else if (HelperThreadState().pendingIonCompileHasSufficientPriority(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_ION;
|
||||||
|
else if (HelperThreadState().canStartWasmCompile(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_ASMJS;
|
||||||
|
else if (HelperThreadState().canStartPromiseTask(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_PROMISE_TASK;
|
||||||
|
else if (HelperThreadState().canStartParseTask(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_PARSE;
|
||||||
|
else if (HelperThreadState().canStartCompressionTask(lock))
|
||||||
|
task = js::oom::THREAD_TYPE_COMPRESS;
|
||||||
|
else
|
||||||
|
task = js::oom::THREAD_TYPE_NONE;
|
||||||
|
|
||||||
|
if (task != js::oom::THREAD_TYPE_NONE)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
|
HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ionCompile) {
|
js::oom::SetThreadType(task);
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_ION);
|
switch (task) {
|
||||||
handleIonWorkload(lock);
|
case js::oom::THREAD_TYPE_GCPARALLEL:
|
||||||
} else if (HelperThreadState().canStartWasmCompile(lock)) {
|
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_ASMJS);
|
|
||||||
handleWasmWorkload(lock);
|
|
||||||
} else if (HelperThreadState().canStartPromiseTask(lock)) {
|
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_PROMISE_TASK);
|
|
||||||
handlePromiseTaskWorkload(lock);
|
|
||||||
} else if (HelperThreadState().canStartParseTask(lock)) {
|
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE);
|
|
||||||
handleParseWorkload(lock, stackLimit);
|
|
||||||
} else if (HelperThreadState().canStartCompressionTask(lock)) {
|
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS);
|
|
||||||
handleCompressionWorkload(lock);
|
|
||||||
} else if (HelperThreadState().canStartGCHelperTask(lock)) {
|
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER);
|
|
||||||
handleGCHelperWorkload(lock);
|
|
||||||
} else if (HelperThreadState().canStartGCParallelTask(lock)) {
|
|
||||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL);
|
|
||||||
handleGCParallelWorkload(lock);
|
handleGCParallelWorkload(lock);
|
||||||
} else {
|
break;
|
||||||
|
case js::oom::THREAD_TYPE_GCHELPER:
|
||||||
|
handleGCHelperWorkload(lock);
|
||||||
|
break;
|
||||||
|
case js::oom::THREAD_TYPE_ION:
|
||||||
|
handleIonWorkload(lock);
|
||||||
|
break;
|
||||||
|
case js::oom::THREAD_TYPE_ASMJS:
|
||||||
|
handleWasmWorkload(lock);
|
||||||
|
break;
|
||||||
|
case js::oom::THREAD_TYPE_PROMISE_TASK:
|
||||||
|
handlePromiseTaskWorkload(lock);
|
||||||
|
break;
|
||||||
|
case js::oom::THREAD_TYPE_PARSE:
|
||||||
|
handleParseWorkload(lock, stackLimit);
|
||||||
|
break;
|
||||||
|
case js::oom::THREAD_TYPE_COMPRESS:
|
||||||
|
handleCompressionWorkload(lock);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
MOZ_CRASH("No task to perform");
|
MOZ_CRASH("No task to perform");
|
||||||
}
|
}
|
||||||
|
js::oom::SetThreadType(js::oom::THREAD_TYPE_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ class GlobalHelperThreadState
|
||||||
void waitForAllThreads();
|
void waitForAllThreads();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool checkTaskThreadLimit(size_t maxThreads) const;
|
bool checkTaskThreadLimit(size_t maxThreads, bool isMaster = false) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue