From 11afa09ea3f56c0e20eb195ae1520a88602ceaca Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 22 Oct 2021 11:36:31 -0400 Subject: SL-16220: Add LL::ThreadPool class and a "General" instance. ThreadPool bundles a WorkQueue with the specified number of worker threads to service it. Each ThreadPool has a name that can be used to locate its WorkQueue. Each worker thread calls WorkQueue::runUntilClose(). ThreadPool listens on the "LLApp" LLEventPump for shutdown notification. On receiving that, it closes its WorkQueue and then join()s each of its worker threads for orderly shutdown. Add a settings.xml entry "ThreadPoolSizes", the first LLSD-valued settings entry to expect a map: pool name->size. The expectation is that usually code instantiating a particular ThreadPool will have a default size in mind, but it should check "ThreadPoolSizes" for a user override. Make idle_startup()'s STATE_SEED_CAP_GRANTED state instantiate a "General" ThreadPool. This is function-static for lazy initialization. Eliminate LLMainLoopRepeater, which is completely unreferenced. Any potential future use cases are better addressed by posting to the main loop's WorkQueue. Eliminate llappviewer.cpp's private LLDeferredTaskList class, which implemented LLAppViewer::addOnIdleCallback(). Make addOnIdleCallback() post work to the main loop's WorkQueue instead. --- indra/llcommon/threadpool.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 indra/llcommon/threadpool.cpp (limited to 'indra/llcommon/threadpool.cpp') diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp new file mode 100644 index 0000000000..aa7d4179a2 --- /dev/null +++ b/indra/llcommon/threadpool.cpp @@ -0,0 +1,75 @@ +/** + * @file threadpool.cpp + * @author Nat Goodspeed + * @date 2021-10-21 + * @brief Implementation for threadpool. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "threadpool.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llerror.h" +#include "llevents.h" +#include "stringize.h" + +LL::ThreadPool::ThreadPool(const std::string& name, size_t threads): + mQueue(name), + mName("ThreadPool:" + name) +{ + for (size_t i = 0; i < threads; ++i) + { + std::string tname{ STRINGIZE(mName << ':' << (i+i) << '/' << threads) }; + mThreads.emplace_back(tname, [this, tname](){ run(tname); }); + } + // Listen on "LLApp", and when the app is shutting down, close the queue + // and join the workers. + LLEventPumps::instance().obtain("LLApp").listen( + mName, + [this](const LLSD& stat) + { + std::string status(stat["status"]); + if (status != "running") + { + // viewer is starting shutdown -- proclaim the end is nigh! + LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL; + close(); + } + return false; + }); +} + +LL::ThreadPool::~ThreadPool() +{ + close(); +} + +void LL::ThreadPool::close() +{ + if (! mQueue.isClosed()) + { + LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL; + mQueue.close(); + for (auto& pair: mThreads) + { + LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; + pair.second.join(); + } + LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; + } +} + +void LL::ThreadPool::run(const std::string& name) +{ + LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL; + mQueue.runUntilClose(); + LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL; +} -- cgit v1.2.3 From d2763897f22e3d7789f97fe68000662ecd4a3548 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 22 Oct 2021 21:51:44 -0400 Subject: SL-16220: Fix thread name expression. --- indra/llcommon/threadpool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llcommon/threadpool.cpp') diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index aa7d4179a2..1899f9a20a 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -27,7 +27,7 @@ LL::ThreadPool::ThreadPool(const std::string& name, size_t threads): { for (size_t i = 0; i < threads; ++i) { - std::string tname{ STRINGIZE(mName << ':' << (i+i) << '/' << threads) }; + std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) }; mThreads.emplace_back(tname, [this, tname](){ run(tname); }); } // Listen on "LLApp", and when the app is shutting down, close the queue -- cgit v1.2.3 From 834e7ca088b5f417235327cd290b42459c733594 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 4 Nov 2021 17:18:57 -0400 Subject: SL-16202: Use large WorkQueue size limits for mainloop and General. Give ThreadPool and WorkQueue the ability to override default ThreadSafeSchedule capacity. Instantiate "mainloop" WorkQueue and "General" ThreadPool with very large capacity because we never want to have to block trying to push to either. --- indra/llcommon/threadpool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llcommon/threadpool.cpp') diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index 1899f9a20a..e4fa0eccf3 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -21,8 +21,8 @@ #include "llevents.h" #include "stringize.h" -LL::ThreadPool::ThreadPool(const std::string& name, size_t threads): - mQueue(name), +LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity): + mQueue(name, capacity), mName("ThreadPool:" + name) { for (size_t i = 0; i < threads; ++i) -- cgit v1.2.3 From ff5496239bffadaca111b1e4380a01447f85843a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 5 Nov 2021 12:33:31 -0400 Subject: SL-16202: Use WorkQueue::postTo() for texture create/post handshake. That is, when LLViewerFetchedTexture::scheduleCreateTexture() wants to call createTexture() on the LLImageGLThread, but postCreateTexture() on the main thread, use the "mainloop" WorkQueue to set up the handshake. Give ThreadPool a public virtual run() method so a subclass can override with desired behavior. This necessitates a virtual destructor. Add accessors for embedded WorkQueue (for post calls), ThreadPool name and width (in threads). Allow LLSimpleton::createInstance() to forward arguments to the subject constructor. Make LLImageGLThread an LLSimpleton - that abstraction didn't yet exist at the time LLImageGLThread was coded. Also derive from ThreadPool rather than LLThread. Make it a single-thread "pool" with a very large queue capacity. --- indra/llcommon/threadpool.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/llcommon/threadpool.cpp') diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index e4fa0eccf3..cf25cc838e 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -70,6 +70,11 @@ void LL::ThreadPool::close() void LL::ThreadPool::run(const std::string& name) { LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL; - mQueue.runUntilClose(); + run(); LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL; } + +void LL::ThreadPool::run() +{ + mQueue.runUntilClose(); +} -- cgit v1.2.3 From 9b0d8c7e629597fd8e6dfb91a6b8f625b34ab274 Mon Sep 17 00:00:00 2001 From: Runitai Linden Date: Mon, 22 Nov 2021 18:42:56 -0600 Subject: SL-16094 More profile hooks for threading code, remove redundant wglCreateContextAttribs call --- indra/llcommon/threadpool.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/llcommon/threadpool.cpp') diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index cf25cc838e..06e0dc5bfc 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -28,7 +28,11 @@ LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capac for (size_t i = 0; i < threads; ++i) { std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) }; - mThreads.emplace_back(tname, [this, tname](){ run(tname); }); + mThreads.emplace_back(tname, [this, tname]() + { + LL_PROFILER_SET_THREAD_NAME(tname.c_str()); + run(tname); + }); } // Listen on "LLApp", and when the app is shutting down, close the queue // and join the workers. -- cgit v1.2.3 From 2b96f89c2a374d72c0a8bc28a7b06ad4db7eae6e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 23 Nov 2021 20:39:32 -0500 Subject: SL-16400: Add ThreadPool::start() method, and call it. It's sometimes important to finish other initialization before launching the threads in the ThreadPool, so make that an explicit step. In particular, we were launching the LLImageGL texture thread before initializing the GL context, resulting in all gray textures. --- indra/llcommon/threadpool.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'indra/llcommon/threadpool.cpp') diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index 06e0dc5bfc..ba914035e2 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -23,11 +23,15 @@ LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity): mQueue(name, capacity), - mName("ThreadPool:" + name) + mName("ThreadPool:" + name), + mThreadCount(threads) +{} + +void LL::ThreadPool::start() { - for (size_t i = 0; i < threads; ++i) + for (size_t i = 0; i < mThreadCount; ++i) { - std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) }; + std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) }; mThreads.emplace_back(tname, [this, tname]() { LL_PROFILER_SET_THREAD_NAME(tname.c_str()); -- cgit v1.2.3