214 lines
5.1 KiB
C++
214 lines
5.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>
|
|
#include <time.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
|
|
|
|
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<std::uint64_t>(time.tv_nsec);
|
|
}();
|
|
};
|
|
#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
|
|
}
|
|
|
|
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<std::uint64_t>(time.tv_sec) * 1e9 + time.tv_nsec) / gCPUClockResolution;
|
|
#else
|
|
MIJIN_ERROR("TODO");
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
std::uint64_t getCPUTicksPerSecond() MIJIN_NOEXCEPT
|
|
{
|
|
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
|
return 1e9 / gCPUClockResolution;
|
|
#else
|
|
MIJIN_ERROR("TODO");
|
|
return 0;
|
|
#endif
|
|
}
|
|
} // namespace mijin
|