Summary: http://rpg.ifi.uzh.ch/docs/glog.html Second phase before tests complete. Delete logging test. Finish relase loging. Reviewers: mislav.bradac, teon.banek, buda Reviewed By: teon.banek Subscribers: buda, pullbot Differential Revision: https://phabricator.memgraph.io/D500
133 lines
4.3 KiB
C++
133 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <experimental/filesystem>
|
|
namespace fs = std::experimental::filesystem;
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include "utils/exceptions.hpp"
|
|
|
|
namespace utils {
|
|
|
|
/**
|
|
* @brief Exception raised by @c DynamicLib.
|
|
*/
|
|
class DynamicLibException : public utils::BasicException {
|
|
public:
|
|
using utils::BasicException::BasicException;
|
|
};
|
|
|
|
/**
|
|
* DynamicLib is a wrapper aroung dynamic object returned by dlopen.
|
|
*
|
|
* Dynamic object must have extern C functions which names should be
|
|
* "produce" and "destruct" (that's by convention).
|
|
*
|
|
* The functions prototypes can be defined with template parameter
|
|
* type trait (T).
|
|
*
|
|
* DynamicLib isn't implemented for concurrent access.
|
|
*
|
|
* @tparam T type trait which defines the prototypes of extern C functions
|
|
* of undelying dynamic object.
|
|
*/
|
|
template <typename T>
|
|
class DynamicLib {
|
|
public:
|
|
/**
|
|
* Initializes dynamic library (loads lib, produce and
|
|
* destruct functions)
|
|
*
|
|
* @param lib_path file system path to dynamic library
|
|
*/
|
|
DynamicLib(const fs::path &lib_path)
|
|
: lib_path(lib_path), lib_object(nullptr) {
|
|
// load dynamic lib
|
|
// I've added the RTL_DEEPBIND flag when we are opening the dynamic_lib to
|
|
// resolve symbols locally instead of globally. For additional information
|
|
// take a look at: http://man7.org/linux/man-pages/man3/dlopen.3.html
|
|
dynamic_lib = dlopen(lib_path.c_str(), RTLD_NOW | RTLD_DEEPBIND);
|
|
if (!dynamic_lib) throw DynamicLibException(dlerror());
|
|
dlerror(); /* Clear any existing error */
|
|
DLOG(INFO) << "dynamic lib at ADDRESS " << dynamic_lib << " was opened";
|
|
|
|
// load produce method
|
|
this->produce_method =
|
|
(typename T::ProducePrototype)dlsym(dynamic_lib, "produce");
|
|
const char *dlsym_produce_error = dlerror();
|
|
if (dlsym_produce_error) throw DynamicLibException(dlsym_produce_error);
|
|
|
|
// load destruct method
|
|
this->destruct_method =
|
|
(typename T::DestructPrototype)dlsym(dynamic_lib, "destruct");
|
|
const char *dlsym_destruct_error = dlerror();
|
|
if (dlsym_destruct_error) throw DynamicLibException(dlsym_destruct_error);
|
|
}
|
|
|
|
// becuase we are dealing with pointers
|
|
// and conceptualy there is no need to copy the instance of this class
|
|
// the copy constructor and copy assignment operator are deleted
|
|
// the same applies to move methods
|
|
DynamicLib(const DynamicLib &other) = delete;
|
|
DynamicLib &operator=(const DynamicLib &other) = delete;
|
|
DynamicLib(DynamicLib &&other) = delete;
|
|
DynamicLib &operator=(DynamicLib &&other) = delete;
|
|
|
|
/**
|
|
* Singleton method. Returns the same instance of underlying class
|
|
* for every call. The instance of underlying class is returned by
|
|
* extern C produce function.
|
|
*
|
|
* @return T the instance of lib class
|
|
*/
|
|
typename T::ObjectPrototype *instance() {
|
|
if (lib_object == nullptr) lib_object = this->produce_method();
|
|
return lib_object;
|
|
}
|
|
|
|
/**
|
|
* Clean underlying object and close the lib
|
|
*/
|
|
~DynamicLib() {
|
|
// first destroy underlying object
|
|
if (lib_object != nullptr) {
|
|
DLOG(INFO) << "shared object at ADDRESS " << (void *)lib_object
|
|
<< " will be destroyed.";
|
|
this->destruct_method(lib_object);
|
|
}
|
|
|
|
// then destroy dynamic lib
|
|
DLOG(INFO) << "unloading lib " << lib_path.c_str();
|
|
if (dynamic_lib != nullptr) {
|
|
DLOG(INFO) << "closing dynamic lib ADDRESS " << (void *)dynamic_lib;
|
|
// // IMPORTANT: weird problem the program SEGFAULT on dlclose
|
|
// // TODO: FIX somehow
|
|
// // maybe something similar is:
|
|
// //
|
|
// http://stackoverflow.com/questions/6450828/segmentation-fault-when-using-dlclose-on-android-platform
|
|
// // for now it is not crucial so I've created a task for that
|
|
// // ! 0 is success
|
|
// Return early because dlclose seems to be casuing the problem again. So
|
|
// strange.
|
|
return;
|
|
int closing_status = dlclose(dynamic_lib);
|
|
if (closing_status != 0) throw DynamicLibException(dlerror());
|
|
} else {
|
|
DLOG(WARNING) << "unload lib was called but lib ptr is null";
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::string lib_path;
|
|
void *dynamic_lib;
|
|
typename T::ObjectPrototype *lib_object;
|
|
typename T::ProducePrototype produce_method;
|
|
typename T::DestructPrototype destruct_method;
|
|
};
|
|
|
|
} // namespace utils
|