memgraph/src/utils/dynamic_lib.hpp
Dominik Gleich e2f3aba332 Use GLogger instead of broken memgraph Logger.
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
2017-06-21 15:33:24 +02:00

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