feat: begin work for linux compile

This commit is contained in:
Hyblocker committed 2026-05-29 01:11:17 +02:00
1 parent 1420bec65b
commit 9998022fb5
18 files changed
+724 -90

No files matched your search

+2
View File
@@ -21,6 +21,8 @@ endfunction()
# windows prefers win8.1 sdk instead of win 10 sdk for some god forsaken reason
if(WIN32)
set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "Forcing Win10 SDK" FORCE)
else()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
project("SpaceCalibrator")
+20 -1
View File
@@ -3,7 +3,7 @@
#include <string>
#include <filesystem>
#ifdef _WIN32
#if defined(_WIN32)
#define OS_WINDOWS 1
#define OS_LINUX 0
#elif (defined(__gnu_linux__) || defined(__linux__))
@@ -13,6 +13,22 @@
#error "Unsupported OS"
#endif
#if defined(__clang__)
#define COMPILER_MSVC 0
#define COMPILER_GCC 0
#define COMPILER_CLANG 1
#elif defined(_MSC_VER)
#define COMPILER_MSVC 1
#define COMPILER_GCC 0
#define COMPILER_CLANG 0
#elif defined(__GNUC__)
#define COMPILER_MSVC 0
#define COMPILER_GCC 1
#define COMPILER_CLANG 0
#else
#error "Unknown compiler"
#endif
// warning guards for various compilers
#if defined(__clang__)
#define BEGIN_EXTERNAL_HEADERS \
@@ -55,4 +71,7 @@ namespace platform {
void showMessageDialog(const std::string& title, const std::string& message);
void setThreadName(const std::string& threadName);
// utf8 stuff for imgui -> overlay -> os interop
}
+188
View File
@@ -0,0 +1,188 @@
#include "platform.h"
#if OS_LINUX
#include "log.h"
#include "constants.h"
#include <stdlib.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
namespace platform {
constexpr int INVALID_FD = -1;
std::filesystem::path getUserConfigDir() {
// based on XDG base dir spec for XDG_DATA_HOME
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
const char* szXdgConfigHome = getenv("XDG_DATA_HOME");
if (szXdgConfigHome != nullptr && szXdgConfigHome[0] != '\0') {
return std::filesystem::path(szXdgConfigHome);
}
szXdgConfigHome = getenv("HOME");
if (szXdgConfigHome != nullptr && szXdgConfigHome[0] != '\0') {
return std::filesystem::path(szXdgConfigHome) / ".local" / "share";
}
struct passwd* user_db_entry = getpwuid(getuid());
if (user_db_entry) {
szXdgConfigHome = user_db_entry->pw_dir;
}
if (szXdgConfigHome != nullptr && szXdgConfigHome[0] != '\0') {
return std::filesystem::path(szXdgConfigHome) / ".local" / "share";
}
return std::filesystem::path();
}
std::filesystem::path getRuntimeDir() {
// based on XDG base dir spec for XDG_RUNTIME_DIR
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
const char* szXdgRuntimeDir = getenv("XDG_RUNTIME_DIR");
if (szXdgRuntimeDir != nullptr && szXdgRuntimeDir[0] != '\0') {
return std::filesystem::path(szXdgRuntimeDir);
}
LOG_WARN("XDG_RUNTIME_DIR is not set, falling back to /tmp/spacecalibrator-runtime-{}", getuid());
std::filesystem::path fallback = std::filesystem::path("/tmp") / ("spacecalibrator-runtime-" + std::to_string(getuid()));
std::error_code ec;
std::filesystem::create_directories(fallback, ec);
if (ec) {
LOG_ERROR("Failed to create runtime dir fallback {}: {}", fallback.string(), ec.message());
return std::filesystem::path();
}
if (chmod(fallback.c_str(), 0700) != 0) {
LOG_ERROR("Failed to set permissions on runtime dir fallback {}: {}", fallback.string(), strerror(errno));
}
return fallback;
}
std::filesystem::path getExeDir() {
std::error_code ec;
std::filesystem::path exePath = std::filesystem::canonical("/proc/self/exe", ec);
if (ec) {
return std::filesystem::path();
}
return exePath;
}
std::string getEnvVariable(const std::string& szEnvVarName) {
const char* szEnvVar = std::getenv(szEnvVarName.c_str());
return szEnvVar ? std::string(szEnvVar) : "";
}
constexpr const char* s_STEAM_MUTEX_KEY = "/MUTEX__SpaceCalibrator_Steam.lock";
int s_hSteamMutex = INVALID_FD; // flock on linux
bool s_isGitHubVersionInstalled = false;
bool isAnotherInstanceRunning(bool& bIsRunningViaSteam) {
bIsRunningViaSteam = false;
std::string szSteamAppIdEnv = getEnvVariable("SteamAppId");
if (spacecal::c_SPACE_CALIBRATOR_STEAM_APP_ID == szSteamAppIdEnv ||
spacecal::c_STEAMVR_STEAM_APP_ID == szSteamAppIdEnv) {
// We got launched via the Steam client UI.
bIsRunningViaSteam = true;
std::filesystem::path szRuntimeDir = getRuntimeDir();
std::string szLockPath = (szRuntimeDir / "spacecalibrator_steam.lock").string();
s_hSteamMutex = open(szLockPath.c_str(), O_CREAT | O_RDWR, 0666);
if (s_hSteamMutex == INVALID_FD) {
return false;
}
if (flock(s_hSteamMutex, LOCK_EX | LOCK_NB) == INVALID_FD) {
if (errno == EWOULDBLOCK) {
close(s_hSteamMutex);
s_hSteamMutex = INVALID_FD;
return true;
}
}
return false;
}
return false;
}
void shutdownCurrentInstance() {
if (s_hSteamMutex != INVALID_FD) {
flock(s_hSteamMutex, LOCK_UN);
close(s_hSteamMutex);
s_hSteamMutex = INVALID_FD;
}
}
void showMessageDialog(const std::string& title, const std::string& message) {
LOG_INFO("displaying dialog [{}]: {}", title, message);
pid_t pid = fork();
if (pid == 0) {
// child process
// redirect stderr to /dev/null to keep the console clean if tools are missing
int nullFd = open("/dev/null", O_WRONLY);
dup2(nullFd, STDERR_FILENO);
close(nullFd);
// try invoking cli tools which provide a gui
// order of choice -> KDE -> GNOME -> notification
char* kdialogArgs[] = {
(char*)"kdialog",
(char*)"--title", (char*)title.c_str(),
(char*)"--error", (char*)message.c_str(),
nullptr
};
execvp(kdialogArgs[0], kdialogArgs);
char* zenityArgs[] = {
(char*)"zenity",
(char*)"--error",
(char*)"--title", (char*)title.c_str(),
(char*)"--text", (char*)message.c_str(),
(char*)"--width=300",
nullptr
};
execvp(zenityArgs[0], zenityArgs);
char* notifySendArgs[] = {
(char*)"notify-send",
(char*)title.c_str(),
(char*)message.c_str(),
nullptr
};
execvp(notifySendArgs[0], notifySendArgs);
// terminate if we failed to switch to any of the above tools
_exit(1);
}
else if (pid > 0) {
// parent process - wait for the user to dismiss the dialog
int status = 0;
waitpid(pid, &status, 0);
} else {
// fork failed
LOG_CRITICAL("Failed to fork process for message dialog.");
}
}
void setThreadName(const std::string& threadName) {
// thread name has max 16 chars
// https://man7.org/linux/man-pages/man3/pthread_setname_np.3.html
std::string truncatedName = threadName.substr(0, 15);
pthread_setname_np(pthread_self(), truncatedName.c_str());
}
}
#endif
+1
View File
@@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <inttypes.h>
#if !defined(_OPENVR_API)
+37 -14
View File
@@ -13,10 +13,12 @@ set(TARGET_NAME 01spacecalibrator)
# This is the name that the binary will be called (driver_01spacecalibrator)
set(DRIVER_NAME "driver_${TARGET_NAME}")
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
endforeach()
if (WIN32)
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
endforeach()
endif()
function(GroupSourcesByFolder target)
set(SOURCE_GROUP_DELIMITER "/")
@@ -59,7 +61,14 @@ message(STATUS "Compilation set for ${PLATFORM}bits architectures.")
# OpenVR compatibility checking
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_definitions(-DLINUX -DPOSIX)
set(ARCH_TARGET linux64)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(ARCH_TARGET linux_arm64)
add_definitions(-DLINUXARM64)
else()
set(ARCH_TARGET linux64)
add_definitions(-DLINUX64)
endif()
if (${PLATFORM} MATCHES 32)
message(WARNING "OpenVR x86 binaries not provided on GNU/Linux.")
@@ -103,6 +112,7 @@ foreach(SOURCE IN ITEMS ${SOURCES_API})
endforeach()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_BINARY_DIR}/${DRIVER_NAME}/bin/${ARCH_TARGET}>)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $<1:${CMAKE_BINARY_DIR}/${DRIVER_NAME}/bin/${ARCH_TARGET}>)
add_library(SpaceCalibratorDriver SHARED ${SOURCES_API} ${SOURCES_HEADERS})
GroupSourcesByFolder(SpaceCalibratorDriver)
@@ -114,7 +124,6 @@ target_include_directories(SpaceCalibratorDriver
PRIVATE ${OPENVR_LIB_DIR}
PUBLIC ${CMAKE_SOURCE_DIR}/vendor
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/openvr/headers
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/minhook/include
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/quill/include
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/fmt/include
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/glaze/include
@@ -123,26 +132,40 @@ target_include_directories(SpaceCalibratorDriver
target_link_libraries(SpaceCalibratorDriver
PRIVATE SpaceCalibratorCommon
PRIVATE ${OPENVR_LIBRARIES}
PRIVATE minhook
PRIVATE fmt
PRIVATE quill
PRIVATE kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 oleaut32 uuid odbc32 odbccp32
)
target_compile_definitions(SpaceCalibratorDriver
PRIVATE $<$<CONFIG:Debug>:_DEBUG>
PRIVATE $<$<CONFIG:Release>:NDEBUG>
PRIVATE _WINDOWS
PRIVATE _USRDLL
PRIVATE NOMINMAX
PRIVATE UNICODE
PRIVATE EIGEN_HAS_STD_RESULT_OF=0
PRIVATE _CRT_SECURE_NO_WARNINGS
PRIVATE IS_DRIVER
)
if (WIN32)
target_include_directories(SpaceCalibratorDriver
PUBLIC ${CMAKE_SOURCE_DIR}/vendor/minhook/include)
target_link_libraries(SpaceCalibratorDriver
PRIVATE minhook
PRIVATE kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 oleaut32 uuid odbc32 odbccp32
)
target_compile_definitions(SpaceCalibratorDriver
PRIVATE _WINDOWS
PRIVATE _USRDLL
PRIVATE NOMINMAX
PRIVATE UNICODE
PRIVATE _CRT_SECURE_NO_WARNINGS
)
endif()
set_target_properties(SpaceCalibratorDriver PROPERTIES OUTPUT_NAME ${DRIVER_NAME})
set_target_properties(SpaceCalibratorOverlay PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
if (WIN32)
set_target_properties(SpaceCalibratorOverlay PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
endif()
# Copy driver assets to output folder
add_custom_command(
+66 -4
View File
@@ -1,10 +1,19 @@
#pragma once
#include <MinHook.h>
#include <string>
#include <map>
#include "log.h"
#include "platform.h"
#if OS_WINDOWS
#include <MinHook.h>
#elif OS_LINUX
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#define ALIGN_TO_PAGE(addr, pageSize) \
((void*)((uintptr_t)(addr) & ~(uintptr_t)((pageSize) - 1)))
#endif
namespace hooking {
class IHook
@@ -38,6 +47,7 @@ namespace hooking {
// To access the vtable, we simply dereference the object.
void** vtable = *((void***)object);
#if OS_WINDOWS
// The vtable itself is an array of pointers to member functions,
// in the order they were declared in.
targetFunc = vtable[vtableOffset];
@@ -45,34 +55,86 @@ namespace hooking {
auto err = MH_CreateHook(targetFunc, detourFunction, (LPVOID*)&originalFunc);
if (err != MH_OK)
{
LOG_HOOKING_ERROR("Failed to create hook for {}, error: {}", name.c_str(), MH_StatusToString(err));
LOG_HOOKING_ERROR("Failed to create hook for {}, error: {}", name, MH_StatusToString(err));
return false;
}
err = MH_EnableHook(targetFunc);
if (err != MH_OK)
{
LOG_HOOKING_ERROR("Failed to enable hook for {}, error: {}", name.c_str(), MH_StatusToString(err));
LOG_HOOKING_ERROR("Failed to enable hook for {}, error: {}", name, MH_StatusToString(err));
MH_RemoveHook(targetFunc);
return false;
}
#elif OS_LINUX
targetFunc = (void**)&vtable[vtableOffset];
originalFunc = (FuncType)vtable[vtableOffset];
LOG_HOOKING_INFO("Enabled hook for {}", name.c_str());
long pageSize = sysconf(_SC_PAGESIZE);
void* pageStart = ALIGN_TO_PAGE(targetFunc, pageSize);
void* pageEnd = ALIGN_TO_PAGE((uintptr_t)targetFunc + sizeof(void*) - 1, pageSize);
size_t length = (uintptr_t)pageEnd - (uintptr_t)pageStart + pageSize;
if (mprotect(pageStart, length, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
LOG_HOOKING_ERROR("Failed to make vtable writable for {}: {}", name, strerror(errno));
return false;
}
*targetFunc = detourFunction;
#if COMPILER_GCC || COMPILER_CLANG
// https://blog.pathogenstudios.com/rolling-your-own-breakpoints-without-0xcc/
// https://github.com/ridpath/gamehacking-cheatsheet#apple-silicon-rosetta-2-game-reversing
// flush cache -> required for aarch64
// emits no-op on amd64 (done automatically by hardware on amd64 so no need)
__builtin___clear_cache(
reinterpret_cast<char*>(targetFunc),
reinterpret_cast<char*>(targetFunc) + sizeof(void*)
);
#endif // COMPILER_GCC || COMPILER_CLANG
if (mprotect(pageStart, length, PROT_READ | PROT_EXEC) != 0) {
LOG_HOOKING_ERROR("Failed to restore vtable protection for {}: {}", name, strerror(errno));
}
#endif // OS_LINUX
LOG_HOOKING_INFO("Enabled hook for {}", name);
enabled = true;
return true;
}
void Destroy()
{
#if OS_WINDOWS
if (enabled)
{
MH_RemoveHook(targetFunc);
enabled = false;
}
#elif OS_LINUX
if (enabled && targetFunc)
{
long pageSize = sysconf(_SC_PAGESIZE);
void* pageStart = ALIGN_TO_PAGE(targetFunc, pageSize);
void* pageEnd = ALIGN_TO_PAGE((uintptr_t)targetFunc + sizeof(void*) - 1, pageSize);
size_t length = (uintptr_t)pageEnd - (uintptr_t)pageStart + pageSize;
if (mprotect(pageStart, length, PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
*targetFunc = (void*)originalFunc;
mprotect(pageStart, length, PROT_READ | PROT_EXEC);
}
enabled = false;
}
#endif // OS_LINUX
}
private:
bool enabled = false;
#if OS_WINDOWS
void* targetFunc = nullptr;
#elif OS_LINUX
void** targetFunc = nullptr;
#undef ALIGN_TO_PAGE
#endif
};
}
+11
View File
@@ -64,6 +64,7 @@ namespace hooking {
void InjectHooks(spacecal::ServerTrackedDeviceProvider* driver, vr::IVRDriverContext* pDriverContext) {
g_mainDriver = driver;
#if OS_WINDOWS
MH_STATUS err = MH_Initialize();
if (err == MH_OK) {
GetGenericInterfaceHook.CreateHookInObjectVTable(pDriverContext, 0, reinterpret_cast<void*>(&DetourGetGenericInterface));
@@ -74,11 +75,21 @@ namespace hooking {
} else {
LOG_HOOKING_ERROR("MH_Initialize error: {}", MH_StatusToString(err));
}
#elif OS_LINUX
if (GetGenericInterfaceHook.CreateHookInObjectVTable(pDriverContext, 0, reinterpret_cast<void*>(&DetourGetGenericInterface))) {
IHook::Register(&GetGenericInterfaceHook);
LOG_HOOKING_INFO("Space Calibrator hooked into OpenVR PoseUpdate successfully");
} else {
LOG_HOOKING_ERROR("Failed to hook into OpenVR PoseUpdate.");
}
#endif
}
void DisableHooks() {
IHook::DestroyAll();
#if OS_WINDOWS
MH_Uninitialize();
#endif
LOG_HOOKING_INFO("Removed all hooks successfully");
}
}
+1 -1
View File
@@ -120,7 +120,7 @@ namespace ipc {
.szSharedMemoryName = protocol::k_szIpcIdentifier,
.dwSharedBufferSizeBytes = protocol::k_unSharedMemoryElementSize,
.aFunctions = m_funcs,
.dwFunctionCount = _countof(m_funcs),
.dwFunctionCount = IPC_COUNT_OF(m_funcs),
.aOperations = nullptr,
.dwOperationCount = 0,
.userData = this,
+4 -2
View File
@@ -1,10 +1,12 @@
#include <stdio.h>
#include <cstring>
#include "tracked_device_provider.h"
#include "platform.h"
#if defined( _WIN32 )
#if OS_WINDOWS
#define SPACECALIBRATORDRIVER_EXPORT extern "C" __declspec( dllexport )
#define SPACECALIBRATORDRIVER_IMPORT extern "C" __declspec( dllimport )
#elif defined( __GNUC__ ) || defined( COMPILER_GCC ) || defined( __APPLE__ )
#elif COMPILER_GCC || OS_LINUX
#define SPACECALIBRATORDRIVER_EXPORT extern "C" __attribute__( ( visibility( "default" ) ) )
#define SPACECALIBRATORDRIVER_IMPORT extern "C"
#else
+1
View File
@@ -6,6 +6,7 @@
#include "interface_hook_injector.h"
#include "vrmath.h"
#include "virtual_desktop.h"
#include <math.h>
#include <Eigen/Dense>
#include <openvr_driver.h>
+92 -20
View File
@@ -3,10 +3,12 @@ cmake_minimum_required (VERSION 3.8)
project(SpaceCalibratorOverlay CXX)
message("SpaceCalibrator - Overlay")
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
endforeach()
if (WIN32)
foreach(config_type RELEASE RELWITHDEBINFO MINSIZEREL)
set(CMAKE_CXX_FLAGS_${config_type} "${CMAKE_CXX_FLAGS_${config_type}} /Ob2 /Zc:inline")
set(CMAKE_SHARED_LINKER_FLAGS_${config_type} "${CMAKE_SHARED_LINKER_FLAGS_${config_type}} /LTCG /OPT:REF /OPT:ICF")
endforeach()
endif()
function(GroupSourcesByFolder target)
set(SOURCE_GROUP_DELIMITER "/")
@@ -33,6 +35,60 @@ function(GroupSourcesByFolder target)
endif()
endfunction()
set(OPENVR_LIB_DIR ${CMAKE_SOURCE_DIR}/vendor/openvr)
# If not set, determine the platform architecture
if (NOT PLATFORM)
if (CMAKE_SIZEOF_VOID_P MATCHES 8)
set(PLATFORM 64)
else ()
set(PLATFORM 32)
endif ()
endif ()
message(STATUS "Compilation set for ${PLATFORM}bits architectures.")
# OpenVR compatibility checking
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_definitions(-DLINUX -DPOSIX)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(ARCH_TARGET linux_arm64)
add_definitions(-DLINUXARM64)
else()
set(ARCH_TARGET linux64)
add_definitions(-DLINUX64)
endif()
if (${PLATFORM} MATCHES 32)
message(WARNING "OpenVR x86 binaries not provided on GNU/Linux.")
endif ()
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_MACOSX_RPATH 0)
add_definitions(-DOSX -DPOSIX)
set(ARCH_TARGET osx32)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
add_definitions(-D_WIN32)
set(ARCH_TARGET win${PLATFORM})
# Binaries path for thirdparties are not generics so we try to guess their suffixes.
set(WINDOWS_PATH_SUFFIXES win${PLATFORM} Win${PLATFORM} x${PLATFORM})
endif ()
find_library(OPENVR_LIBRARIES
NAMES
openvr_api
PATHS
${OPENVR_LIB_DIR}/bin
${OPENVR_LIB_DIR}/lib
PATH_SUFFIXES
osx${PLATFORM}
linux${PLATFORM}
win${PLATFORM}
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -83,28 +139,33 @@ target_include_directories(SpaceCalibratorOverlay
target_link_libraries(SpaceCalibratorOverlay
PRIVATE SpaceCalibratorCommon
PRIVATE opengl32.lib
PRIVATE dwmapi.lib
PRIVATE imgui
PRIVATE glad
PRIVATE glfw
PRIVATE fmt
PRIVATE quill
PRIVATE ${CMAKE_SOURCE_DIR}/vendor/openvr/lib/win64/openvr_api.lib)
PRIVATE ${OPENVR_LIBRARIES})
target_compile_definitions(SpaceCalibratorOverlay
PRIVATE NOMINMAX
PRIVATE UNICODE
PRIVATE _CRT_SECURE_NO_WARNINGS
PRIVATE IMGUI_DEFINE_MATH_OPERATORS
PRIVATE IS_OVERLAY
)
if (WIN32)
target_link_libraries(SpaceCalibratorOverlay
PRIVATE opengl32.lib
PRIVATE dwmapi.lib)
target_compile_definitions(SpaceCalibratorOverlay
PRIVATE NOMINMAX
PRIVATE UNICODE
PRIVATE _CRT_SECURE_NO_WARNINGS
)
endif()
# Object files are too big with spacecal sooooo
if (MSVC)
target_compile_options(SpaceCalibratorOverlay PRIVATE /bigobj)
else ()
target_compile_options(SpaceCalibratorOverlay PRIVATE -Wa,-mbig-obj)
endif ()
set(OVERLAY_BIN_DIR "$<TARGET_FILE_DIR:SpaceCalibratorOverlay>")
@@ -150,12 +211,21 @@ add_custom_command(
)
# Copy openvr_api.dll
add_custom_command(
TARGET SpaceCalibratorOverlay POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/vendor/openvr/bin/win64/openvr_api.dll
${OVERLAY_BIN_DIR}/openvr_api.dll
)
if (WIN32)
add_custom_command(
TARGET SpaceCalibratorOverlay POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/vendor/openvr/bin/${ARCH_TARGET}/openvr_api.dll
${OVERLAY_BIN_DIR}/openvr_api.dll
)
else()
add_custom_command(
TARGET SpaceCalibratorOverlay POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/vendor/openvr/bin/${ARCH_TARGET}/libopenvr_api.so
${OVERLAY_BIN_DIR}/libopenvr_api.so
)
endif()
# Copy assets to output folder
add_custom_command(
@@ -168,6 +238,8 @@ add_custom_command(
)
# Set as startup project
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT SpaceCalibratorOverlay)
set_property(TARGET SpaceCalibratorOverlay PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${OVERLAY_BIN_DIR}")
if (WIN32)
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT SpaceCalibratorOverlay)
set_property(TARGET SpaceCalibratorOverlay PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${OVERLAY_BIN_DIR}")
endif()
set_target_properties(SpaceCalibratorOverlay PROPERTIES OUTPUT_NAME "SpaceCalibrator")
+1 -1
View File
@@ -32,7 +32,7 @@ namespace ipc {
.szSharedMemoryName = protocol::k_szIpcIdentifier,
.dwSharedBufferSizeBytes = protocol::k_unSharedMemoryElementSize,
.aFunctions = m_funcs,
.dwFunctionCount = _countof(m_funcs),
.dwFunctionCount = IPC_COUNT_OF(m_funcs),
.aOperations = nullptr,
.dwOperationCount = 0,
.userData = this,
@@ -1,5 +1,6 @@
#include "localisation.h"
#if OS_WINDOWS
#include "log.h"
#include <unordered_map>
@@ -384,4 +385,5 @@ namespace spacecal {
return estimatedLocale;
}
} // namespace localisation
} // namespace localisation
#endif // OS_WINDOWS
+8 -8
View File
@@ -4,6 +4,8 @@
#include "platform.h"
#include "util.h"
#include <errno.h>
BEGIN_EXTERNAL_HEADERS
#include <filesystem>
#include <glaze/glaze.hpp>
@@ -116,9 +118,8 @@ namespace spacecal {
auto rootDir = util::getSpaceCalibratorLangsDir();
std::string langPath = (rootDir / (getLocaleAsRegionString(locale) + ".json")).string();
FILE* localeFile = nullptr;
errno_t fileErr = fopen_s(&localeFile, langPath.c_str(), "rb");
switch (fileErr) {
FILE* localeFile = fopen(langPath.c_str(), "rb");
switch (errno) {
case 0: // OK
break;
case ENOENT:
@@ -135,7 +136,7 @@ namespace spacecal {
LOG_WARNING("The locale file \"{0}\" could not be loaded as it was too large.", langPath);
return false;
default:
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, fileErr);
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, errno);
return false;
}
if (localeFile) {
@@ -202,9 +203,8 @@ namespace spacecal {
// fallback to the loaded locale string
m_nativeLanguageNames[locale] = getString(expectedKey);
FILE* file = nullptr;
errno_t fileErr = fopen_s(&file, langPath.c_str(), "rb");
switch (fileErr) {
FILE* file = fopen(langPath.c_str(), "rb");
switch (errno) {
case 0: // OK
break;
case ENOENT:
@@ -221,7 +221,7 @@ namespace spacecal {
LOG_WARNING("The locale file \"{0}\" could not be loaded as it was too large.", langPath);
return;
default:
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, fileErr);
LOG_WARNING("The locale file \"{0}\" could not be loaded due to an unknown error ({1}).", langPath, errno);
return;
}
+11 -1
View File
@@ -1,5 +1,4 @@
#include <stdio.h>
#include <windows.h>
#include "util.h"
#include "window.h"
#include "platform.h"
@@ -8,13 +7,24 @@
#include "localisation.h"
#include "vr_core.h"
#include "log.h"
#if OS_WINDOWS
#include <windows.h>
#endif
#if OS_WINDOWS
// http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
// http://developer.amd.com/community/blog/2015/10/02/amd-enduro-system-for-developers/
extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
#endif
#if OS_WINDOWS
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
#elif OS_LINUX
int main(int argc, char* argv[])
#else
#error "Unsupported platform!"
#endif
{
// Space Calibrator has to be single instance to work well with Steam
bool bIsRunningViaSteam = false;
+14 -2
View File
@@ -1,12 +1,24 @@
#pragma once
#include "platform.h"
#include "ipc_client.h"
#include "calibration.h"
#include <glad/glad.h>
#if OS_WINDOWS
#define GLFW_EXPOSE_NATIVE_WIN32
#elif OS_LINUX
#define GLFW_EXPOSE_NATIVE_WAYLAND
#define GLFW_EXPOSE_NATIVE_X11
#endif
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include "ipc_client.h"
#include "calibration.h"
#if OS_LINUX
#ifdef None
#undef None
#endif
#endif
namespace spacecal {
// handles window creation, setting the icon, and initialising a renderer for UI, also handles connecting it to SteamVR as an overlay
+13 -9
View File
@@ -5,8 +5,10 @@ project("vendor")
# Includes all 3rd party libraries here
# Minhook library
message("Adding minhook...")
add_subdirectory ("minhook")
if (WIN32)
message("Adding minhook...")
add_subdirectory ("minhook")
endif()
# glad
message("Adding glad...")
@@ -53,11 +55,13 @@ message ("Adding glaze...")
add_subdirectory(glaze)
# Assign solution dirs
set_property(TARGET glfw PROPERTY FOLDER "vendor/glfw")
set_property(TARGET update_mappings PROPERTY FOLDER "vendor/glfw")
if (WIN32)
set_property(TARGET glfw PROPERTY FOLDER "vendor/glfw")
set_property(TARGET update_mappings PROPERTY FOLDER "vendor/glfw")
set_property(TARGET minhook PROPERTY FOLDER "vendor")
set_property(TARGET imgui PROPERTY FOLDER "vendor")
set_property(TARGET fmt PROPERTY FOLDER "vendor")
set_property(TARGET quill PROPERTY FOLDER "vendor")
set_property(TARGET glad PROPERTY FOLDER "vendor")
set_property(TARGET minhook PROPERTY FOLDER "vendor")
set_property(TARGET imgui PROPERTY FOLDER "vendor")
set_property(TARGET fmt PROPERTY FOLDER "vendor")
set_property(TARGET quill PROPERTY FOLDER "vendor")
set_property(TARGET glad PROPERTY FOLDER "vendor")
endif()
+251 -26
View File
@@ -43,6 +43,8 @@
// o-----------------o
//
#define IPC_COUNT_OF(arr) (sizeof(arr) / sizeof((arr)[0]))
typedef void* IpcHandle_t;
static const IpcHandle_t k_hInvalidIpcHandle = ((IpcHandle_t)(-1));
typedef uint64_t IpcCommandType_t;
@@ -89,7 +91,20 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
#ifdef IPC_IMPLEMENTATION
#if defined(_WIN32)
#define IPC_OS_WIN32 1
#else
#define IPC_OS_WIN32 0
#endif
#if defined(__gnu_linux__) || defined(__linux__)
#define IPC_OS_LINUX 1
#else
#define IPC_OS_LINUX 0
#endif
#include <stdio.h>
#include <string.h>
#include <vector>
#include <string>
#include <thread>
@@ -100,7 +115,7 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
#define IPC_FUNCTION_ARGS_TOTAL_SIZE (1024*16)
#endif // IPC_FUNCTION_ARGS_TOTAL_SIZE
#if _WIN32
#if IPC_OS_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // WIN32_LEAN_AND_MEAN
@@ -117,6 +132,11 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
#define NOMINMAX
#endif // NOMINMAX
#include <windows.h>
#elif IPC_OS_LINUX
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#endif
struct __internal__IpcFunction_t {
@@ -139,10 +159,14 @@ struct __internal__IpcHandle_t {
void* userData = nullptr;
};
#if IPC_OS_LINUX
#define IPC_S_RW_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#endif
void __internal_ipc_server_poll_requests(IpcHandle_t hIpcServer) {
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcServer;
#if _WIN32
#if IPC_OS_WIN32
while (handleInternal->is_running) {
DWORD result = WaitForSingleObject((HANDLE)handleInternal->hNativeEvent, 100);
@@ -164,6 +188,41 @@ void __internal_ipc_server_poll_requests(IpcHandle_t hIpcServer) {
ReleaseMutex((HANDLE)handleInternal->hNativeMutex);
}
}
#elif IPC_OS_LINUX
sem_t* semEvt = (sem_t*)handleInternal->hNativeEvent;
sem_t* semMtx = (sem_t*)handleInternal->hNativeMutex;
while (handleInternal->is_running) {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) continue;
ts.tv_nsec += 100000000; // 100ms
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec += 1;
ts.tv_nsec -= 1000000000;
}
int res = sem_timedwait(semEvt, &ts);
if (res == 0) {
if (sem_wait(semMtx) == 0) {
IpcCommandType_t* cmdType = (IpcCommandType_t*)handleInternal->pSharedMemory;
void* pArgs = (void*)((char*)handleInternal->pSharedMemory + sizeof(IpcCommandType_t));
for (const auto& func : handleInternal->registed_functions) {
if (func.unCmdType == *cmdType) {
if (func.pfnCallback) {
func.pfnCallback(*cmdType, hIpcServer, pArgs, handleInternal->userData);
}
break;
}
}
sem_post(semMtx);
}
}
else if (errno != ETIMEDOUT && errno != EINTR) {
handleInternal->is_running = false;
}
}
#else
#error "Unsupported platform"
#endif
@@ -184,7 +243,7 @@ IpcHandle_t ipc_server_init(IpcCreateArguments_t args) {
handleInternal->szSharedMemoryName = args.szSharedMemoryName;
size_t totalSharedMemSize = IPC_FUNCTION_ARGS_TOTAL_SIZE + args.dwSharedBufferSizeBytes;
#if _WIN32
#if IPC_OS_WIN32
handleInternal->hSharedMemory = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)totalSharedMemSize, args.szSharedMemoryName);
if (handleInternal->hSharedMemory == NULL) {
free(handleInternal);
@@ -207,6 +266,39 @@ IpcHandle_t ipc_server_init(IpcCreateArguments_t args) {
ipc_server_shutdown(&hIpcHandle);
return k_hInvalidIpcHandle;
}
#elif IPC_OS_LINUX
// shared mem needs a leading / on linux
std::string szSharedMemoryPath = (args.szSharedMemoryName[0] == '/') ? args.szSharedMemoryName : "/" + std::string(args.szSharedMemoryName);
int hSharedMemFd = shm_open(szSharedMemoryPath.c_str(), O_CREAT | O_RDWR, IPC_S_RW_ALL);
if (hSharedMemFd == -1) {
free(handleInternal);
return k_hInvalidIpcHandle;
}
handleInternal->hSharedMemory = (IpcNativeHandle_t)(intptr_t)hSharedMemFd;
ftruncate(hSharedMemFd, totalSharedMemSize);
handleInternal->pSharedMemory = mmap(NULL, totalSharedMemSize, PROT_READ | PROT_WRITE, MAP_SHARED, hSharedMemFd, 0);
if (handleInternal->pSharedMemory == MAP_FAILED) {
close(hSharedMemFd);
free(handleInternal);
return k_hInvalidIpcHandle;
}
std::string mutexName = szSharedMemoryPath + "_FUNC_MTX";
std::string eventName = szSharedMemoryPath + "_FUNC_EVT";
handleInternal->hNativeMutex = (IpcNativeHandle_t)sem_open(mutexName.c_str(), O_CREAT, IPC_S_RW_ALL, 1);
handleInternal->hNativeEvent = (IpcNativeHandle_t)sem_open(eventName.c_str(), O_CREAT, IPC_S_RW_ALL, 0);
if (handleInternal->hNativeMutex == SEM_FAILED || handleInternal->hNativeEvent == SEM_FAILED) {
IpcHandle_t hIpcHandle = ((IpcHandle_t)handleInternal);
ipc_server_shutdown(&hIpcHandle);
return k_hInvalidIpcHandle;
}
#else
#error "Unsupported platform"
#endif
for (size_t i = 0; i < args.dwFunctionCount; ++i) {
const IpcFunction_t& reg = args.aFunctions[i];
@@ -219,9 +311,6 @@ IpcHandle_t ipc_server_init(IpcCreateArguments_t args) {
handleInternal->is_running = true;
handleInternal->poll_thread = std::thread(__internal_ipc_server_poll_requests, (IpcHandle_t)handleInternal);
#else
#error "Unsupported platform"
#endif
return (IpcHandle_t)handleInternal;
}
@@ -239,7 +328,7 @@ IpcHandle_t ipc_client_init(IpcCreateArguments_t args) {
handleInternal->szSharedMemoryName = args.szSharedMemoryName;
#if _WIN32
#if IPC_OS_WIN32
handleInternal->hSharedMemory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, args.szSharedMemoryName);
if (handleInternal->hSharedMemory == NULL) {
free(handleInternal);
@@ -262,6 +351,32 @@ IpcHandle_t ipc_client_init(IpcCreateArguments_t args) {
ipc_client_shutdown(&handleFinal);
return k_hInvalidIpcHandle;
}
#elif IPC_OS_LINUX
std::string szSharedMemoryPath = (args.szSharedMemoryName[0] == '/') ? args.szSharedMemoryName : "/" + std::string(args.szSharedMemoryName);
int hSharedMemFd = shm_open(szSharedMemoryPath.c_str(), O_RDWR, IPC_S_RW_ALL);
if (hSharedMemFd == -1) {
free(handleInternal);
return k_hInvalidIpcHandle;
}
handleInternal->hSharedMemory = (IpcNativeHandle_t)(intptr_t)hSharedMemFd;
struct stat st = {};
fstat(hSharedMemFd, &st);
handleInternal->pSharedMemory = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, hSharedMemFd, 0);
std::string mutexName = szSharedMemoryPath + "_FUNC_MTX";
std::string eventName = szSharedMemoryPath + "_FUNC_EVT";
handleInternal->hNativeMutex = (IpcNativeHandle_t)sem_open(mutexName.c_str(), 1);
handleInternal->hNativeEvent = (IpcNativeHandle_t)sem_open(eventName.c_str(), 0);
if (handleInternal->hNativeMutex == SEM_FAILED || handleInternal->hNativeEvent == SEM_FAILED) {
IpcHandle_t hIpcHandle = ((IpcHandle_t)handleInternal);
ipc_client_shutdown(&hIpcHandle);
return k_hInvalidIpcHandle;
}
#else
#error "Unsupported platform"
#endif
for (size_t i = 0; i < args.dwFunctionCount; ++i) {
const IpcFunction_t& reg = args.aFunctions[i];
@@ -270,9 +385,6 @@ IpcHandle_t ipc_client_init(IpcCreateArguments_t args) {
};
handleInternal->registed_functions.push_back(func);
}
#else
#error "Unsupported platform"
#endif
return (IpcHandle_t)handleInternal;
}
@@ -281,11 +393,11 @@ bool ipc_server_shutdown(IpcHandle_t* hIpcServer) {
if (hIpcServer && *hIpcServer != k_hInvalidIpcHandle) {
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)*hIpcServer;
#if _WIN32
handleInternal->is_running = false;
if (handleInternal->poll_thread.joinable()) {
handleInternal->poll_thread.join();
}
#if IPC_OS_WIN32
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
if (handleInternal->registed_operations[i].hNativeEvent)
@@ -303,6 +415,40 @@ bool ipc_server_shutdown(IpcHandle_t* hIpcServer) {
UnmapViewOfFile(handleInternal->pSharedMemory);
if (handleInternal->hSharedMemory)
CloseHandle(handleInternal->hSharedMemory);
#elif IPC_OS_LINUX
std::string szSharedMemoryPath = (handleInternal->szSharedMemoryName[0] == '/') ? handleInternal->szSharedMemoryName : "/" + std::string(handleInternal->szSharedMemoryName);
if ((sem_t*)handleInternal->hNativeMutex != SEM_FAILED) {
sem_close((sem_t*)handleInternal->hNativeMutex);
sem_unlink((szSharedMemoryPath + "_FUNC_MTX").c_str());
}
if ((sem_t*)handleInternal->hNativeEvent != SEM_FAILED) {
sem_close((sem_t*)handleInternal->hNativeEvent);
sem_unlink((szSharedMemoryPath + "_FUNC_EVT").c_str());
}
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
IpcOperation_t& op = handleInternal->registed_operations[i];
std::string opMutexName = szSharedMemoryPath + "_" + std::string(op.szIdentifier) + "_MTX";
std::string opEventName = szSharedMemoryPath + "_" + std::string(op.szIdentifier) + "_EVT";
if ((sem_t*)op.hNativeMutex != SEM_FAILED) {
sem_close((sem_t*)op.hNativeMutex);
sem_unlink(opMutexName.c_str());
}
if ((sem_t*)op.hNativeEvent != SEM_FAILED) {
sem_close((sem_t*)op.hNativeEvent);
sem_unlink(opEventName.c_str());
}
}
if (handleInternal->pSharedMemory) {
struct stat st = {};
fstat((int)(intptr_t)handleInternal->hSharedMemory, &st);
munmap(handleInternal->pSharedMemory, st.st_size);
}
if (handleInternal->hSharedMemory)
close((int)(intptr_t)handleInternal->hSharedMemory);
shm_unlink(szSharedMemoryPath.c_str());
#else
#error "Unsupported platform"
#endif
@@ -317,7 +463,7 @@ bool ipc_client_shutdown(IpcHandle_t* hIpcClient) {
if (hIpcClient && *hIpcClient != k_hInvalidIpcHandle) {
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)*hIpcClient;
#if _WIN32
#if IPC_OS_WIN32
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
if (handleInternal->registed_operations[i].hNativeEvent)
CloseHandle((HANDLE)handleInternal->registed_operations[i].hNativeEvent);
@@ -334,6 +480,29 @@ bool ipc_client_shutdown(IpcHandle_t* hIpcClient) {
UnmapViewOfFile(handleInternal->pSharedMemory);
if (handleInternal->hSharedMemory)
CloseHandle(handleInternal->hSharedMemory);
#elif IPC_OS_LINUX
std::string szSharedMemoryPath = (handleInternal->szSharedMemoryName[0] == '/') ? handleInternal->szSharedMemoryName : "/" + std::string(handleInternal->szSharedMemoryName);
for (size_t i = 0; i < handleInternal->registed_operations.size(); ++i) {
IpcOperation_t& op = handleInternal->registed_operations[i];
if ((sem_t*)op.hNativeMutex != SEM_FAILED)
sem_close((sem_t*)op.hNativeMutex);
if ((sem_t*)op.hNativeEvent != SEM_FAILED)
sem_close((sem_t*)op.hNativeEvent);
}
if ((sem_t*)handleInternal->hNativeMutex != SEM_FAILED)
sem_close((sem_t*)handleInternal->hNativeMutex);
if ((sem_t*)handleInternal->hNativeEvent != SEM_FAILED)
sem_close((sem_t*)handleInternal->hNativeEvent);
if (handleInternal->pSharedMemory) {
struct stat st = {};
fstat((int)(intptr_t)handleInternal->hSharedMemory, &st);
munmap(handleInternal->pSharedMemory, st.st_size);
}
if (handleInternal->hSharedMemory)
close((int)(intptr_t)handleInternal->hSharedMemory);
#else
#error "Unsupported platform"
#endif
@@ -363,14 +532,23 @@ bool ipc_client_dispatch_function(IpcHandle_t hIpcClient, IpcCommandType_t unCmd
return false;
}
#if _WIN32
#if IPC_OS_WIN32
WaitForSingleObject((HANDLE)handleInternal->hNativeMutex, INFINITE);
void* pSharedMem = handleInternal->pSharedMemory;
*((IpcCommandType_t*)pSharedMem) = unCmdType;
memcpy((char*)pSharedMem + sizeof(IpcCommandType_t), pArgs, dwArgsSize);
SetEvent((HANDLE)handleInternal->hNativeEvent);
WaitForSingleObject((HANDLE)handleInternal->hNativeEvent, INFINITE);
ReleaseMutex((HANDLE)handleInternal->hNativeMutex);
#elif IPC_OS_LINUX
sem_t* semMtx = (sem_t*)handleInternal->hNativeMutex;
sem_t* semEvt = (sem_t*)handleInternal->hNativeEvent;
sem_wait(semMtx);
void* pSharedMem = handleInternal->pSharedMemory;
*((IpcCommandType_t*)pSharedMem) = unCmdType;
memcpy((char*)pSharedMem + sizeof(IpcCommandType_t), pArgs, dwArgsSize);
sem_post(semEvt);
sem_post(semMtx);
#else
#error "Unsupported platform"
#endif
@@ -384,7 +562,7 @@ bool ipc_server_register_operation(IpcHandle_t hIpcServer, IpcOperation_t* ipcOp
}
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcServer;
#if _WIN32
#if IPC_OS_WIN32
std::string mutexName = std::string(handleInternal->szSharedMemoryName) + "_" + std::string(ipcOperation->szIdentifier) + "_MTX";
std::string eventName = std::string(handleInternal->szSharedMemoryName) + "_" + std::string(ipcOperation->szIdentifier) + "_EVT";
@@ -398,12 +576,31 @@ bool ipc_server_register_operation(IpcHandle_t hIpcServer, IpcOperation_t* ipcOp
CloseHandle((HANDLE)ipcOperation->hNativeEvent);
return false;
}
#elif IPC_OS_LINUX
std::string szSharedMemoryPath = (handleInternal->szSharedMemoryName[0] == '/') ? handleInternal->szSharedMemoryName : "/" + std::string(handleInternal->szSharedMemoryName);
std::string mutexName = szSharedMemoryPath + "_" + std::string(ipcOperation->szIdentifier) + "_MTX";
std::string eventName = szSharedMemoryPath + "_" + std::string(ipcOperation->szIdentifier) + "_EVT";
handleInternal->registed_operations.push_back(*ipcOperation);
ipcOperation->hNativeMutex = (IpcNativeHandle_t)sem_open(mutexName.c_str(), O_CREAT, IPC_S_RW_ALL, 1);
ipcOperation->hNativeEvent = (IpcNativeHandle_t)sem_open(eventName.c_str(), O_CREAT, IPC_S_RW_ALL, 0);
if (ipcOperation->hNativeMutex == SEM_FAILED || ipcOperation->hNativeEvent == SEM_FAILED) {
if ((sem_t*)ipcOperation->hNativeMutex != SEM_FAILED) {
sem_close((sem_t*)ipcOperation->hNativeMutex);
sem_unlink(mutexName.c_str());
}
if ((sem_t*)ipcOperation->hNativeEvent != SEM_FAILED) {
sem_close((sem_t*)ipcOperation->hNativeEvent);
sem_unlink(eventName.c_str());
}
return false;
}
#else
#error "Unsupported platform"
#endif
handleInternal->registed_operations.push_back(*ipcOperation);
return true;
}
@@ -415,16 +612,31 @@ bool ipc_server_write_shared_memory(IpcHandle_t hIpcServer, IpcOperation_t ipcOp
return false;
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcServer;
#if _WIN32
#if IPC_OS_WIN32
DWORD ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeMutex, 10);
if (ret == WAIT_TIMEOUT) {
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
return false;
}
void* pDest = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
memcpy(pDest, pSrc, destSize);
SetEvent((HANDLE)ipcOperation.hNativeEvent);
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
#elif IPC_OS_LINUX
sem_t* semMtx = (sem_t*)ipcOperation.hNativeMutex;
sem_t* semEvt = (sem_t*)ipcOperation.hNativeEvent;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_nsec += 10000000; // 10ms
if (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; }
if (sem_timedwait(semMtx, &ts) != 0) {
return false;
}
void* pDest = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
memcpy(pDest, pSrc, destSize);
sem_post(semEvt);
sem_post(semMtx);
#else
#error "Unsupported platform"
#endif
@@ -440,20 +652,29 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
return false;
__internal__IpcHandle_t* handleInternal = (__internal__IpcHandle_t*)hIpcClient;
#if _WIN32
DWORD ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeEvent, 10);
#if IPC_OS_WIN32
DWORD ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeMutex, 10);
if (ret == WAIT_TIMEOUT) {
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
return false;
}
ret = WaitForSingleObject((HANDLE)ipcOperation.hNativeMutex, 10);
if (ret == WAIT_TIMEOUT) {
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
return false;
}
void* pSrc = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
memcpy(pDest, pSrc, destSize);
ReleaseMutex((HANDLE)ipcOperation.hNativeMutex);
#elif IPC_OS_LINUX
sem_t* semMtx = (sem_t*)ipcOperation.hNativeMutex;
sem_t* semEvt = (sem_t*)ipcOperation.hNativeEvent;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_nsec += 10000000;
if (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; }
if (sem_timedwait(semMtx, &ts) != 0) {
return false;
}
void* pSrc = (char*)handleInternal->pSharedMemory + IPC_FUNCTION_ARGS_TOTAL_SIZE + ipcOperation.dwSharedMemoryOffset;
memcpy(pDest, pSrc, destSize);
sem_post(semMtx);
#else
#error "Unsupported platform"
#endif
@@ -461,5 +682,9 @@ bool ipc_client_read_shared_memory(IpcHandle_t hIpcClient, IpcOperation_t ipcOpe
return true;
}
#if IPC_OS_LINUX
#undef IPC_S_RW_ALL
#endif
#endif // IPC_IMPLEMENTATION
#endif // HEKKY_IPC_INC