From 264608b62156b83c342730ccc5b321077e748b4a Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 1 Sep 2024 19:05:02 +0800 Subject: [PATCH] Testing with threads instead of processes under Windows. --- README.md | 1 - src/libipc/CMakeLists.txt | 12 +++++ src/libipc/platform/win/process_impl.h | 71 ++++++++++++++++++++++++++ test/ipc/test_ipc_shm.cpp | 20 +++++++- test/test_util.h | 17 ++++-- 5 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 src/libipc/platform/win/process_impl.h diff --git a/README.md b/README.md index 237a2c7..8ee59ed 100755 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ A high-performance inter-process communication using shared memory on Linux/Wind - [ ] IPC:实现基本组件 - [x] 共享内存(需要作为后续组件的基础) - [x] 原子锁 - - [ ] 进程对象 - [ ] 互斥量 - [ ] 条件变量 - [ ] 信号量 diff --git a/src/libipc/CMakeLists.txt b/src/libipc/CMakeLists.txt index 8ece8b5..5c67bb7 100644 --- a/src/libipc/CMakeLists.txt +++ b/src/libipc/CMakeLists.txt @@ -5,6 +5,14 @@ if(NOT MSVC) -Wno-attributes) endif() +# if(CMAKE_SYSTEM_NAME MATCHES "Windows") +# FetchContent_Declare(phnt +# GIT_REPOSITORY https://github.com/winsiderss/phnt.git +# GIT_TAG master +# ) +# FetchContent_MakeAvailable(phnt) +# endif() + aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc SRC_FILES) file(GLOB HEAD_FILES @@ -47,6 +55,10 @@ else() target_link_libraries(${PROJECT_NAME} PUBLIC imp pmr) endif() +# if(CMAKE_SYSTEM_NAME MATCHES "Windows") +# target_link_libraries(${PROJECT_NAME} PUBLIC phnt) +# endif() + install( TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin diff --git a/src/libipc/platform/win/process_impl.h b/src/libipc/platform/win/process_impl.h new file mode 100644 index 0000000..3468825 --- /dev/null +++ b/src/libipc/platform/win/process_impl.h @@ -0,0 +1,71 @@ +/** + * \file libipc/platform/win/process_impl.h + * \author mutouyun (orz@orzz.org) + */ +#pragma once + +#include +#include + +#include "libimp/log.h" +#include "libipc/process.h" + +LIBIPC_NAMESPACE_BEG_ +using namespace ::LIBIMP; + +/// \brief Experimental fork() on Windows. +/// \see https://gist.github.com/Cr4sh/126d844c28a7fbfd25c6 +/// https://github.com/huntandhackett/process-cloning +namespace { + +typedef SSIZE_T pid_t; + +pid_t fork() { + LIBIMP_LOG_(); + + RTL_USER_PROCESS_INFORMATION process_info; + NTSTATUS status; + + /* lets do this */ + status = RtlCloneUserProcess(RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES + , NULL, NULL, NULL, &process_info); + if (status == STATUS_PROCESS_CLONED) { + // Executing inside the clone... + // Re-attach to the parent's console to be able to write to it + FreeConsole(); + AttachConsole(ATTACH_PARENT_PROCESS); + return 0; + } else { + // Executing inside the original (parent) process... + if (!NT_SUCCESS(status)) { + log.error("failed: RtlCloneUserProcess(...)"); + return -1; + } + return (pid_t)process_info.ProcessHandle; + } + + /* NOTREACHED */ +} + +#define WNOHANG 1 /* Don't block waiting. */ + +/// \see https://man7.org/linux/man-pages/man3/wait.3p.html +/// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntwaitforsingleobject +pid_t waitpid(pid_t pid, int */*status*/, int options) { + LIBIMP_LOG_(); + if (pid == -1) { + return -1; + } + if (options & WNOHANG) { + return pid; + } + NTSTATUS status = NtWaitForSingleObject((HANDLE)pid, FALSE, NULL); + if (!NT_SUCCESS(status)) { + log.error("failed: NtWaitForSingleObject(...)"); + return -1; + } + return pid; +} + +} // namespace +LIBIPC_NAMESPACE_END_ diff --git a/test/ipc/test_ipc_shm.cpp b/test/ipc/test_ipc_shm.cpp index 249cf37..9a237d0 100644 --- a/test/ipc/test_ipc_shm.cpp +++ b/test/ipc/test_ipc_shm.cpp @@ -3,6 +3,8 @@ #include "libipc/shm.h" +#include "test_util.h" + TEST(shm, open_close) { EXPECT_FALSE(ipc::shm_open("hello-ipc-shm", 1024, ipc::mode::none)); @@ -76,6 +78,22 @@ TEST(shm, shared_memory) { EXPECT_TRUE(ipc::shm_close(*shm_r)); } +TEST(shm, process) { + ipc::shared_memory shm{"ipc-shared-memory-process1", 333}; + ASSERT_TRUE(shm.valid()); + *shm.as() = 4321; + + auto r1 = test::subproc([] { + ipc::shared_memory shm{"ipc-shared-memory-process1"}; + ASSERT_TRUE(shm.valid()); + EXPECT_EQ(*shm.as(), 4321); + *shm.as() = 1234; + }); + + test::join_subproc(r1); + EXPECT_EQ(*shm.as(), 1234); +} + #include #if /*defined(LIBIMP_OS_LINUX)*/ 0 #include @@ -87,8 +105,6 @@ TEST(shm, shared_memory) { #include #include -#include "test_util.h" - TEST(shm, pipe) { auto writer = test::subproc([] { mkfifo("/tmp/shm-pipe.w", S_IFIFO|0666); diff --git a/test/test_util.h b/test/test_util.h index da22ea8..c78d919 100644 --- a/test/test_util.h +++ b/test/test_util.h @@ -6,7 +6,9 @@ # include # include #else -# define pid_t int +# include +# include +# define pid_t uintptr_t #endif #include @@ -15,7 +17,7 @@ namespace test { template -pid_t subproc(Fn&& fn) { +pid_t subproc(Fn &&fn) { #ifndef LIBIMP_OS_WIN pid_t pid = fork(); if (pid == -1) { @@ -31,14 +33,23 @@ pid_t subproc(Fn&& fn) { } return pid; #else - return -1; + auto runner = [](void* pparam) { + auto fn = reinterpret_cast *>(pparam); + (*fn)(); + }; + return _beginthread(runner, 0, (void *)&fn); #endif } inline void join_subproc(pid_t pid) { + if (pid == -1) return; #ifndef LIBIMP_OS_WIN int ret_code; waitpid(pid, &ret_code, 0); +#else + HANDLE hThread = reinterpret_cast(pid); + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); #endif }