xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp (revision 57447d3ddfb0b1c44618e97081906d19a387ff00)
1 //===------------ TaskDispatch.cpp - ORC task dispatch utils --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
10 #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS
11 #include "llvm/ExecutionEngine/Orc/Core.h"
12 
13 namespace llvm {
14 namespace orc {
15 
16 char Task::ID = 0;
17 char GenericNamedTask::ID = 0;
18 const char *GenericNamedTask::DefaultDescription = "Generic Task";
19 
20 void Task::anchor() {}
21 TaskDispatcher::~TaskDispatcher() = default;
22 
23 void InPlaceTaskDispatcher::dispatch(std::unique_ptr<Task> T) { T->run(); }
24 
25 void InPlaceTaskDispatcher::shutdown() {}
26 
27 #if LLVM_ENABLE_THREADS
28 void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
29   bool IsMaterializationTask = isa<MaterializationTask>(*T);
30 
31   {
32     std::lock_guard<std::mutex> Lock(DispatchMutex);
33 
34     // Reject new tasks if they're dispatched after a call to shutdown.
35     if (Shutdown)
36       return;
37 
38     if (IsMaterializationTask) {
39 
40       // If this is a materialization task and there are too many running
41       // already then queue this one up and return early.
42       if (MaxMaterializationThreads &&
43           NumMaterializationThreads == *MaxMaterializationThreads) {
44         MaterializationTaskQueue.push_back(std::move(T));
45         return;
46       }
47 
48       // Otherwise record that we have a materialization task running.
49       ++NumMaterializationThreads;
50     }
51 
52     ++Outstanding;
53   }
54 
55   std::thread([this, T = std::move(T), IsMaterializationTask]() mutable {
56     while (true) {
57 
58       // Run the task.
59       T->run();
60 
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.
69       std::lock_guard<std::mutex> Lock(DispatchMutex);
70       if (!MaterializationTaskQueue.empty()) {
71         // If there are any materialization tasks running then steal that work.
72         T = std::move(MaterializationTaskQueue.front());
73         MaterializationTaskQueue.pop_front();
74         if (!IsMaterializationTask) {
75           ++NumMaterializationThreads;
76           IsMaterializationTask = true;
77         }
78       } else {
79         if (IsMaterializationTask)
80           --NumMaterializationThreads;
81         --Outstanding;
82         if (Outstanding == 0)
83           OutstandingCV.notify_all();
84         return;
85       }
86     }
87   }).detach();
88 }
89 
90 void DynamicThreadPoolTaskDispatcher::shutdown() {
91   std::unique_lock<std::mutex> Lock(DispatchMutex);
92   Shutdown = true;
93   OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
94 }
95 #endif
96 
97 } // namespace orc
98 } // namespace llvm
99