Add LoadableLibraryManager and refactor StimBuffApiManager to use it.

Centralize dlopen/search in LoadableLibraryManager so typed library managers
can share one loaded-shlib registry without duplicating load/unload logic.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-10 21:14:55 -04:00
parent 10234bc422
commit 7eda755c15
7 changed files with 418 additions and 241 deletions
@@ -0,0 +1,111 @@
#ifndef LOADABLE_LIBRARY_MANAGER_H
#define LOADABLE_LIBRARY_MANAGER_H
#include <dlfcn.h>
#include <atomic>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <vector>
#include <spinscale/co/coQutex.h>
#include <spinscale/sharedResourceGroup.h>
namespace smo {
namespace loadable_lib {
class LoadableLibraryManager
{
public:
struct SharedLibraryDeleter
{
void operator()(void* handle) const;
};
struct LoadedSharedLibrary
{
LoadedSharedLibrary(
std::string libraryPathIn,
std::string resolvedPathIn,
std::unique_ptr<void, SharedLibraryDeleter> dlopenHandleIn)
: libraryPath(std::move(libraryPathIn)),
resolvedPath(std::move(resolvedPathIn)),
dlopenHandle(std::move(dlopenHandleIn))
{}
std::string libraryPath;
std::string resolvedPath;
std::unique_ptr<void, SharedLibraryDeleter> dlopenHandle;
std::atomic<bool> isBeingDestroyed{false};
void* getDlopenHandle() const
{
return dlopenHandle.get();
}
};
struct Resources
{
std::vector<std::shared_ptr<LoadedSharedLibrary>> loadedSharedLibraries;
};
static LoadableLibraryManager& getInstance()
{
static LoadableLibraryManager instance;
return instance;
}
std::optional<std::string> searchForLibInSmoSearchPaths(
const std::string& libraryPath) const;
std::shared_ptr<LoadedSharedLibrary> loadSharedLibrary(
const std::string& libraryPath);
void unloadSharedLibrary(
const std::shared_ptr<LoadedSharedLibrary>& loadedLibrary);
template<typename FnPtr>
static FnPtr resolveSymbol(void* handle, const char* symbolName)
{
dlerror();
auto symbol = reinterpret_cast<FnPtr>(dlsym(handle, symbolName));
const char* dlerr = dlerror();
if (dlerr != nullptr)
{
throw std::runtime_error(
std::string("dlsym('") + symbolName + "') failed: " + dlerr);
}
if (symbol == nullptr)
{
throw std::runtime_error(
std::string("dlsym('") + symbolName + "') returned null");
}
return symbol;
}
public:
sscl::SharedResourceGroup<sscl::co::CoQutex, Resources> s;
private:
LoadableLibraryManager()
: s("LoadableLibraryManager")
{}
~LoadableLibraryManager();
LoadableLibraryManager(const LoadableLibraryManager&) = delete;
LoadableLibraryManager& operator=(const LoadableLibraryManager&) = delete;
void appendLoadedSharedLibrary(
const std::shared_ptr<LoadedSharedLibrary>& loadedLibrary);
void removeLoadedSharedLibrary(
const std::shared_ptr<LoadedSharedLibrary>& loadedLibrary);
};
} // namespace loadable_lib
} // namespace smo
#endif // LOADABLE_LIBRARY_MANAGER_H
+18 -27
View File
@@ -3,11 +3,10 @@
#include <string>
#include <memory>
#include <atomic>
#include <vector>
#include <dlfcn.h>
#include <functional>
#include <user/senseApiDesc.h>
#include <loadableLib/loadableLibraryManager.h>
#include <spinscale/co/coQutex.h>
#include <spinscale/sharedResourceGroup.h>
@@ -18,25 +17,15 @@ class StimBuffApiLib
{
private:
friend class StimBuffApiManager;
struct DlCloser
{
void operator()(void* handle) const
{
if (handle) {
dlclose(handle);
}
}
};
public:
StimBuffApiLib(
const std::string& path, void *_dlopen_handle,
std::shared_ptr<loadable_lib::LoadableLibraryManager::LoadedSharedLibrary>
_loadedSharedLibrary,
SMO_GET_STIM_BUFF_API_DESC_FN_TYPEDEF *descFn)
: libraryPath(path),
isBeingDestroyed(false),
dlopen_handle(_dlopen_handle, DlCloser()),
SMO_GET_STIM_BUFF_API_DESC_FN_NAME(descFn),
s("StimBuffApiLib-" + path)
: loadedSharedLibrary(std::move(_loadedSharedLibrary)),
SMO_GET_STIM_BUFF_API_DESC_FN_NAME(descFn),
s("StimBuffApiLib-" + loadedSharedLibrary->libraryPath)
{}
void setStimBuffApiDesc(const StimBuffApiDesc &desc)
@@ -45,19 +34,19 @@ public:
{
throw std::runtime_error(
std::string(__func__) + ": Sanity check failed for stim buff API "
"descriptor in library '" + libraryPath + "'");
"descriptor in library '"
+ loadedSharedLibrary->libraryPath + "'");
}
stimBuffApiDesc = desc;
}
public:
std::string libraryPath;
std::atomic<bool> isBeingDestroyed;
std::unique_ptr<void, DlCloser> dlopen_handle;
/* UNIMPLEMENTED: API-specific cmdline options. These affect this specific
* stim buff api lib's behaviour globally.
*/
std::shared_ptr<loadable_lib::LoadableLibraryManager::LoadedSharedLibrary>
loadedSharedLibrary;
/* UNIMPLEMENTED: API-specific cmdline options. These affect this specific
* stim buff api lib's behaviour globally.
*/
std::vector<std::string> options;
/**
@@ -80,11 +69,13 @@ public:
struct StimBuffApiLibResources
{};
sscl::SharedResourceGroup<sscl::co::CoQutex, StimBuffApiLibResources> s;
std::string stringify() const {
std::string result = "Library Path: " + libraryPath + "\n";
std::string stringify() const
{
std::string result = "Library Path: "
+ loadedSharedLibrary->libraryPath + "\n";
result += "Stim Buff API Descriptor: " + stimBuffApiDesc.stringify() + "\n";
return result;
}
@@ -21,7 +21,7 @@ class StimBuffApiManager
public:
struct Resources
{
std::vector<std::shared_ptr<StimBuffApiLib>> stimBuffApiLibs;
std::vector<std::shared_ptr<StimBuffApiLib>> libs;
};
static StimBuffApiManager& getInstance()
@@ -39,7 +39,7 @@ public:
const std::string& libraryPath,
const std::shared_ptr<sscl::ComponentThread>& componentThread);
std::optional<std::shared_ptr<StimBuffApiLib>> getStimBuffApiLib(
std::optional<std::shared_ptr<StimBuffApiLib>> findStimBuffApiLibByLibraryPath(
const std::string& libraryPath);
std::optional<std::shared_ptr<StimBuffApiLib>> findStimBuffApiLibByApiName(
const std::string& apiName);
@@ -48,19 +48,21 @@ public:
void loadAllStimBuffApiLibsFromOptions(
const std::shared_ptr<sscl::ComponentThread>& componentThread);
void unloadAllStimBuffApiLibs(void);
body::BodyViralPostingInvoker<void> initializeStimBuffApiLibCReq(
StimBuffApiLib &lib, bool acquireSbamLock=true);
StimBuffApiLib &lib, bool acquireListLock=true);
body::BodyViralPostingInvoker<void> finalizeStimBuffApiLibCReq(
StimBuffApiLib &lib, bool acquireSbamLock=true);
StimBuffApiLib &lib, bool acquireListLock=true);
body::BodyViralPostingInvoker<void> initializeAllStimBuffApiLibsCReq();
body::BodyViralPostingInvoker<void> finalizeAllStimBuffApiLibsCReq();
std::string stringifyLibs() const;
public:
sscl::SharedResourceGroup<sscl::co::CoQutex, Resources> s;
private:
StimBuffApiManager()
: s("StimBuffApiManager")
@@ -70,13 +72,6 @@ private:
StimBuffApiManager(const StimBuffApiManager&) = delete;
StimBuffApiManager& operator=(const StimBuffApiManager&) = delete;
public:
sscl::SharedResourceGroup<sscl::co::CoQutex, Resources> s;
public:
static std::optional<std::string> searchForLibInSmoSearchPaths(
const std::string& libraryPath);
};
} // namespace stim_buff