1 //===------------ TaskDispatch.cpp - ORC task dispatch utils --------------===//
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
7 //===----------------------------------------------------------------------===//
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"
17 char GenericNamedTask::ID
= 0;
18 char IdleTask::ID
= 0;
20 const char *GenericNamedTask::DefaultDescription
= "Generic Task";
22 void Task::anchor() {}
23 void IdleTask::anchor() {}
25 TaskDispatcher::~TaskDispatcher() = default;
27 void InPlaceTaskDispatcher::dispatch(std::unique_ptr
<Task
> T
) { T
->run(); }
29 void InPlaceTaskDispatcher::shutdown() {}
31 #if LLVM_ENABLE_THREADS
32 void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr
<Task
> T
) {
34 enum { Normal
, Materialization
, Idle
} TaskKind
;
36 if (isa
<MaterializationTask
>(*T
))
37 TaskKind
= Materialization
;
38 else if (isa
<IdleTask
>(*T
))
44 std::lock_guard
<std::mutex
> Lock(DispatchMutex
);
46 // Reject new tasks if they're dispatched after a call to shutdown.
50 if (TaskKind
== Materialization
) {
52 // If this is a materialization task and there are too many running
53 // already then queue this one up and return early.
54 if (!canRunMaterializationTaskNow())
55 return MaterializationTaskQueue
.push_back(std::move(T
));
57 // Otherwise record that we have a materialization task running.
58 ++NumMaterializationThreads
;
59 } else if (TaskKind
== Idle
) {
60 if (!canRunIdleTaskNow())
61 return IdleTaskQueue
.push_back(std::move(T
));
67 std::thread([this, T
= std::move(T
), TaskKind
]() mutable {
73 // Reset the task to free any resources. We need this to happen *before*
74 // we notify anyone (via Outstanding) that this thread is done to ensure
75 // that we don't proceed with JIT shutdown while still holding resources.
76 // (E.g. this was causing "Dangling SymbolStringPtr" assertions).
79 // Check the work queue state and either proceed with the next task or
81 std::lock_guard
<std::mutex
> Lock(DispatchMutex
);
83 if (TaskKind
== Materialization
)
84 --NumMaterializationThreads
;
87 if (!MaterializationTaskQueue
.empty() && canRunMaterializationTaskNow()) {
88 // If there are any materialization tasks running then steal that work.
89 T
= std::move(MaterializationTaskQueue
.front());
90 MaterializationTaskQueue
.pop_front();
91 TaskKind
= Materialization
;
92 ++NumMaterializationThreads
;
94 } else if (!IdleTaskQueue
.empty() && canRunIdleTaskNow()) {
95 T
= std::move(IdleTaskQueue
.front());
96 IdleTaskQueue
.pop_front();
100 if (Outstanding
== 0)
101 OutstandingCV
.notify_all();
108 void DynamicThreadPoolTaskDispatcher::shutdown() {
109 std::unique_lock
<std::mutex
> Lock(DispatchMutex
);
111 OutstandingCV
.wait(Lock
, [this]() { return Outstanding
== 0; });
114 bool DynamicThreadPoolTaskDispatcher::canRunMaterializationTaskNow() {
115 return !MaxMaterializationThreads
||
116 (NumMaterializationThreads
< *MaxMaterializationThreads
);
119 bool DynamicThreadPoolTaskDispatcher::canRunIdleTaskNow() {
120 return !MaxMaterializationThreads
||
121 (Outstanding
< *MaxMaterializationThreads
);