mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Parallel: only allow the first TaskGroup to run tasks parallelly
Summary: Concurrent (e.g. nested) llvm::parallel::for_each() may lead to dead locks. See PR35788 (fixed by rLLD322041) and PR41508 (fixed by D60757). When parallel_for_each() is about to return, in ~Latch() called by ~TaskGroup(), a thread (in the default executor) may block in Latch::sync() waiting for Count to become zero. If all threads in the default executor are blocked, it is a dead lock. To fix this, force serial execution if the current TaskGroup is not the first one. For a nested llvm::parallel::for_each(), this parallelizes the outermost loop and serializes inner loops. Differential Revision: https://reviews.llvm.org/D61115 llvm-svn: 359182
This commit is contained in:
parent
2b25116202
commit
2e7ead2539
@ -73,8 +73,12 @@ public:
|
||||
|
||||
class TaskGroup {
|
||||
Latch L;
|
||||
bool Parallel;
|
||||
|
||||
public:
|
||||
TaskGroup();
|
||||
~TaskGroup();
|
||||
|
||||
void spawn(std::function<void()> f);
|
||||
|
||||
void sync() const { L.sync(); }
|
||||
|
@ -17,7 +17,9 @@
|
||||
#include <stack>
|
||||
#include <thread>
|
||||
|
||||
using namespace llvm;
|
||||
namespace llvm {
|
||||
namespace parallel {
|
||||
namespace detail {
|
||||
|
||||
namespace {
|
||||
|
||||
@ -118,11 +120,28 @@ Executor *Executor::getDefaultExecutor() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
|
||||
L.inc();
|
||||
Executor::getDefaultExecutor()->add([&, F] {
|
||||
static std::atomic<int> TaskGroupInstances;
|
||||
|
||||
// Latch::sync() called by the dtor may cause one thread to block. If is a dead
|
||||
// lock if all threads in the default executor are blocked. To prevent the dead
|
||||
// lock, only allow the first TaskGroup to run tasks parallelly. In the scenario
|
||||
// of nested parallel_for_each(), only the outermost one runs parallelly.
|
||||
TaskGroup::TaskGroup() : Parallel(TaskGroupInstances++ == 0) {}
|
||||
TaskGroup::~TaskGroup() { --TaskGroupInstances; }
|
||||
|
||||
void TaskGroup::spawn(std::function<void()> F) {
|
||||
if (Parallel) {
|
||||
L.inc();
|
||||
Executor::getDefaultExecutor()->add([&, F] {
|
||||
F();
|
||||
L.dec();
|
||||
});
|
||||
} else {
|
||||
F();
|
||||
L.dec();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace parallel
|
||||
} // namespace llvm
|
||||
#endif // LLVM_ENABLE_THREADS
|
||||
|
Loading…
x
Reference in New Issue
Block a user