From 49f763aa445cac3b338a8291c6114f0602e1ccd5 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sun, 14 May 2023 06:50:27 +0200 Subject: [PATCH] code: Add a proper dynamic loader for components This loader model should have wider compatibility, as it relies on defined C++ behavior instead of undefined preprocessor behavior. We may even be able to implement a simple dependency system that automatically sorts components into the correct order. --- source/plugin.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++++ source/plugin.hpp | 29 +++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/source/plugin.cpp b/source/plugin.cpp index 50b72b4..50929da 100644 --- a/source/plugin.cpp +++ b/source/plugin.cpp @@ -76,6 +76,8 @@ #include "warning-disable.hpp" #include +#include +#include #include #include "warning-enable.hpp" @@ -83,11 +85,60 @@ static std::shared_ptr _threadpool; static std::shared_ptr _streamfx_gfx_opengl; static std::shared_ptr _source_tracker; +namespace streamfx { + typedef std::list loader_list_t; + typedef std::map loader_map_t; + + loader_map_t& get_initializers() + { + static loader_map_t initializers; + return initializers; + } + + loader_map_t& get_finalizers() + { + static loader_map_t finalizers; + return finalizers; + } + + loader::loader(loader_function_t initializer, loader_function_t finalizer, loader_priority_t priority) + { + auto init_kv = get_initializers().find(priority); + if (init_kv != get_initializers().end()) { + init_kv->second.push_back(initializer); + } else { + get_initializers().emplace(priority, loader_list_t{initializer}); + } + + // Invert the order for finalizers. + auto ipriority = priority ^ static_cast(0xFFFFFFFFFFFFFFFF); + auto fina_kv = get_finalizers().find(ipriority); + if (fina_kv != get_finalizers().end()) { + fina_kv->second.push_back(finalizer); + } else { + get_finalizers().emplace(ipriority, loader_list_t{finalizer}); + } + } +} // namespace streamfx + MODULE_EXPORT bool obs_module_load(void) { try { DLOG_INFO("Loading Version %s", STREAMFX_VERSION_STRING); + // Run all initializers. + for (auto kv : streamfx::get_initializers()) { + for (auto init : kv.second) { + try { + init(); + } catch (const std::exception& ex) { + DLOG_ERROR("Initializer threw exception: %s", ex.what()); + } catch (...) { + DLOG_ERROR("Initializer threw unknown exception."); + } + } + } + // Initialize global configuration. streamfx::configuration::initialize(); @@ -290,6 +341,19 @@ MODULE_EXPORT void obs_module_unload(void) // Finalize Thread Pool _threadpool.reset(); + // Run all finalizers. + for (auto kv : streamfx::get_finalizers()) { + for (auto init : kv.second) { + try { + init(); + } catch (const std::exception& ex) { + DLOG_ERROR("Finalizer threw exception: %s", ex.what()); + } catch (...) { + DLOG_ERROR("Finalizer threw unknown exception."); + } + } + } + DLOG_INFO("Unloaded Version %s", STREAMFX_VERSION_STRING); } catch (std::exception const& ex) { DLOG_ERROR("Unexpected exception in function '%s': %s", __FUNCTION_NAME__, ex.what()); diff --git a/source/plugin.hpp b/source/plugin.hpp index 25b58b3..5d3268a 100644 --- a/source/plugin.hpp +++ b/source/plugin.hpp @@ -5,7 +5,36 @@ #pragma once #include "common.hpp" +#include "warning-disable.hpp" +#include +#include +#include "warning-enable.hpp" + namespace streamfx { + /** Simple but efficient loader structure for ordered initia-/finalize. + * + */ + typedef int32_t loader_priority_t; + typedef std::function loader_function_t; + enum loader_priority : loader_priority_t { + HIGHEST = INT32_MIN, + HIGHER = INT32_MIN / 4 * 3, + HIGH = INT32_MIN / 4 * 2, + ABOVE = INT32_MIN / 4, + NORMAL = 0, + BELOW = INT32_MAX / 4, + LOW = INT32_MAX / 4 * 2, + LOWER = INT32_MAX / 4 * 3, + LOWEST = INT32_MAX, + }; + + struct loader { + loader(loader_function_t initializer, loader_function_t finalizer, loader_priority_t priority); + + // Usage: + // auto loader = streamfx::loader([]() { ... }, []() { ... }, 0); + }; + // Threadpool std::shared_ptr threadpool();