You've already forked linux-packaging-mono
acceptance-tests
data
docs
external
Newtonsoft.Json
api-doc-tools
api-snapshot
aspnetwebstack
bdwgc
binary-reference-assemblies
bockbuild
boringssl
cecil
cecil-legacy
corefx
corert
helix-binaries
ikdasm
ikvm
illinker-test-assets
linker
llvm-project
clang
clang-tools-extra
compiler-rt
eng
libcxx
libcxxabi
libunwind
lld
lldb
llvm
bindings
cmake
docs
examples
include
lib
Analysis
AsmParser
BinaryFormat
Bitcode
CodeGen
DebugInfo
Demangle
ExecutionEngine
FuzzMutate
Fuzzer
IR
IRReader
LTO
LineEditor
Linker
MC
Object
ObjectYAML
Option
Passes
ProfileData
Support
Unix
Windows
AMDGPUMetadata.cpp
APFloat.cpp.REMOVED.git-id
APInt.cpp
APSInt.cpp
ARMAttributeParser.cpp
ARMBuildAttrs.cpp
ARMWinEH.cpp
Allocator.cpp
Atomic.cpp
BinaryStreamError.cpp
BinaryStreamReader.cpp
BinaryStreamRef.cpp
BinaryStreamWriter.cpp
BlockFrequency.cpp
BranchProbability.cpp
CMakeLists.txt
COM.cpp
COPYRIGHT.regex
CachePruning.cpp
Chrono.cpp
CodeGenCoverage.cpp
CommandLine.cpp
Compression.cpp
ConvertUTF.cpp
ConvertUTFWrapper.cpp
CrashRecoveryContext.cpp
DAGDeltaAlgorithm.cpp
DataExtractor.cpp
Debug.cpp
DebugCounter.cpp
DeltaAlgorithm.cpp
DynamicLibrary.cpp
Errno.cpp
Error.cpp
ErrorHandling.cpp
FileOutputBuffer.cpp
FileUtilities.cpp
FoldingSet.cpp
FormatVariadic.cpp
FormattedStream.cpp
GlobPattern.cpp
GraphWriter.cpp
Hashing.cpp
Host.cpp
IntEqClasses.cpp
IntervalMap.cpp
JamCRC.cpp
KnownBits.cpp
LEB128.cpp
LLVMBuild.txt
LineIterator.cpp
Locale.cpp
LockFileManager.cpp
LowLevelType.cpp
MD5.cpp
ManagedStatic.cpp
MathExtras.cpp
Memory.cpp
MemoryBuffer.cpp
Mutex.cpp
NativeFormatting.cpp
Options.cpp
Parallel.cpp
Path.cpp
PluginLoader.cpp
PrettyStackTrace.cpp
Process.cpp
Program.cpp
README.txt.system
RWMutex.cpp
RandomNumberGenerator.cpp
Regex.cpp
SHA1.cpp
ScaledNumber.cpp
ScopedPrinter.cpp
Signals.cpp
SmallPtrSet.cpp
SmallVector.cpp
SourceMgr.cpp
SpecialCaseList.cpp
Statistic.cpp
StringExtras.cpp
StringMap.cpp
StringPool.cpp
StringRef.cpp
StringSaver.cpp
SystemUtils.cpp
TarWriter.cpp
TargetParser.cpp
TargetRegistry.cpp
ThreadLocal.cpp
ThreadPool.cpp
Threading.cpp
Timer.cpp
ToolOutputFile.cpp
TrigramIndex.cpp
Triple.cpp
Twine.cpp
Unicode.cpp
Valgrind.cpp
Watchdog.cpp
YAMLParser.cpp
YAMLTraits.cpp
circular_raw_ostream.cpp
raw_os_ostream.cpp
raw_ostream.cpp
regcomp.c
regengine.inc
regerror.c
regex2.h
regex_impl.h
regexec.c
regfree.c
regstrlcpy.c
regutils.h
xxhash.cpp
TableGen
Target
Testing
ToolDrivers
Transforms
WindowsManifest
XRay
CMakeLists.txt
LLVMBuild.txt
projects
resources
runtimes
scripts
test
tools
unittests
utils
.arcconfig
.clang-format
.clang-tidy
.gitattributes
.gitignore
CMakeLists.txt
CODE_OWNERS.TXT
CREDITS.TXT
LICENSE.TXT
LLVMBuild.txt
README.txt
RELEASE_TESTERS.TXT
configure
llvm.spec.in
version.txt.in
nuget
openmp
polly
Directory.Build.props
Directory.Build.targets
NuGet.config
azure-pipelines.yml
build.cmd
build.sh
dir.common.props
global.json
llvm.proj
mxe-Win64.cmake.in
nuget-buildtasks
nunit-lite
roslyn-binaries
rx
xunit-binaries
how-to-bump-roslyn-binaries.md
ikvm-native
llvm
m4
man
mcs
mono
msvc
netcore
po
runtime
samples
scripts
support
tools
COPYING.LIB
LICENSE
Makefile.am
Makefile.in
NEWS
README.md
acinclude.m4
aclocal.m4
autogen.sh
code_of_conduct.md
compile
config.guess
config.h.in
config.rpath
config.sub
configure.REMOVED.git-id
configure.ac.REMOVED.git-id
depcomp
install-sh
ltmain.sh.REMOVED.git-id
missing
mkinstalldirs
mono-uninstalled.pc.in
test-driver
winconfig.h
151 lines
4.6 KiB
C++
151 lines
4.6 KiB
C++
![]() |
//==-- llvm/Support/ThreadPool.cpp - A ThreadPool implementation -*- C++ -*-==//
|
||
|
//
|
||
|
// The LLVM Compiler Infrastructure
|
||
|
//
|
||
|
// This file is distributed under the University of Illinois Open Source
|
||
|
// License. See LICENSE.TXT for details.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// This file implements a crude C++11 based thread pool.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "llvm/Config/llvm-config.h"
|
||
|
#include "llvm/Support/Threading.h"
|
||
|
#include "llvm/Support/raw_ostream.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
#if LLVM_ENABLE_THREADS
|
||
|
|
||
|
#include "llvm/Support/ThreadPool.h"
|
||
|
|
||
|
// Default to hardware_concurrency
|
||
|
ThreadPool::ThreadPool() : ThreadPool(hardware_concurrency()) {}
|
||
|
|
||
|
ThreadPool::ThreadPool(unsigned ThreadCount)
|
||
|
: ActiveThreads(0), EnableFlag(true) {
|
||
|
// Create ThreadCount threads that will loop forever, wait on QueueCondition
|
||
|
// for tasks to be queued or the Pool to be destroyed.
|
||
|
Threads.reserve(ThreadCount);
|
||
|
for (unsigned ThreadID = 0; ThreadID < ThreadCount; ++ThreadID) {
|
||
|
Threads.emplace_back([&] {
|
||
|
while (true) {
|
||
|
PackagedTaskTy Task;
|
||
|
{
|
||
|
std::unique_lock<std::mutex> LockGuard(QueueLock);
|
||
|
// Wait for tasks to be pushed in the queue
|
||
|
QueueCondition.wait(LockGuard,
|
||
|
[&] { return !EnableFlag || !Tasks.empty(); });
|
||
|
// Exit condition
|
||
|
if (!EnableFlag && Tasks.empty())
|
||
|
return;
|
||
|
// Yeah, we have a task, grab it and release the lock on the queue
|
||
|
|
||
|
// We first need to signal that we are active before popping the queue
|
||
|
// in order for wait() to properly detect that even if the queue is
|
||
|
// empty, there is still a task in flight.
|
||
|
{
|
||
|
std::unique_lock<std::mutex> LockGuard(CompletionLock);
|
||
|
++ActiveThreads;
|
||
|
}
|
||
|
Task = std::move(Tasks.front());
|
||
|
Tasks.pop();
|
||
|
}
|
||
|
// Run the task we just grabbed
|
||
|
Task();
|
||
|
|
||
|
{
|
||
|
// Adjust `ActiveThreads`, in case someone waits on ThreadPool::wait()
|
||
|
std::unique_lock<std::mutex> LockGuard(CompletionLock);
|
||
|
--ActiveThreads;
|
||
|
}
|
||
|
|
||
|
// Notify task completion, in case someone waits on ThreadPool::wait()
|
||
|
CompletionCondition.notify_all();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ThreadPool::wait() {
|
||
|
// Wait for all threads to complete and the queue to be empty
|
||
|
std::unique_lock<std::mutex> LockGuard(CompletionLock);
|
||
|
// The order of the checks for ActiveThreads and Tasks.empty() matters because
|
||
|
// any active threads might be modifying the Tasks queue, and this would be a
|
||
|
// race.
|
||
|
CompletionCondition.wait(LockGuard,
|
||
|
[&] { return !ActiveThreads && Tasks.empty(); });
|
||
|
}
|
||
|
|
||
|
std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) {
|
||
|
/// Wrap the Task in a packaged_task to return a future object.
|
||
|
PackagedTaskTy PackagedTask(std::move(Task));
|
||
|
auto Future = PackagedTask.get_future();
|
||
|
{
|
||
|
// Lock the queue and push the new task
|
||
|
std::unique_lock<std::mutex> LockGuard(QueueLock);
|
||
|
|
||
|
// Don't allow enqueueing after disabling the pool
|
||
|
assert(EnableFlag && "Queuing a thread during ThreadPool destruction");
|
||
|
|
||
|
Tasks.push(std::move(PackagedTask));
|
||
|
}
|
||
|
QueueCondition.notify_one();
|
||
|
return Future.share();
|
||
|
}
|
||
|
|
||
|
// The destructor joins all threads, waiting for completion.
|
||
|
ThreadPool::~ThreadPool() {
|
||
|
{
|
||
|
std::unique_lock<std::mutex> LockGuard(QueueLock);
|
||
|
EnableFlag = false;
|
||
|
}
|
||
|
QueueCondition.notify_all();
|
||
|
for (auto &Worker : Threads)
|
||
|
Worker.join();
|
||
|
}
|
||
|
|
||
|
#else // LLVM_ENABLE_THREADS Disabled
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
ThreadPool::ThreadPool() : ThreadPool(0) {}
|
||
|
|
||
|
// No threads are launched, issue a warning if ThreadCount is not 0
|
||
|
ThreadPool::ThreadPool(unsigned ThreadCount)
|
||
|
: ActiveThreads(0) {
|
||
|
if (ThreadCount) {
|
||
|
errs() << "Warning: request a ThreadPool with " << ThreadCount
|
||
|
<< " threads, but LLVM_ENABLE_THREADS has been turned off\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ThreadPool::wait() {
|
||
|
// Sequential implementation running the tasks
|
||
|
while (!Tasks.empty()) {
|
||
|
auto Task = std::move(Tasks.front());
|
||
|
Tasks.pop();
|
||
|
Task();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) {
|
||
|
// Get a Future with launch::deferred execution using std::async
|
||
|
auto Future = std::async(std::launch::deferred, std::move(Task)).share();
|
||
|
// Wrap the future so that both ThreadPool::wait() can operate and the
|
||
|
// returned future can be sync'ed on.
|
||
|
PackagedTaskTy PackagedTask([Future]() { Future.get(); });
|
||
|
Tasks.push(std::move(PackagedTask));
|
||
|
return Future;
|
||
|
}
|
||
|
|
||
|
ThreadPool::~ThreadPool() {
|
||
|
wait();
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#endif
|