xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp (revision 2d10b7b750f97b42055d5b9b08a88c18ff811cd2)
1f3411616SLang Hames //===------------ TaskDispatch.cpp - ORC task dispatch utils --------------===//
2f3411616SLang Hames //
3f3411616SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f3411616SLang Hames // See https://llvm.org/LICENSE.txt for license information.
5f3411616SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f3411616SLang Hames //
7f3411616SLang Hames //===----------------------------------------------------------------------===//
8f3411616SLang Hames 
9f3411616SLang Hames #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
1089e6a288SDaniil Fukalov #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS
117da63426SLang Hames #include "llvm/ExecutionEngine/Orc/Core.h"
12f3411616SLang Hames 
13f3411616SLang Hames namespace llvm {
14f3411616SLang Hames namespace orc {
15f3411616SLang Hames 
16f3411616SLang Hames char Task::ID = 0;
17f3411616SLang Hames char GenericNamedTask::ID = 0;
18*2d10b7b7SLang Hames char IdleTask::ID = 0;
19*2d10b7b7SLang Hames 
20f3411616SLang Hames const char *GenericNamedTask::DefaultDescription = "Generic Task";
21f3411616SLang Hames 
22f3411616SLang Hames void Task::anchor() {}
23*2d10b7b7SLang Hames void IdleTask::anchor() {}
24*2d10b7b7SLang Hames 
253a3cb929SKazu Hirata TaskDispatcher::~TaskDispatcher() = default;
26f3411616SLang Hames 
27f3411616SLang Hames void InPlaceTaskDispatcher::dispatch(std::unique_ptr<Task> T) { T->run(); }
28f3411616SLang Hames 
29f3411616SLang Hames void InPlaceTaskDispatcher::shutdown() {}
30f3411616SLang Hames 
31f3411616SLang Hames #if LLVM_ENABLE_THREADS
32f3411616SLang Hames void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
33*2d10b7b7SLang Hames 
34*2d10b7b7SLang Hames   enum { Normal, Materialization, Idle } TaskKind;
35*2d10b7b7SLang Hames 
36*2d10b7b7SLang Hames   if (isa<MaterializationTask>(*T))
37*2d10b7b7SLang Hames     TaskKind = Materialization;
38*2d10b7b7SLang Hames   else if (isa<IdleTask>(*T))
39*2d10b7b7SLang Hames     TaskKind = Idle;
40*2d10b7b7SLang Hames   else
41*2d10b7b7SLang Hames     TaskKind = Normal;
427da63426SLang Hames 
43f3411616SLang Hames   {
44f3411616SLang Hames     std::lock_guard<std::mutex> Lock(DispatchMutex);
457da63426SLang Hames 
4683128762SLang Hames     // Reject new tasks if they're dispatched after a call to shutdown.
4783128762SLang Hames     if (Shutdown)
4883128762SLang Hames       return;
4983128762SLang Hames 
50*2d10b7b7SLang Hames     if (TaskKind == Materialization) {
517da63426SLang Hames 
527da63426SLang Hames       // If this is a materialization task and there are too many running
537da63426SLang Hames       // already then queue this one up and return early.
54*2d10b7b7SLang Hames       if (!canRunMaterializationTaskNow())
55*2d10b7b7SLang Hames         return MaterializationTaskQueue.push_back(std::move(T));
567da63426SLang Hames 
577da63426SLang Hames       // Otherwise record that we have a materialization task running.
587da63426SLang Hames       ++NumMaterializationThreads;
59*2d10b7b7SLang Hames     } else if (TaskKind == Idle) {
60*2d10b7b7SLang Hames       if (!canRunIdleTaskNow())
61*2d10b7b7SLang Hames         return IdleTaskQueue.push_back(std::move(T));
627da63426SLang Hames     }
637da63426SLang Hames 
64f3411616SLang Hames     ++Outstanding;
65f3411616SLang Hames   }
66f3411616SLang Hames 
67*2d10b7b7SLang Hames   std::thread([this, T = std::move(T), TaskKind]() mutable {
687da63426SLang Hames     while (true) {
697da63426SLang Hames 
707da63426SLang Hames       // Run the task.
71f3411616SLang Hames       T->run();
727da63426SLang Hames 
7383128762SLang Hames       // Reset the task to free any resources. We need this to happen *before*
7483128762SLang Hames       // we notify anyone (via Outstanding) that this thread is done to ensure
7583128762SLang Hames       // that we don't proceed with JIT shutdown while still holding resources.
7683128762SLang Hames       // (E.g. this was causing "Dangling SymbolStringPtr" assertions).
7783128762SLang Hames       T.reset();
7883128762SLang Hames 
7983128762SLang Hames       // Check the work queue state and either proceed with the next task or
8083128762SLang Hames       // end this thread.
81f3411616SLang Hames       std::lock_guard<std::mutex> Lock(DispatchMutex);
82*2d10b7b7SLang Hames 
83*2d10b7b7SLang Hames       if (TaskKind == Materialization)
84*2d10b7b7SLang Hames         --NumMaterializationThreads;
85*2d10b7b7SLang Hames       --Outstanding;
86*2d10b7b7SLang Hames 
87*2d10b7b7SLang Hames       if (!MaterializationTaskQueue.empty() && canRunMaterializationTaskNow()) {
887da63426SLang Hames         // If there are any materialization tasks running then steal that work.
897da63426SLang Hames         T = std::move(MaterializationTaskQueue.front());
907da63426SLang Hames         MaterializationTaskQueue.pop_front();
91*2d10b7b7SLang Hames         TaskKind = Materialization;
927da63426SLang Hames         ++NumMaterializationThreads;
93*2d10b7b7SLang Hames         ++Outstanding;
94*2d10b7b7SLang Hames       } else if (!IdleTaskQueue.empty() && canRunIdleTaskNow()) {
95*2d10b7b7SLang Hames         T = std::move(IdleTaskQueue.front());
96*2d10b7b7SLang Hames         IdleTaskQueue.pop_front();
97*2d10b7b7SLang Hames         TaskKind = Idle;
98*2d10b7b7SLang Hames         ++Outstanding;
997da63426SLang Hames       } else {
1002b3aff8fSLang Hames         if (Outstanding == 0)
101f3411616SLang Hames           OutstandingCV.notify_all();
1027da63426SLang Hames         return;
1037da63426SLang Hames       }
1047da63426SLang Hames     }
105f3411616SLang Hames   }).detach();
106f3411616SLang Hames }
107f3411616SLang Hames 
108f3411616SLang Hames void DynamicThreadPoolTaskDispatcher::shutdown() {
109f3411616SLang Hames   std::unique_lock<std::mutex> Lock(DispatchMutex);
11083128762SLang Hames   Shutdown = true;
111f3411616SLang Hames   OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
112f3411616SLang Hames }
113*2d10b7b7SLang Hames 
114*2d10b7b7SLang Hames bool DynamicThreadPoolTaskDispatcher::canRunMaterializationTaskNow() {
115*2d10b7b7SLang Hames   return !MaxMaterializationThreads ||
116*2d10b7b7SLang Hames          (NumMaterializationThreads < *MaxMaterializationThreads);
117*2d10b7b7SLang Hames }
118*2d10b7b7SLang Hames 
119*2d10b7b7SLang Hames bool DynamicThreadPoolTaskDispatcher::canRunIdleTaskNow() {
120*2d10b7b7SLang Hames   return !MaxMaterializationThreads ||
121*2d10b7b7SLang Hames          (Outstanding < *MaxMaterializationThreads);
122*2d10b7b7SLang Hames }
123*2d10b7b7SLang Hames 
124f3411616SLang Hames #endif
125f3411616SLang Hames 
126f3411616SLang Hames } // namespace orc
127f3411616SLang Hames } // namespace llvm
128