summaryrefslogtreecommitdiffstats
path: root/util/system/dynlib.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/dynlib.cpp
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/dynlib.cpp')
-rw-r--r--util/system/dynlib.cpp138
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);
+}