3e19d39853
SenseApiDesc's exported API now uses coro pointers instead of CPS fn pointers. * Do not build this version of SMO with the Livox drivers enabled, because SMO has been changed at the smocore level to use coros when calling into stimbuffAPI libs. But the Livox drivers haven't yet been ported from CPS to coros. xcbWindow has been ported to expose coros to SMO in its senseApiDesc exported iface.
384 lines
11 KiB
C++
384 lines
11 KiB
C++
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <optional>
|
|
#include <filesystem>
|
|
#include <stimBuffApis/stimBuffApiManager.h>
|
|
#include <stimBuffApis/stimBuffApiLib.h>
|
|
#include <body/bodyThread.h>
|
|
#include <componentThread.h>
|
|
#include <opts.h>
|
|
#include <user/senseApiDesc.h>
|
|
#include <mind.h>
|
|
#include <deviceManager/deviceManager.h>
|
|
#include <marionette/marionette.h>
|
|
#include <computeManager/computeManager.h>
|
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace smo {
|
|
namespace stim_buff {
|
|
|
|
namespace {
|
|
|
|
void assertBodyThread()
|
|
{
|
|
auto self = sscl::ComponentThread::getSelf();
|
|
if (self->id != SmoThreadId::BODY)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__)
|
|
+ ": Must be executed on Body thread");
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/**
|
|
* @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())
|
|
{
|
|
// 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 sscl::ComponentThread::getSelf for SmoCallbacks */
|
|
static std::shared_ptr<sscl::ComponentThread> ComponentThread_getSelf()
|
|
{
|
|
return sscl::ComponentThread::getSelf();
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Hooks to be provided to stimBuffApiLibs, enabling them to call into Salmanoff
|
|
* code.
|
|
*/
|
|
static SmoCallbacks smoCallbacks =
|
|
{
|
|
.searchForLibInSmoSearchPaths = searchForLibInSmoSearchPaths,
|
|
.ComponentThread_getSelf = ComponentThread_getSelf,
|
|
.OptionParser_getOptions = OptionParser_getOptions,
|
|
.ComputeManager_createUseHostPtrBuffer =
|
|
ComputeManager_createUseHostPtrBuffer,
|
|
.ComputeManager_releaseUseHostPtrBuffer =
|
|
ComputeManager_releaseUseHostPtrBuffer,
|
|
.ComputeManager_getDevice = ComputeManager_getDevice,
|
|
.ComputeManager_releaseDevice = ComputeManager_releaseDevice
|
|
};
|
|
|
|
/* Static file-scope threading model object for senseApi libraries */
|
|
static SmoThreadingModelDesc smoThreadingModelDesc = {
|
|
.componentThread = nullptr
|
|
};
|
|
|
|
std::optional<std::string> StimBuffApiManager::searchForLibInSmoSearchPaths(
|
|
const std::string& libraryPath)
|
|
{
|
|
return ::smo::stim_buff::searchForLibInSmoSearchPaths(libraryPath);
|
|
}
|
|
|
|
StimBuffApiLib& StimBuffApiManager::loadStimBuffApiLib(
|
|
const std::string& libraryPath,
|
|
const std::shared_ptr<sscl::ComponentThread>& componentThread
|
|
)
|
|
{
|
|
std::optional<std::string> fullPath = searchForLibInSmoSearchPaths(
|
|
libraryPath);
|
|
std::string resolvedPath = fullPath.value_or(libraryPath);
|
|
|
|
// Clear any existing error
|
|
dlerror();
|
|
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)
|
|
{
|
|
const char *dlerr = dlerror();
|
|
|
|
std::string error = (dlerr
|
|
? dlerr
|
|
: "Unknown error while opening shlib");
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": Cannot load library '"
|
|
+ libraryPath + "': "
|
|
+ error);
|
|
}
|
|
|
|
// Initialize getSenseApiDescriptor
|
|
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(
|
|
std::string(__func__) + ": dlsym('"
|
|
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;
|
|
}
|
|
|
|
const StimBuffApiDesc &libApiDesc = func(
|
|
smoCallbacks, smoThreadingModelDesc);
|
|
|
|
auto lib = std::make_shared<StimBuffApiLib>(
|
|
libraryPath, dlopen_handle.release(), func);
|
|
lib->setStimBuffApiDesc(libApiDesc);
|
|
getInstance().s.rsrc.stimBuffApiLibs.push_back(lib);
|
|
return *getInstance().s.rsrc.stimBuffApiLibs.back();
|
|
}
|
|
|
|
std::optional<std::shared_ptr<StimBuffApiLib>>
|
|
StimBuffApiManager::getStimBuffApiLib(const std::string& libraryPath)
|
|
{
|
|
auto &libs = getInstance().s.rsrc.stimBuffApiLibs;
|
|
auto it = std::find_if(libs.begin(), libs.end(),
|
|
[&libPath = libraryPath](const std::shared_ptr<StimBuffApiLib>& lib) {
|
|
return lib->libraryPath == libPath;
|
|
}
|
|
);
|
|
|
|
if (it != libs.end()) { return *it; }
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<std::shared_ptr<StimBuffApiLib>>
|
|
StimBuffApiManager::getStimBuffApiLibByApiName(const std::string& apiName)
|
|
{
|
|
auto &libs = getInstance().s.rsrc.stimBuffApiLibs;
|
|
auto it = std::find_if(libs.begin(), libs.end(),
|
|
[&apiName](const std::shared_ptr<StimBuffApiLib>& lib) {
|
|
return lib->stimBuffApiDesc.name == apiName;
|
|
}
|
|
);
|
|
|
|
if (it != libs.end()) { return *it; }
|
|
return std::nullopt;
|
|
}
|
|
|
|
void StimBuffApiManager::unloadStimBuffApiLib(const std::string& libraryPath)
|
|
{
|
|
auto &libs = getInstance().s.rsrc.stimBuffApiLibs;
|
|
auto it = std::find_if(libs.begin(), libs.end(),
|
|
[&lpath = libraryPath](const std::shared_ptr<StimBuffApiLib>& lib) {
|
|
return lib->libraryPath == lpath;
|
|
}
|
|
);
|
|
|
|
if (it != libs.end())
|
|
{
|
|
libs.erase(it);
|
|
return;
|
|
}
|
|
|
|
std::cerr << std::string(__func__) + ": Library not found: "
|
|
<< libraryPath << '\n';
|
|
}
|
|
|
|
void StimBuffApiManager::unloadAllStimBuffApiLibs(void)
|
|
{
|
|
getInstance().s.rsrc.stimBuffApiLibs.clear();
|
|
}
|
|
|
|
void StimBuffApiManager::loadAllStimBuffApiLibsFromOptions(
|
|
const std::shared_ptr<sscl::ComponentThread>& componentThread
|
|
)
|
|
{
|
|
const auto& options = OptionParser::getOptions();
|
|
for (const auto& libPath : options.senseApiLibs) {
|
|
loadStimBuffApiLib(libPath, componentThread);
|
|
}
|
|
}
|
|
|
|
std::string StimBuffApiManager::stringifyLibs() const
|
|
{
|
|
std::string result;
|
|
for (const auto& lib : getInstance().s.rsrc.stimBuffApiLibs) {
|
|
result += lib->stringify() + "\n";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
body::BodyViralPostingInvoker<void>
|
|
StimBuffApiManager::initializeStimBuffApiLibCReq(
|
|
StimBuffApiLib &lib, bool acquireSbamLock)
|
|
{
|
|
assertBodyThread();
|
|
|
|
StimBuffApiManager &sbam = getInstance();
|
|
std::optional<sscl::co::CoQutex::ReleaseHandle> sbamGuard;
|
|
if (acquireSbamLock)
|
|
{
|
|
sbamGuard.emplace(
|
|
co_await sbam.s.lock.getAcquireInvocationAndSuspensionPolicy());
|
|
}
|
|
|
|
if (!lib.stimBuffApiDesc.sal_mgmt_libOps.initializeCInd)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": initializeCInd() is NULL for library '"
|
|
+ lib.libraryPath + "'");
|
|
}
|
|
|
|
sscl::co::CoQutex::ReleaseHandle libGuard =
|
|
co_await lib.s.lock.getAcquireInvocationAndSuspensionPolicy();
|
|
|
|
co_await lib.stimBuffApiDesc.sal_mgmt_libOps.initializeCInd();
|
|
|
|
co_return;
|
|
}
|
|
|
|
body::BodyViralPostingInvoker<void>
|
|
StimBuffApiManager::finalizeStimBuffApiLibCReq(
|
|
StimBuffApiLib &lib, bool acquireSbamLock)
|
|
{
|
|
assertBodyThread();
|
|
|
|
StimBuffApiManager &sbam = getInstance();
|
|
std::optional<sscl::co::CoQutex::ReleaseHandle> sbamGuard;
|
|
if (acquireSbamLock)
|
|
{
|
|
sbamGuard.emplace(
|
|
co_await sbam.s.lock.getAcquireInvocationAndSuspensionPolicy());
|
|
}
|
|
|
|
lib.isBeingDestroyed.store(true);
|
|
|
|
if (!lib.stimBuffApiDesc.sal_mgmt_libOps.finalizeCInd)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": finalizeCInd() is NULL for library '"
|
|
+ lib.libraryPath + "'");
|
|
}
|
|
|
|
sscl::co::CoQutex::ReleaseHandle libGuard =
|
|
co_await lib.s.lock.getAcquireInvocationAndSuspensionPolicy();
|
|
|
|
co_await lib.stimBuffApiDesc.sal_mgmt_libOps.finalizeCInd();
|
|
|
|
co_return;
|
|
}
|
|
|
|
body::BodyViralPostingInvoker<void>
|
|
StimBuffApiManager::initializeAllStimBuffApiLibsCReq()
|
|
{
|
|
assertBodyThread();
|
|
|
|
StimBuffApiManager &sbam = getInstance();
|
|
sscl::co::CoQutex::ReleaseHandle sbamGuard =
|
|
co_await sbam.s.lock.getAcquireInvocationAndSuspensionPolicy();
|
|
|
|
for (auto &lib : sbam.s.rsrc.stimBuffApiLibs) {
|
|
co_await initializeStimBuffApiLibCReq(*lib, false);
|
|
}
|
|
|
|
co_return;
|
|
}
|
|
|
|
body::BodyViralPostingInvoker<void>
|
|
StimBuffApiManager::finalizeAllStimBuffApiLibsCReq()
|
|
{
|
|
assertBodyThread();
|
|
|
|
StimBuffApiManager &sbam = getInstance();
|
|
sscl::co::CoQutex::ReleaseHandle sbamGuard =
|
|
co_await sbam.s.lock.getAcquireInvocationAndSuspensionPolicy();
|
|
|
|
for (auto &lib : sbam.s.rsrc.stimBuffApiLibs) {
|
|
co_await finalizeStimBuffApiLibCReq(*lib, false);
|
|
}
|
|
|
|
co_return;
|
|
}
|
|
|
|
|
|
} // namespace stim_buff
|
|
} // namespace smo
|