#include "os.hpp" #include #include "../debug/assert.hpp" #if MIJIN_TARGET_OS == MIJIN_OS_LINUX #include #include #include #include #include #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS #include #include #include #include "../util/winundef.hpp" #endif namespace fs = std::filesystem; namespace mijin { // // internal defines // // // internal constants // // // internal types // // // internal variables // #if MIJIN_TARGET_OS == MIJIN_OS_LINUX namespace { std::mutex gDlErrorMutex; // dlerror may not be thread-safe } #endif // MIJIN_TARGET_OS == MIJIN_OS_LINUX // // internal functions // // // public functions // Result openSharedLibrary(std::string_view libraryFile) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX const std::unique_lock dlErrorLock(gDlErrorMutex); dlerror(); // NOLINT(concurrency-mt-unsafe) we take care of that const fs::path libraryPath = fs::absolute(libraryFile); void* ptr = dlopen(libraryPath.c_str(), RTLD_NOW); if (ptr == nullptr) { return ResultError(dlerror()); // NOLINT(concurrency-mt-unsafe) we take care of that } return LibraryHandle{.data = dlopen(libraryPath.c_str(), RTLD_NOW)}; #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS // TODO (void) libraryFile; return {}; #endif } bool closeSharedLibrary(const LibraryHandle library) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX return dlclose(library.data) == 0; #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS (void) library; return true; #endif } void* loadSymbolFromLibrary(const LibraryHandle library, const char* symbolName) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX return dlsym(library.data, symbolName); #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS (void) library; (void) symbolName; return nullptr; #endif } void setCurrentThreadName(const char* threadName) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX pthread_setname_np(pthread_self(), threadName); #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS (void) threadName; #endif } std::string getExecutablePath() MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX return fs::canonical("/proc/self/exe").string(); #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS // TODO: this is completely untested std::array buffer; if (FAILED(GetModuleFileNameA(nullptr, buffer.data(), static_cast(buffer.size())))) { std::vector buffer2; buffer2.resize(1024); do { if (buffer2.size() >= 10240) { MIJIN_ERROR("Something is wrong."); return ""; } buffer2.resize(buffer2.size() + 1024); } while (FAILED(GetModuleFileNameA(nullptr, buffer.data(), static_cast(buffer.size())))); return buffer2.data(); } return buffer.data(); #else #endif } [[nodiscard]] std::string makeLibraryFilename(std::string_view libraryName) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX return "lib" + std::string(libraryName) + ".so"; #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS return std::string(libraryName) + ".dll"; #else #endif } void* alignedAlloc(std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS return _aligned_alloc(size, alignment); #else return std::aligned_alloc(alignment, size); #endif } void* alignedRealloc(void* ptr, std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS return _aligned_realloc(ptr, size, alignment); #else void* newPtr = std::realloc(ptr, size); if (newPtr == ptr || (std::bit_cast(newPtr) % alignment) == 0) { return newPtr; } // bad luck, have to copy a second time void* newPtr2 = std::aligned_alloc(alignment, size); std::memcpy(newPtr2, newPtr, size); std::free(newPtr); return newPtr2; #endif } void alignedFree(void* ptr) { #if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS _aligned_free(ptr); #else std::free(ptr); #endif } } // namespace mijin