Skip to content

Commit 8312876

Browse files
committed
[ORC] Fix Task cleanup during DynamicThreadPoolTaskDispatcher::shutdown.
Threads created by DynamicThreadPoolTaskDispatcher::dispatch had been holding a unique_ptr to the most recent Task, meaning that the Task would be destroyed when the thread object was destroyed, but this would happen *after* the thread signaled the Dispatcher that it was finished. This could cause DynamicThreadPoolTaskDispatcher::shutdown to return (and consequently ExecutionSession to be destroyed) before all Tasks were destroyed, with Task destructors accessing ExecutionSession and related objects after they were freed. The fix is to reset the Task pointer immediately after it is run to trigger cleanup, *then* (if there are no other tasks to run) signal the Dispatcher that the thread is finished. This patch also updates DynamicThreadPoolTaskDispatcher::dispatch to reject any new Tasks dispatched after DynamicThreadPoolTaskDispatcher::shutdown is called.
1 parent 3cb9648 commit 8312876

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

llvm/include/llvm/ExecutionEngine/Orc/TaskDispatch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class DynamicThreadPoolTaskDispatcher : public TaskDispatcher {
122122
void shutdown() override;
123123
private:
124124
std::mutex DispatchMutex;
125-
bool Running = true;
125+
bool Shutdown = false;
126126
size_t Outstanding = 0;
127127
std::condition_variable OutstandingCV;
128128

llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
3131
{
3232
std::lock_guard<std::mutex> Lock(DispatchMutex);
3333

34+
// Reject new tasks if they're dispatched after a call to shutdown.
35+
if (Shutdown)
36+
return;
37+
3438
if (IsMaterializationTask) {
3539

3640
// If this is a materialization task and there are too many running
@@ -54,6 +58,14 @@ void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
5458
// Run the task.
5559
T->run();
5660

61+
// Reset the task to free any resources. We need this to happen *before*
62+
// we notify anyone (via Outstanding) that this thread is done to ensure
63+
// that we don't proceed with JIT shutdown while still holding resources.
64+
// (E.g. this was causing "Dangling SymbolStringPtr" assertions).
65+
T.reset();
66+
67+
// Check the work queue state and either proceed with the next task or
68+
// end this thread.
5769
std::lock_guard<std::mutex> Lock(DispatchMutex);
5870
if (!MaterializationTaskQueue.empty()) {
5971
// If there are any materialization tasks running then steal that work.
@@ -64,7 +76,6 @@ void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
6476
IsMaterializationTask = true;
6577
}
6678
} else {
67-
// Otherwise decrement work counters.
6879
if (IsMaterializationTask)
6980
--NumMaterializationThreads;
7081
--Outstanding;
@@ -78,7 +89,7 @@ void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
7889

7990
void DynamicThreadPoolTaskDispatcher::shutdown() {
8091
std::unique_lock<std::mutex> Lock(DispatchMutex);
81-
Running = false;
92+
Shutdown = true;
8293
OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
8394
}
8495
#endif

0 commit comments

Comments
 (0)