#include "os.hpp" #include #include "../debug/assert.hpp" #if MIJIN_TARGET_OS == MIJIN_OS_LINUX #include #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 // namespace { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX std::mutex gDlErrorMutex; // dlerror may not be thread-safe const std::uint64_t gCPUClockResolution = []() { struct timespec time; [[maybe_unused]] const int result = clock_getres(CLOCK_PROCESS_CPUTIME_ID, &time); MIJIN_ASSERT(result == 0, "Error getting cputime resolution."); MIJIN_ASSERT(time.tv_sec == 0, "What kind of cpu clock is this?"); return static_cast(time.tv_nsec); }(); #elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS const std::uint64_t gCPUTickFrequency = []() { LARGE_INTEGER ticks; [[maybe_unused]] const BOOL result = QueryPerformanceFrequency(&ticks); MIJIN_ASSERT(result, "Error getting cpu frequency."); return static_cast(ticks.QuadPart); }(); #endif // MIJIN_TARGET_OS == MIJIN_OS_LINUX || MIJIN_TARGET_OS == MIJIN_OS_WINDOWS } // // 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_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(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 } std::uint64_t getCPUTicks() MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX struct timespec time; [[maybe_unused]] const int result = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time); MIJIN_ASSERT(result == 0, "Error getting cpu time."); return (static_cast(time.tv_sec) * 1e9 + time.tv_nsec) / gCPUClockResolution; #else LARGE_INTEGER ticks; [[maybe_unused]] const BOOL result = QueryPerformanceCounter(&ticks); MIJIN_ASSERT(result, "Error getting cpu time."); return static_cast(ticks.QuadPart); #endif } std::uint64_t getCPUTicksPerSecond() MIJIN_NOEXCEPT { #if MIJIN_TARGET_OS == MIJIN_OS_LINUX return 1e9 / gCPUClockResolution; #else return gCPUTickFrequency; #endif } } // namespace mijin