diff options
| author | Nat Linden <nat@lindenlab.com> | 2022-06-13 19:50:49 +0000 | 
|---|---|---|
| committer | Nat Linden <nat@lindenlab.com> | 2022-06-13 19:50:49 +0000 | 
| commit | c9a48a1cdd23a592eb25454d5e2d6c316ec93445 (patch) | |
| tree | 614d3ae0efdcbec1211d638e602cdb2d78aa8057 /indra/llcommon | |
| parent | da069765b1974e60df5ebf9e973c7fd00c52e329 (diff) | |
| parent | 3b043d90b60eca17dfcc014b21c4c8fc5b432384 (diff) | |
Merged in sl-17483 (pull request #1014)
SL-17483: Make LLImageDecodeThread a facade for LL::ThreadPool.
Approved-by: Dave Parks
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llcommon/commoncontrol.cpp | 106 | ||||
| -rw-r--r-- | indra/llcommon/commoncontrol.h | 75 | ||||
| -rw-r--r-- | indra/llcommon/threadpool.cpp | 60 | ||||
| -rw-r--r-- | indra/llcommon/threadpool.h | 34 | 
5 files changed, 274 insertions, 3 deletions
| diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index ca8b5e946f..4dbf1282c4 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -29,6 +29,7 @@ include_directories(  #     ${LLCOMMON_LIBRARIES})  set(llcommon_SOURCE_FILES +    commoncontrol.cpp      indra_constants.cpp      llallocator.cpp      llallocator_heap_profile.cpp @@ -129,6 +130,7 @@ set(llcommon_HEADER_FILES      CMakeLists.txt      chrono.h +    commoncontrol.h      ctype_workaround.h      fix_macros.h      indra_constants.h diff --git a/indra/llcommon/commoncontrol.cpp b/indra/llcommon/commoncontrol.cpp new file mode 100644 index 0000000000..81e66baf8c --- /dev/null +++ b/indra/llcommon/commoncontrol.cpp @@ -0,0 +1,106 @@ +/** + * @file   commoncontrol.cpp + * @author Nat Goodspeed + * @date   2022-06-08 + * @brief  Implementation for commoncontrol. + *  + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Copyright (c) 2022, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "commoncontrol.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llevents.h" +#include "llsdutil.h" + +LLSD LL::CommonControl::access(const LLSD& params) +{ +    // We can't actually introduce a link-time dependency on llxml, or on any +    // global LLControlGroup (*koff* gSavedSettings *koff*) but we can issue a +    // runtime query. If we're running as part of a viewer with +    // LLViewerControlListener, we can use that to interact with any +    // instantiated LLControGroup. +    LLSD response; +    { +        LLEventStream reply("reply"); +        LLTempBoundListener connection = reply.listen("listener", +                     [&response] (const LLSD& event) +                     { +                         response = event; +                         return false; +                     }); +        LLSD rparams{ params }; +        rparams["reply"] = reply.getName(); +        LLEventPumps::instance().obtain("LLViewerControl").post(rparams); +    } +    // LLViewerControlListener responds immediately. If it's listening at all, +    // it will already have set response. +    if (! response.isDefined()) +    { +        LLTHROW(NoListener("No LLViewerControl listener instantiated")); +    } +    LLSD error{ response["error"] }; +    if (error.isDefined()) +    { +        LLTHROW(ParamError(error)); +    } +    response.erase("error"); +    response.erase("reqid"); +    return response; +} + +/// set control group.key to defined default value +LLSD LL::CommonControl::set_default(const std::string& group, const std::string& key) +{ +    return access(llsd::map("op", "set", +                            "group", group, "key", key))["value"]; +} + +/// set control group.key to specified value +LLSD LL::CommonControl::set(const std::string& group, const std::string& key, const LLSD& value) +{ +    return access(llsd::map("op", "set", +                            "group", group, "key", key, "value", value))["value"]; +} + +/// toggle boolean control group.key +LLSD LL::CommonControl::toggle(const std::string& group, const std::string& key) +{ +    return access(llsd::map("op", "toggle", +                            "group", group, "key", key))["value"]; +} + +/// get the definition for control group.key, (! isDefined()) if bad +/// ["name"], ["type"], ["value"], ["comment"] +LLSD LL::CommonControl::get_def(const std::string& group, const std::string& key) +{ +    return access(llsd::map("op", "get", +                            "group", group, "key", key)); +} + +/// get the value of control group.key +LLSD LL::CommonControl::get(const std::string& group, const std::string& key) +{ +    return access(llsd::map("op", "get", +                            "group", group, "key", key))["value"]; +} + +/// get defined groups +std::vector<std::string> LL::CommonControl::get_groups() +{ +    auto groups{ access(llsd::map("op", "groups"))["groups"] }; +    return { groups.beginArray(), groups.endArray() }; +} + +/// get definitions for all variables in group +LLSD LL::CommonControl::get_vars(const std::string& group) +{ +    return access(llsd::map("op", "vars", "group", group))["vars"]; +} diff --git a/indra/llcommon/commoncontrol.h b/indra/llcommon/commoncontrol.h new file mode 100644 index 0000000000..07d4a45ac5 --- /dev/null +++ b/indra/llcommon/commoncontrol.h @@ -0,0 +1,75 @@ +/** + * @file   commoncontrol.h + * @author Nat Goodspeed + * @date   2022-06-08 + * @brief  Access LLViewerControl LLEventAPI, if process has one. + *  + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Copyright (c) 2022, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_COMMONCONTROL_H) +#define LL_COMMONCONTROL_H + +#include <vector> +#include "llexception.h" +#include "llsd.h" + +namespace LL +{ +    class CommonControl +    { +    public: +        struct Error: public LLException +        { +            Error(const std::string& what): LLException(what) {} +        }; + +        /// Exception thrown if there's no LLViewerControl LLEventAPI +        struct NoListener: public Error +        { +            NoListener(const std::string& what): Error(what) {} +        }; + +        struct ParamError: public Error +        { +            ParamError(const std::string& what): Error(what) {} +        }; + +        /// set control group.key to defined default value +        static +        LLSD set_default(const std::string& group, const std::string& key); + +        /// set control group.key to specified value +        static +        LLSD set(const std::string& group, const std::string& key, const LLSD& value); + +        /// toggle boolean control group.key +        static +        LLSD toggle(const std::string& group, const std::string& key); + +        /// get the definition for control group.key, (! isDefined()) if bad +        /// ["name"], ["type"], ["value"], ["comment"] +        static +        LLSD get_def(const std::string& group, const std::string& key); + +        /// get the value of control group.key +        static +        LLSD get(const std::string& group, const std::string& key); + +        /// get defined groups +        static +        std::vector<std::string> get_groups(); + +        /// get definitions for all variables in group +        static +        LLSD get_vars(const std::string& group); + +    private: +        static +        LLSD access(const LLSD& params); +    }; +} // namespace LL + +#endif /* ! defined(LL_COMMONCONTROL_H) */ diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index ba914035e2..f49dd40a8b 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -17,14 +17,17 @@  // std headers  // external library headers  // other Linden headers +#include "commoncontrol.h"  #include "llerror.h"  #include "llevents.h" +#include "llsd.h"  #include "stringize.h"  LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity): +    super(name),      mQueue(name, capacity),      mName("ThreadPool:" + name), -    mThreadCount(threads) +    mThreadCount(getConfiguredWidth(name, threads))  {}  void LL::ThreadPool::start() @@ -86,3 +89,58 @@ void LL::ThreadPool::run()  {      mQueue.runUntilClose();  } + +//static +size_t LL::ThreadPool::getConfiguredWidth(const std::string& name, size_t dft) +{ +    LLSD poolSizes; +    try +    { +        poolSizes = LL::CommonControl::get("Global", "ThreadPoolSizes"); +        // "ThreadPoolSizes" is actually a map containing the sizes of +        // interest -- or should be, if this process has an +        // LLViewerControlListener instance and its settings include +        // "ThreadPoolSizes". If we failed to retrieve it, perhaps we're in a +        // program that doesn't define that, or perhaps there's no such +        // setting, or perhaps we're asking too early, before the LLEventAPI +        // itself has been instantiated. In any of those cases, it seems worth +        // warning. +        if (! poolSizes.isDefined()) +        { +            // Note: we don't warn about absence of an override key for a +            // particular ThreadPool name, that's fine. This warning is about +            // complete absence of a ThreadPoolSizes setting, which we expect +            // in a normal viewer session. +            LL_WARNS("ThreadPool") << "No 'ThreadPoolSizes' setting for ThreadPool '" +                                   << name << "'" << LL_ENDL; +        } +    } +    catch (const LL::CommonControl::Error& exc) +    { +        // We don't want ThreadPool to *require* LLViewerControlListener. +        // Just log it and carry on. +        LL_WARNS("ThreadPool") << "Can't check 'ThreadPoolSizes': " << exc.what() << LL_ENDL; +    } + +    LL_DEBUGS("ThreadPool") << "ThreadPoolSizes = " << poolSizes << LL_ENDL; +    // LLSD treats an undefined value as an empty map when asked to retrieve a +    // key, so we don't need this to be conditional. +    LLSD sizeSpec{ poolSizes[name] }; +    // We retrieve sizeSpec as LLSD, rather than immediately as LLSD::Integer, +    // so we can distinguish the case when it's undefined. +    return sizeSpec.isInteger() ? sizeSpec.asInteger() : dft; +} + +//static +size_t LL::ThreadPool::getWidth(const std::string& name, size_t dft) +{ +    auto instance{ getInstance(name) }; +    if (instance) +    { +        return instance->getWidth(); +    } +    else +    { +        return getConfiguredWidth(name, dft); +    } +} diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index b79c9b9090..b49d511257 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -22,14 +22,25 @@  namespace LL  { -    class ThreadPool +    class ThreadPool: public LLInstanceTracker<ThreadPool, std::string>      { +    private: +        using super = LLInstanceTracker<ThreadPool, std::string>;      public:          /**           * Pass ThreadPool a string name. This can be used to look up the           * relevant WorkQueue. +         * +         * The number of threads you pass sets the compile-time default. But +         * if the user has overridden the LLSD map in the "ThreadPoolSizes" +         * setting with a key matching this ThreadPool name, that setting +         * overrides this parameter. +         * +         * Pass an explicit capacity to limit the size of the queue. +         * Constraining the queue can cause a submitter to block. Do not +         * constrain any ThreadPool accepting work from the main thread.           */ -        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024); +        ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024*1024);          virtual ~ThreadPool();          /** @@ -57,6 +68,25 @@ namespace LL           */          virtual void run(); +        /** +         * getConfiguredWidth() returns the setting, if any, for the specified +         * ThreadPool name. Returns dft if the "ThreadPoolSizes" map does not +         * contain the specified name. +         */ +        static +        size_t getConfiguredWidth(const std::string& name, size_t dft=0); + +        /** +         * This getWidth() returns the width of the instantiated ThreadPool +         * with the specified name, if any. If no instance exists, returns its +         * getConfiguredWidth() if any. If there's no instance and no relevant +         * override, return dft. Presumably dft should match the threads +         * parameter passed to the ThreadPool constructor call that will +         * eventually instantiate the ThreadPool with that name. +         */ +        static +        size_t getWidth(const std::string& name, size_t dft); +      private:          void run(const std::string& name); | 
