Files

321 lines
9.4 KiB
C++
Raw Permalink Normal View History

#include <iostream>
#include <stdexcept>
#include <optional>
#include <filesystem>
2025-10-01 18:47:42 -04:00
#include <stimBuffApis/stimBuffApiManager.h>
#include <stimBuffApis/stimBuffApiLib.h>
#include <opts.h>
#include <asynchronousBridge.h>
#include <asynchronousContinuation.h>
#include <asynchronousLoop.h>
#include <callback.h>
#include <user/senseApiDesc.h>
#include <mind.h>
#include <deviceManager/deviceManager.h>
#include <marionette/marionette.h>
#include <computeManager/computeManager.h>
namespace fs = std::filesystem;
2025-07-22 06:48:04 -04:00
namespace smo {
2025-10-01 18:47:42 -04:00
namespace stim_buff {
/**
* @brief Searches for a library in predefined locations
* @param libraryPath The name or path of the library to find
* @return Optional containing the full path if found in search paths, nullopt
* if not
*
* Searches for the library in the following locations in order:
* 1. Custom path specified by --sense-api-lib-path option (if provided)
* 2. Current working directory
* 3. Directory containing the executable
*
* If the library is not found in any of these locations, returns nullopt and
* falls back to system default library search paths (LD_LIBRARY_PATH, etc.)
*/
static std::optional<std::string> searchForLibInSmoSearchPaths(
const std::string& libraryPath)
{
std::vector<std::string> searchPaths = {
fs::current_path().string(),
fs::path("/proc/self/exe").parent_path().string()
};
const auto& options = OptionParser::getOptions();
if (!options.senseApiLibPath.empty())
{
2025-10-01 18:47:42 -04:00
// Insert all stim buff API library paths at the beginning of search paths
searchPaths.insert(
searchPaths.begin(),
options.senseApiLibPath.begin(),
options.senseApiLibPath.end());
}
for (const auto& path : searchPaths)
{
fs::path fullPath = fs::path(path) / libraryPath;
if (fs::exists(fullPath))
{
return fullPath.string();
}
}
std::cerr << std::string(__func__) + ": library '"
+ libraryPath + "' isn't in search bespoke search paths: ";
for (const auto& path : searchPaths) {
std::cerr << path << " ";
}
std::cerr << std::endl;
std::cerr << "Trying to load " + libraryPath + " from system default "
"search paths\n";
return std::nullopt;
}
/* Local static function to wrap ComponentThread::getSelf for SmoCallbacks */
static std::shared_ptr<ComponentThread> ComponentThread_getSelf()
{
return ComponentThread::getSelf();
}
2025-11-07 14:59:28 -04:00
/* Local static function to wrap OptionParser::getOptions for SmoCallbacks */
static OptionParser& OptionParser_getOptions()
{
return OptionParser::getOptions();
}
/* Local static functions to wrap ComputeManager methods for SmoCallbacks */
static std::shared_ptr<smo::compute::ClBuffer>
ComputeManager_createUseHostPtrBuffer(
void* hostPtr, size_t size, cl_mem_flags flags
)
{
return smo::compute::ComputeManager::getInstance().createUseHostPtrBuffer(
hostPtr, size, flags);
}
static void ComputeManager_releaseUseHostPtrBuffer(
std::shared_ptr<smo::compute::ClBuffer> buffer
)
{
smo::compute::ComputeManager::getInstance().releaseUseHostPtrBuffer(
buffer);
}
static std::shared_ptr<smo::compute::ComputeDevice> ComputeManager_getDevice()
{
return smo::compute::ComputeManager::getInstance().getDevice();
}
static void ComputeManager_releaseDevice(
std::shared_ptr<smo::compute::ComputeDevice> device
)
{
smo::compute::ComputeManager::getInstance().releaseDevice(device);
}
2025-10-01 18:47:42 -04:00
/* Hooks to be provided to stimBuffApiLibs, enabling them to call into Salmanoff
2025-07-24 06:00:35 -04:00
* code.
*/
static SmoCallbacks smoCallbacks =
2025-07-24 06:00:35 -04:00
{
.searchForLibInSmoSearchPaths = searchForLibInSmoSearchPaths,
2025-11-07 14:59:28 -04:00
.ComponentThread_getSelf = ComponentThread_getSelf,
.OptionParser_getOptions = OptionParser_getOptions,
.ComputeManager_createUseHostPtrBuffer =
ComputeManager_createUseHostPtrBuffer,
.ComputeManager_releaseUseHostPtrBuffer =
ComputeManager_releaseUseHostPtrBuffer,
.ComputeManager_getDevice = ComputeManager_getDevice,
.ComputeManager_releaseDevice = ComputeManager_releaseDevice
2025-07-24 06:00:35 -04:00
};
/* Static file-scope threading model object for senseApi libraries */
static SmoThreadingModelDesc smoThreadingModelDesc = {
.componentThread = nullptr
};
2025-10-01 18:47:42 -04:00
std::optional<std::string> StimBuffApiManager::searchForLibInSmoSearchPaths(
const std::string& libraryPath)
{
2025-10-01 18:47:42 -04:00
return ::smo::stim_buff::searchForLibInSmoSearchPaths(libraryPath);
}
2025-10-01 18:47:42 -04:00
StimBuffApiLib& StimBuffApiManager::loadStimBuffApiLib(
const std::string& libraryPath,
const std::shared_ptr<ComponentThread>& componentThread
)
{
std::optional<std::string> fullPath = searchForLibInSmoSearchPaths(
libraryPath);
std::string resolvedPath = fullPath.value_or(libraryPath);
// Clear any existing error
dlerror();
2025-10-01 18:47:42 -04:00
auto dlopen_handle = std::unique_ptr<void, StimBuffApiLib::DlCloser>(
dlopen(resolvedPath.c_str(), RTLD_LAZY));
if (!dlopen_handle && fullPath.has_value())
{
// Fallback to using the supplied libraryPath
dlerror();
dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY));
}
if (!dlopen_handle)
{
2025-01-08 15:08:51 -04:00
const char *dlerr = dlerror();
std::string error = (dlerr
? dlerr
: "Unknown error while opening shlib");
throw std::runtime_error(
2025-01-08 15:08:51 -04:00
std::string(__func__) + ": Cannot load library '"
+ libraryPath + "': "
+ error);
}
// Initialize getSenseApiDescriptor
2025-10-01 18:47:42 -04:00
auto func = reinterpret_cast<SMO_GET_STIM_BUFF_API_DESC_FN_TYPEDEF *>(
dlsym(dlopen_handle.get(), SMO_GET_STIM_BUFF_API_DESC_FN_NAME_STR));
if (!func)
{
throw std::runtime_error(
2025-01-08 15:09:18 -04:00
std::string(__func__) + ": dlsym('"
2025-10-01 18:47:42 -04:00
SMO_GET_STIM_BUFF_API_DESC_FN_NAME_STR "') failed for library '"
+ libraryPath + "'");
}
// Check if the static threading model obj is null and initialize if needed
if (!smoThreadingModelDesc.componentThread) {
smoThreadingModelDesc.componentThread = componentThread;
}
2025-10-01 18:47:42 -04:00
const StimBuffApiDesc &libApiDesc = func(
smoCallbacks, smoThreadingModelDesc);
2025-10-01 18:47:42 -04:00
auto lib = std::make_shared<StimBuffApiLib>(
libraryPath, dlopen_handle.release(), func);
2025-10-01 18:47:42 -04:00
lib->setStimBuffApiDesc(libApiDesc);
stimBuffApiLibs.push_back(lib);
return *stimBuffApiLibs.back();
}
2025-10-01 18:47:42 -04:00
std::optional<std::shared_ptr<StimBuffApiLib>>
StimBuffApiManager::getStimBuffApiLib(const std::string& libraryPath)
{
2025-10-01 18:47:42 -04:00
auto it = std::find_if(stimBuffApiLibs.begin(), stimBuffApiLibs.end(),
[&libPath = libraryPath](const std::shared_ptr<StimBuffApiLib>& lib) {
return lib->libraryPath == libPath;
}
);
2025-10-01 18:47:42 -04:00
if (it != stimBuffApiLibs.end()) { return *it; }
return std::nullopt;
}
2025-10-01 18:47:42 -04:00
std::optional<std::shared_ptr<StimBuffApiLib>>
StimBuffApiManager::getStimBuffApiLibByApiName(const std::string& apiName)
{
2025-10-01 18:47:42 -04:00
auto it = std::find_if(stimBuffApiLibs.begin(), stimBuffApiLibs.end(),
[&apiName](const std::shared_ptr<StimBuffApiLib>& lib) {
return lib->stimBuffApiDesc.name == apiName;
}
);
2025-10-01 18:47:42 -04:00
if (it != stimBuffApiLibs.end()) { return *it; }
return std::nullopt;
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::unloadStimBuffApiLib(const std::string& libraryPath)
{
2025-10-01 18:47:42 -04:00
auto it = std::find_if(stimBuffApiLibs.begin(), stimBuffApiLibs.end(),
[&lpath = libraryPath](const std::shared_ptr<StimBuffApiLib>& lib) {
return lib->libraryPath == lpath;
}
);
2025-10-01 18:47:42 -04:00
if (it != stimBuffApiLibs.end())
{
2025-10-01 18:47:42 -04:00
stimBuffApiLibs.erase(it);
return;
}
std::cerr << std::string(__func__) + ": Library not found: "
<< libraryPath << '\n';
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::unloadAllStimBuffApiLibs(void)
{
2025-10-01 18:47:42 -04:00
stimBuffApiLibs.clear();
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::loadAllStimBuffApiLibsFromOptions(
const std::shared_ptr<ComponentThread>& componentThread
)
{
const auto& options = OptionParser::getOptions();
for (const auto& libPath : options.senseApiLibs) {
2025-10-01 18:47:42 -04:00
loadStimBuffApiLib(libPath, componentThread);
}
}
2025-10-01 18:47:42 -04:00
std::string StimBuffApiManager::stringifyLibs() const
{
std::string result;
2025-10-01 18:47:42 -04:00
for (const auto& lib : stimBuffApiLibs) {
result += lib->stringify() + "\n";
}
return result;
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::initializeStimBuffApiLib(StimBuffApiLib& lib)
{
/** FIXME:
* When we eventually make this method async, this method should acquire
2025-10-01 18:47:42 -04:00
* the StimBuffApiManager's main CRUD qutex.
*/
2025-10-01 18:47:42 -04:00
if (!lib.stimBuffApiDesc.sal_mgmt_libOps.initializeInd)
{
throw std::runtime_error(
std::string(__func__) + ": initializeInd() is NULL for library '"
+ lib.libraryPath + "'");
}
2025-10-01 18:47:42 -04:00
lib.stimBuffApiDesc.sal_mgmt_libOps.initializeInd();
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::finalizeStimBuffApiLib(StimBuffApiLib& lib)
{
/** FIXME:
* When we eventually make this method async, this flag should only be set
2025-10-01 18:47:42 -04:00
* after acquiring the StimBuffApiManager's main CRUD qutex.
*/
lib.isBeingDestroyed.store(true);
2025-10-01 18:47:42 -04:00
if (!lib.stimBuffApiDesc.sal_mgmt_libOps.finalizeInd)
{
throw std::runtime_error(
std::string(__func__) + ": finalizeInd() is NULL for library '"
+ lib.libraryPath + "'");
}
2025-10-01 18:47:42 -04:00
lib.stimBuffApiDesc.sal_mgmt_libOps.finalizeInd();
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::initializeAllStimBuffApiLibs(void)
{
2025-10-01 18:47:42 -04:00
for (auto& lib : stimBuffApiLibs) {
initializeStimBuffApiLib(*lib);
}
}
2025-10-01 18:47:42 -04:00
void StimBuffApiManager::finalizeAllStimBuffApiLibs(void)
{
2025-10-01 18:47:42 -04:00
for (auto& lib : stimBuffApiLibs) {
finalizeStimBuffApiLib(*lib);
}
}
2025-10-01 18:47:42 -04:00
} // namespace stim_buff
2025-07-22 06:48:04 -04:00
} // namespace smo