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