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.
This commit is contained in:
@@ -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<const CSenseApiDesc> cDescriptor;
|
||||
std::string name;
|
||||
// These options affect the sense api lib's behaviour globally.
|
||||
std::vector<std::string> options;
|
||||
// These are the implexors whose APIs this lib exports.
|
||||
std::vector<ExportedImplexorApiDesc> 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<void(*)(void*)>(&dlclose))
|
||||
dlopen_handle(
|
||||
_dlopen_handle, reinterpret_cast<void(*)(void*)>(&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<void, void(*)(void*)> handle;
|
||||
std::unique_ptr<void, void(*)(void*)> dlopen_handle;
|
||||
/* UNIMPLEMENTED: API-specific cmdline options. These affect this specific
|
||||
* sense api lib's behaviour globally.
|
||||
*/
|
||||
std::vector<std::string> 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<getSenseApiDescFn> getSenseApiDescriptor;
|
||||
std::function<getSenseApiDescFn> 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<SenseApiDesc> apiDescriptor;
|
||||
SenseApiDesc senseApiDesc;
|
||||
};
|
||||
|
||||
} // namespace sense_api
|
||||
|
||||
@@ -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<std::string> findLibraryPath(
|
||||
const std::string& libraryPath)
|
||||
{
|
||||
@@ -50,20 +58,22 @@ static std::optional<std::string> findLibraryPath(
|
||||
|
||||
SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath)
|
||||
{
|
||||
const CSenseApiDesc *libApiDesc;
|
||||
std::optional<std::string> fullPath = findLibraryPath(libraryPath);
|
||||
auto lib = std::make_unique<SenseApiLib>(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<void, DlCloser>(
|
||||
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<getSenseApiDescFn *>(
|
||||
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<SenseApiLib>(
|
||||
libraryPath, dlopen_handle.release(), func);
|
||||
lib->setSenseApiDesc(libApiDesc);
|
||||
senseApiLibs.push_back(std::move(lib));
|
||||
return *senseApiLibs.back();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user