Index: include/llvm/Support/Parallel.h =================================================================== --- include/llvm/Support/Parallel.h +++ include/llvm/Support/Parallel.h @@ -73,8 +73,12 @@ class TaskGroup { Latch L; + bool Parallel; public: + TaskGroup(); + ~TaskGroup(); + void spawn(std::function f); void sync() const { L.sync(); } Index: lib/Support/Parallel.cpp =================================================================== --- lib/Support/Parallel.cpp +++ lib/Support/Parallel.cpp @@ -17,7 +17,9 @@ #include #include -using namespace llvm; +namespace llvm { +namespace parallel { +namespace detail { namespace { @@ -118,11 +120,28 @@ #endif } -void parallel::detail::TaskGroup::spawn(std::function F) { - L.inc(); - Executor::getDefaultExecutor()->add([&, F] { +static std::atomic 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 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