128 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/TaskDispatch.h"10#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS11#include "llvm/ExecutionEngine/Orc/Core.h"12 13namespace llvm {14namespace orc {15 16char Task::ID = 0;17char GenericNamedTask::ID = 0;18char IdleTask::ID = 0;19 20const char *GenericNamedTask::DefaultDescription = "Generic Task";21 22void Task::anchor() {}23void IdleTask::anchor() {}24 25TaskDispatcher::~TaskDispatcher() = default;26 27void InPlaceTaskDispatcher::dispatch(std::unique_ptr<Task> T) { T->run(); }28 29void InPlaceTaskDispatcher::shutdown() {}30 31#if LLVM_ENABLE_THREADS32void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {33 34 enum { Normal, Materialization, Idle } TaskKind;35 36 if (isa<MaterializationTask>(*T))37 TaskKind = Materialization;38 else if (isa<IdleTask>(*T))39 TaskKind = Idle;40 else41 TaskKind = Normal;42 43 {44 std::lock_guard<std::mutex> Lock(DispatchMutex);45 46 // Reject new tasks if they're dispatched after a call to shutdown.47 if (Shutdown)48 return;49 50 if (TaskKind == Materialization) {51 52 // If this is a materialization task and there are too many running53 // already then queue this one up and return early.54 if (!canRunMaterializationTaskNow())55 return MaterializationTaskQueue.push_back(std::move(T));56 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));62 }63 64 ++Outstanding;65 }66 67 std::thread([this, T = std::move(T), TaskKind]() mutable {68 while (true) {69 70 // Run the task.71 T->run();72 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 ensure75 // that we don't proceed with JIT shutdown while still holding resources.76 // (E.g. this was causing "Dangling SymbolStringPtr" assertions).77 T.reset();78 79 // Check the work queue state and either proceed with the next task or80 // end this thread.81 std::lock_guard<std::mutex> Lock(DispatchMutex);82 83 if (TaskKind == Materialization)84 --NumMaterializationThreads;85 --Outstanding;86 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;93 ++Outstanding;94 } else if (!IdleTaskQueue.empty() && canRunIdleTaskNow()) {95 T = std::move(IdleTaskQueue.front());96 IdleTaskQueue.pop_front();97 TaskKind = Idle;98 ++Outstanding;99 } else {100 if (Outstanding == 0)101 OutstandingCV.notify_all();102 return;103 }104 }105 }).detach();106}107 108void DynamicThreadPoolTaskDispatcher::shutdown() {109 std::unique_lock<std::mutex> Lock(DispatchMutex);110 Shutdown = true;111 OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });112}113 114bool DynamicThreadPoolTaskDispatcher::canRunMaterializationTaskNow() {115 return !MaxMaterializationThreads ||116 (NumMaterializationThreads < *MaxMaterializationThreads);117}118 119bool DynamicThreadPoolTaskDispatcher::canRunIdleTaskNow() {120 return !MaxMaterializationThreads ||121 (Outstanding < *MaxMaterializationThreads);122}123 124#endif125 126} // namespace orc127} // namespace llvm128