From 53583e573527c2c0a900cb832099b15ecd50396f Mon Sep 17 00:00:00 2001 From: Hayodea Hakol Date: Thu, 9 Jan 2025 06:03:43 -0400 Subject: [PATCH] SenseApiLib, SenseApiDesc improvements, new Sense API Mgmt Lib Ops role SenseApiDesc: * Use a number count for num exported implexor APIs instead of NULL-terminated list. * Add sanity checker functions for structs. SenseApiLib: * Invoke the new sanity checkers on new Lib objects. * SenseApiDesc is now a member object instead of being pointed to. SenseApiManager: * loadSenseApiLib now calls the SenseApiDesc getter function. * loadSenseApiLib now fills out the SenseApiLib class object. New Sense API Mgmt Sub-API: This sub-api (metalanguage, some might call it) is used to initialize the lib's connection to the provider. After this call, the lib should be ready to attach new devices to its provider on behalf of Hk. --- hcore/include/senseApis/senseApiLib.h | 72 ++++++++++++++++++++++----- hcore/senseApis/senseApiManager.cpp | 36 +++++++++++--- include/user/senseApiDesc.h | 64 +++++++++++++++++++++++- senseApis/xcbXorg/xcbXorg.cpp | 49 ++++++++++++++++-- 4 files changed, 196 insertions(+), 25 deletions(-) diff --git a/hcore/include/senseApis/senseApiLib.h b/hcore/include/senseApis/senseApiLib.h index a072a3e..3d88775 100644 --- a/hcore/include/senseApis/senseApiLib.h +++ b/hcore/include/senseApis/senseApiLib.h @@ -20,18 +20,35 @@ public: class ExportedImplexorApiDesc { public: + ExportedImplexorApiDesc(const CExportedImplexorApiDesc& cDesc) + // The caller should sanity check before calling this constructor. + : name(cDesc.name) + {} + const std::string name; }; public: + SenseApiDesc() = default; SenseApiDesc(const CSenseApiDesc& cDesc) - : cDescriptor(cDesc), name(cDesc.name) - {} + // The caller should sanity check before calling this constructor. + : name(cDesc.name) + { + for (uint32_t i = 0; i < cDesc.numExportedImplexorApis; ++i) + { + if (!CExportedImplexorApiDesc_sanityCheck( + &cDesc.exportedImplexorApis[i])) + { + throw std::runtime_error( + "Sanity check failed for exported implexor API descriptor"); + } + + exportedImplexorApis.push_back( + ExportedImplexorApiDesc(cDesc.exportedImplexorApis[i])); + } + } - std::reference_wrapper cDescriptor; std::string name; - // These options affect the sense api lib's behaviour globally. - std::vector options; // These are the implexors whose APIs this lib exports. std::vector exportedImplexorApis; }; @@ -39,14 +56,44 @@ public: class SenseApiLib { public: - SenseApiLib(const std::string& path) + SenseApiLib( + const std::string& path, void *_dlopen_handle, getSenseApiDescFn *descFn) : libraryPath(path), - handle(nullptr, reinterpret_cast(&dlclose)) + dlopen_handle( + _dlopen_handle, reinterpret_cast(&dlclose)), + HK_GET_SENSE_API_DESC_FN_NAME(descFn) {} + void setSenseApiDesc(const CSenseApiDesc* desc) + { + if (!CSenseApiDesc_sanityCheck(desc) || + !Csal_libMgmtOps_sanityCheck(desc->sal_libMgmtOps)) + { + throw std::runtime_error( + std::string(__func__) + ": Sanity check failed for sense API " + "descriptor in library '" + libraryPath + "'"); + } + for (uint32_t i = 0; i < desc->numExportedImplexorApis; ++i) + { + if (!CExportedImplexorApiDesc_sanityCheck( + &desc->exportedImplexorApis[i])) + { + throw std::runtime_error( + std::string(__func__) + ": Sanity check failed for " + "exported implexor API descriptor in library '" + + libraryPath + "'"); + } + } + new (&senseApiDesc) SenseApiDesc(*desc); // Placement new + } + public: std::string libraryPath; - std::unique_ptr handle; + std::unique_ptr dlopen_handle; + /* UNIMPLEMENTED: API-specific cmdline options. These affect this specific + * sense api lib's behaviour globally. + */ + std::vector options; /** * @brief Every sense API lib is required to provide a function that returns @@ -56,13 +103,14 @@ public: * This getter function should be visible to dlsym() so that Harikoff can * find it in the lib after loading it, and call it. */ - std::function getSenseApiDescriptor; + std::function HK_GET_SENSE_API_DESC_FN_NAME; /** - * @brief Harikoff will call the `getSenseApiDescriptor` getter function and - * use the data it provides in order to fill out this descriptor. + * @brief Harikoff will call the `HK_GET_SENSE_API_DESC_FN_NAME` getter + * function and use the data it provides in order to fill out this + * descriptor. */ - std::unique_ptr apiDescriptor; + SenseApiDesc senseApiDesc; }; } // namespace sense_api diff --git a/hcore/senseApis/senseApiManager.cpp b/hcore/senseApis/senseApiManager.cpp index 72ef17d..cc5b617 100644 --- a/hcore/senseApis/senseApiManager.cpp +++ b/hcore/senseApis/senseApiManager.cpp @@ -12,6 +12,14 @@ namespace fs = std::filesystem; namespace hk { namespace sense_api { +struct DlCloser { + void operator()(void* handle) const { + if (handle) { + dlclose(handle); + } + } +}; + static std::optional findLibraryPath( const std::string& libraryPath) { @@ -50,20 +58,22 @@ static std::optional findLibraryPath( SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath) { + const CSenseApiDesc *libApiDesc; std::optional fullPath = findLibraryPath(libraryPath); - auto lib = std::make_unique(fullPath.value_or(libraryPath)); + std::string resolvedPath = fullPath.value_or(libraryPath); // Clear any existing error dlerror(); - lib->handle.reset(dlopen(lib->libraryPath.c_str(), RTLD_LAZY)); - if (!lib->handle && fullPath.has_value()) + auto dlopen_handle = std::unique_ptr( + dlopen(resolvedPath.c_str(), RTLD_LAZY)); + if (!dlopen_handle && fullPath.has_value()) { // Fallback to using the supplied libraryPath dlerror(); - lib->handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY)); + dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY)); } - if (!lib->handle) + if (!dlopen_handle) { const char *dlerr = dlerror(); @@ -78,16 +88,26 @@ SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath) // Initialize getSenseApiDescriptor auto func = reinterpret_cast( - dlsym(lib->handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR)); + dlsym(dlopen_handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR)); if (!func) { throw std::runtime_error( std::string(__func__) + ": dlsym('" HK_GET_SENSE_API_DESC_FN_NAME_STR "') failed for library '" - + lib->libraryPath + "'"); + + libraryPath + "'"); } - lib->getSenseApiDescriptor = func; + libApiDesc = func(); + if (!libApiDesc) + { + throw std::runtime_error( + std::string(__func__) + ": getSenseApiDesc() returned NULL for " + "library '" + libraryPath + "'"); + } + + auto lib = std::make_unique( + libraryPath, dlopen_handle.release(), func); + lib->setSenseApiDesc(libApiDesc); senseApiLibs.push_back(std::move(lib)); return *senseApiLibs.back(); } diff --git a/include/user/senseApiDesc.h b/include/user/senseApiDesc.h index 272308b..4b13cd2 100644 --- a/include/user/senseApiDesc.h +++ b/include/user/senseApiDesc.h @@ -2,6 +2,7 @@ #define __USER_SENSE_API_LIB_H__ #include +#include #ifdef __cplusplus extern "C" { @@ -15,16 +16,77 @@ struct CExportedImplexorApiDesc const char *name; }; +typedef int (sal_lmo_initializeIndFn)(void); +typedef int (sal_lmo_finalizeIndFn)(void); +typedef int (sal_lmo_attachDeviceReqFn)(void); +typedef int (sal_lmo_detachDeviceReqFn)(void); + +struct Csal_libMgmtOps +{ + /* When Harikoff loads a sense API lib, it calls this function to initialize + * the lib. When this returns, the lib should be ready to attach devices. + */ + sal_lmo_initializeIndFn *initializeInd; + /* Harikoff calls this to finalize the lib and free its internal + * resources. When this returns, the lib should be ready to be unloaded. + */ + sal_lmo_finalizeIndFn *finalizeInd; + /* Harikoff calls this to attach a device to the lib. When it returns, the + * device should be attached and ready to be implexed. + */ + sal_lmo_attachDeviceReqFn *attachDeviceReq; + // When this returns, the device should be detached. + sal_lmo_detachDeviceReqFn *detachDeviceReq; +}; + struct CSenseApiDesc { /* Shortname that identifies the API used by this lib to talk to the sense * provider. */ const char *name; - // These are the implexors whose APIs this lib exports. + /* These are the implexors whose APIs this lib exports. + */ + uint32_t numExportedImplexorApis; CExportedImplexorApiDesc *exportedImplexorApis; + /* Sub-API for managing the lib. Library role within the API. + */ + Csal_libMgmtOps *sal_libMgmtOps; }; +static bool CSenseApiDesc_sanityCheck(const CSenseApiDesc *desc) +{ + if (!desc || !desc->name || desc->numExportedImplexorApis < 1 + ||!desc->exportedImplexorApis || !desc->sal_libMgmtOps) + { + return false; + } + + return true; +} + +static bool CExportedImplexorApiDesc_sanityCheck( + const CExportedImplexorApiDesc *desc) +{ + if (!desc || !desc->name) + { + return false; + } + + return true; +} + +static bool Csal_libMgmtOps_sanityCheck(const Csal_libMgmtOps *ops) +{ + if (!ops || !ops->initializeInd || !ops->finalizeInd + || !ops->attachDeviceReq || !ops->detachDeviceReq) + { + return false; + } + + return true; +} + #define HK_GET_SENSE_API_DESC_FN_NAME getSenseApiDesc #define HK_GET_SENSE_API_DESC_FN_NAME_STR \ HK_QUOTE(HK_GET_SENSE_API_DESC_FN_NAME) diff --git a/senseApis/xcbXorg/xcbXorg.cpp b/senseApis/xcbXorg/xcbXorg.cpp index 94204ca..8ac5c01 100644 --- a/senseApis/xcbXorg/xcbXorg.cpp +++ b/senseApis/xcbXorg/xcbXorg.cpp @@ -8,16 +8,29 @@ static CExportedImplexorApiDesc xcbXorgExportedImplexorApis[] = { { .name = "video-implexor" - }, - { - .name = NULL } }; +static sal_lmo_initializeIndFn xcbXorg_initializeInd; +static sal_lmo_finalizeIndFn xcbXorg_finalizeInd; +static sal_lmo_attachDeviceReqFn xcbXorg_attachDeviceReq; +static sal_lmo_detachDeviceReqFn xcbXorg_detachDeviceReq; + +static Csal_libMgmtOps xcbXorgSalLibMgmtOps = +{ + .initializeInd = xcbXorg_initializeInd, + .finalizeInd = xcbXorg_finalizeInd, + .attachDeviceReq = xcbXorg_attachDeviceReq, + .detachDeviceReq = xcbXorg_detachDeviceReq +}; + static CSenseApiDesc xcbXorgApiDesc = { .name = "XcbXorg", - .exportedImplexorApis = xcbXorgExportedImplexorApis + .numExportedImplexorApis = sizeof(xcbXorgExportedImplexorApis) / + sizeof(*xcbXorgExportedImplexorApis), + .exportedImplexorApis = xcbXorgExportedImplexorApis, + .sal_libMgmtOps = &xcbXorgSalLibMgmtOps }; extern HK_UNMANGLED getSenseApiDescFn HK_GET_SENSE_API_DESC_FN_NAME; @@ -26,3 +39,31 @@ const CSenseApiDesc *HK_GET_SENSE_API_DESC_FN_NAME(void) { return &xcbXorgApiDesc; } + +static sal_lmo_initializeIndFn xcbXorg_initializeInd; +int xcbXorg_initializeInd(void) +{ + std::cerr << "XcbXorg::sal_lmo_initializeInd\n"; + return 0; +} + +static sal_lmo_finalizeIndFn xcbXorg_finalizeInd; +int xcbXorg_finalizeInd(void) +{ + std::cerr << "XcbXorg::sal_lmo_finalizeInd\n"; + return 0; +} + +static sal_lmo_attachDeviceReqFn xcbXorg_attachDeviceReq; +int xcbXorg_attachDeviceReq(void) +{ + std::cerr << "XcbXorg::sal_lmo_attachDeviceReq\n"; + return 0; +} + +static sal_lmo_detachDeviceReqFn xcbXorg_detachDeviceReq; +int xcbXorg_detachDeviceReq(void) +{ + std::cerr << "XcbXorg::sal_lmo_detachDeviceReq\n"; + return 0; +}