aboutsummaryrefslogblamecommitdiffstats
path: root/util/system/dynlib.cpp
blob: 9d2541c25f1c787d112cdc1db6a3a1c86c8b6cd0 (plain) (tree)
1
2
3
4
5


                   
                                   













                                                         
                        




                                                    
                         





                                                                                                                          
                                                                                                                           

                                        
              
                             












                                             
                                                   










                                                                  
 
                     



                                   
                                                         




                                           
                                
                                                   












                                                
                                             
 
                                                                  
                             
 
                                              
 
                                                         
 
                                        

                    
                                                               
                      
                       





                                              
                                                    



                            
                                                 
                             
                                                      
                                     
 
#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);
}