diff options
author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/dynlib.cpp |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/dynlib.cpp')
-rw-r--r-- | util/system/dynlib.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/util/system/dynlib.cpp b/util/system/dynlib.cpp new file mode 100644 index 00000000000..9d2541c25f1 --- /dev/null +++ b/util/system/dynlib.cpp @@ -0,0 +1,138 @@ +#include "dynlib.h" + +#include "guard.h" +#include "mutex.h" +#include <util/generic/singleton.h> +#include <util/generic/yexception.h> + +#ifdef _win32_ + #include "winint.h" + + #define DLLOPEN(path, flags) LoadLibrary(path) + #define DLLCLOSE(hndl) FreeLibrary(hndl) + #define DLLSYM(hndl, name) GetProcAddress(hndl, name) +#else + #include <dlfcn.h> + + #ifndef RTLD_GLOBAL + #define RTLD_GLOBAL (0) + #endif + +using HINSTANCE = void*; + + #define DLLOPEN(path, flags) dlopen(path, flags) + #define DLLCLOSE(hndl) dlclose(hndl) + #define DLLSYM(hndl, name) dlsym(hndl, name) +#endif + +inline TString DLLERR() { +#ifdef _unix_ + return dlerror(); +#endif + +#ifdef _win32_ + char* msg = 0; + DWORD cnt = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, nullptr); + if (!msg) + return "DLLERR() unknown error"; + while (cnt && isspace(msg[cnt - 1])) + --cnt; + TString err(msg, 0, cnt); + LocalFree(msg); + return err; +#endif +} + +class TDynamicLibrary::TImpl { +private: + inline TImpl(const char* path, int flags) + : Module(DLLOPEN(path, flags)) + , Unloadable(true) + { + (void)flags; + + if (!Module) { + ythrow yexception() << DLLERR().data(); + } + } + + class TCreateMutex: public TMutex { + }; + +public: + static inline TImpl* SafeCreate(const char* path, int flags) { + auto guard = Guard(*Singleton<TCreateMutex>()); + + return new TImpl(path, flags); + } + + inline ~TImpl() { + if (Module && Unloadable) { + DLLCLOSE(Module); + } + } + + inline void* SymOptional(const char* name) noexcept { + return (void*)DLLSYM(Module, name); + } + + inline void* Sym(const char* name) { + void* symbol = SymOptional(name); + + if (symbol == nullptr) { + ythrow yexception() << DLLERR().data(); + } + + return symbol; + } + + inline void SetUnloadable(bool unloadable) { + Unloadable = unloadable; + } + +private: + HINSTANCE Module; + bool Unloadable; +}; + +TDynamicLibrary::TDynamicLibrary() noexcept { +} + +TDynamicLibrary::TDynamicLibrary(const TString& path, int flags) { + Open(path.data(), flags); +} + +TDynamicLibrary::~TDynamicLibrary() = default; + +void TDynamicLibrary::Open(const char* path, int flags) { + Impl_.Reset(TImpl::SafeCreate(path, flags)); +} + +void TDynamicLibrary::Close() noexcept { + Impl_.Destroy(); +} + +void* TDynamicLibrary::SymOptional(const char* name) noexcept { + if (!IsLoaded()) { + return nullptr; + } + + return Impl_->SymOptional(name); +} + +void* TDynamicLibrary::Sym(const char* name) { + if (!IsLoaded()) { + ythrow yexception() << "library not loaded"; + } + + return Impl_->Sym(name); +} + +bool TDynamicLibrary::IsLoaded() const noexcept { + return (bool)Impl_.Get(); +} + +void TDynamicLibrary::SetUnloadable(bool unloadable) { + Impl_->SetUnloadable(unloadable); +} |