182 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #include "os.hpp"
 | |
| 
 | |
| #include <filesystem>
 | |
| #include "../debug/assert.hpp"
 | |
| 
 | |
| #if MIJIN_TARGET_OS == MIJIN_OS_LINUX
 | |
|     #include <bit>
 | |
|     #include <cstring>
 | |
|     #include <mutex>
 | |
|     #include <dlfcn.h>
 | |
|     #include <pthread.h>
 | |
| #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
 | |
|     #include <array>
 | |
|     #include <malloc.h>
 | |
|     #include <windows.h>
 | |
|     #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<LibraryHandle> 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<char, 1024> buffer;
 | |
|     if (FAILED(GetModuleFileNameA(nullptr, buffer.data(), static_cast<DWORD>(buffer.size()))))
 | |
|     {
 | |
|         std::vector<char> 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<DWORD>(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_malloc(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<std::uintptr_t>(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
 |