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; +}