From 693e0288fd3bb73daf596d5f592c64d22a71d1e6 Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:11:18 +0100 Subject: Include POSIX headers on all platforms except Windows --- zencore/thread.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 596549bb5..1d36ba192 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -12,13 +12,12 @@ # include # include # include -#elif ZEN_PLATFORM_LINUX +#else # include # include # include # include -# include # include # include # include @@ -27,6 +26,10 @@ # include #endif +#if ZEN_PLATFORM_LINUX +# include +#endif + #include ZEN_THIRD_PARTY_INCLUDES_START -- cgit v1.2.3 From e08fab20fc49f546e908763be6e7a11228fc68c6 Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:11:50 +0100 Subject: Corrected misleading comment --- zencore/thread.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 1d36ba192..0a6af0406 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -281,9 +281,9 @@ NamedEvent::NamedEvent(std::string_view EventName) int LockResult = flock(Inner, LOCK_EX | LOCK_NB); if (LockResult == 0) { - // This is really thread safe as the message queue could be set between - // getting the exclusive lock and checking the queue. But for the our - // simple synchronising of process, this should be okay. + // This isn't really thread safe as the message queue could be set + // between getting the exclusive lock and checking the queue. But for + // the our simple synchronising of process, this should be okay. while (!IsMessageQueueEmpty(Inner)) { char Sink; -- cgit v1.2.3 From 9ea8768c0799a1670966e41d37fe01f39eccd5bc Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:12:48 +0100 Subject: Timeouts longer than one second wouldn't work as expected --- zencore/thread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 0a6af0406..fc7efa2fc 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -373,8 +373,8 @@ NamedEvent::Wait(int TimeoutMs) } struct timeval TimeoutValue = { - .tv_sec = 0, - .tv_usec = TimeoutMs << 10, + .tv_sec = (TimeoutMs >> 10), + .tv_usec = (TimeoutMs & 0x3ff) << 10, }; struct timeval* TimeoutPtr = (TimeoutMs < 0) ? nullptr : &TimeoutValue; -- cgit v1.2.3 From f062774b87fbd51c7ec4e88ef573c19dcd937fcf Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:13:29 +0100 Subject: Added a trivial test call to GetCurrentThreadId() --- zencore/thread.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index fc7efa2fc..940db1778 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -1081,6 +1081,8 @@ TEST_CASE("Thread") int Pid = GetCurrentProcessId(); CHECK(Pid > 0); CHECK(IsProcessRunning(Pid)); + + CHECK_FALSE(GetCurrentThreadId() == 0); } TEST_CASE("BuildArgV") -- cgit v1.2.3 From a1ebf45b573953ab3c8841694ce4f32ed64613a5 Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:14:43 +0100 Subject: Found some Wayward whitespace --- zencore/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 940db1778..249eee121 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -313,7 +313,7 @@ NamedEvent::Close() #if ZEN_PLATFORM_WINDOWS CloseHandle(m_EventHandle); #elif ZEN_PLATFORM_LINUX - int Inner = int(intptr_t(m_EventHandle)); + int Inner = int(intptr_t(m_EventHandle)); if (flock(Inner, LOCK_EX | LOCK_NB) == 0) { -- cgit v1.2.3 From 3b2b679d3f0f328a4203f478296db0a15b09ca2c Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:15:24 +0100 Subject: Implemented NamedEvents on Mac using System V semaphores --- zencore/thread.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 2 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 249eee121..063b060c9 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -30,6 +30,10 @@ # include #endif +#if ZEN_PLATFORM_MAC +# include +#endif + #include ZEN_THIRD_PARTY_INCLUDES_START @@ -292,8 +296,52 @@ NamedEvent::NamedEvent(std::string_view EventName) } m_EventHandle = (void*)intptr_t(Inner); -#else -# error Implement NamedEvent for this platform +#elif ZEN_PLATFORM_MAC + // Create a file to back the semaphore + ExtendableStringBuilder<64> EventPath; + EventPath << "/tmp/" << EventName; + + int Fd = open(EventPath.c_str(), O_RDWR|O_CREAT, 0644); + if (Fd < 0) + { + using namespace fmt::literals; + ThrowLastError("Failed to create '{}' for named event"_format(EventPath)); + } + + // Use the file path to generate an IPC key + key_t IpcKey = ftok(EventPath.c_str(), 1); + if (IpcKey < 0) + { + close(Fd); + ThrowLastError("Failed to create an SysV IPC key"); + } + + // Use the key to create/open the semaphore + int Sem = semget(IpcKey, 1, 0600 | IPC_CREAT); + if (Sem < 0) + { + close(Fd); + ThrowLastError("Failed creating an SysV semaphore"); + } + + // Atomically claim ownership of the semaphore's key. The owner initialises + // the semaphore to 1 so we can use the wait-for-zero op as that does not + // modify the semaphore's value on a successful wait. + int LockResult = flock(Fd, LOCK_EX | LOCK_NB); + if (LockResult == 0) + { + // This isn't thread safe really. Another thread could open the same + // semaphore and successfully wait on it in the period of time where + // this comment is but before the semaphore's initialised. + semctl(Sem, 0, SETVAL, 1); + } + + // Pack into the handle + static_assert(sizeof(Sem) + sizeof(Fd) <= sizeof(void*), "Semaphore packing assumptions not met"); + intptr_t Packed; + Packed = intptr_t(Sem) << 32; + Packed |= intptr_t(Fd) & 0xffff'ffff; + m_EventHandle = (void*)Packed; #endif } @@ -323,6 +371,20 @@ NamedEvent::Close() } close(Inner); +#elif ZEN_PLATFORM_MAC + int Fd = int(intptr_t(m_EventHandle) & 0xffff'ffff); + + if (flock(Fd, LOCK_EX | LOCK_NB) == 0) + { + std::filesystem::path Name = PathFromHandle((void*)(intptr_t(Fd))); + unlink(Name.c_str()); + + flock(Fd, LOCK_UN | LOCK_NB); + close(Fd); + + int Sem = int(intptr_t(m_EventHandle) >> 32); + semctl(Sem, 0, IPC_RMID); + } #endif m_EventHandle = nullptr; @@ -346,6 +408,9 @@ NamedEvent::Set() { ThrowLastError("Unable to send set message to queue"); } +#elif ZEN_PLATFORM_MAC + int Sem = int(intptr_t(m_EventHandle) >> 32); + semctl(Sem, 0, SETVAL, 0); #endif } @@ -382,6 +447,34 @@ NamedEvent::Wait(int TimeoutMs) FD_ZERO(&FdSet); FD_SET(Inner, &FdSet); return select(Inner + 1, &FdSet, nullptr, nullptr, TimeoutPtr) > 0; +#elif ZEN_PLATFORM_MAC + int Sem = int(intptr_t(m_EventHandle) >> 32); + + int Result; + struct sembuf SemOp = {}; + + if (TimeoutMs < 0) + { + Result = semop(Sem, &SemOp, 1); + return Result == 0; + } + + const int SleepTimeMs = 10; + SemOp.sem_flg = IPC_NOWAIT; + do + { + Result = semop(Sem, &SemOp, 1); + if (Result == 0 || errno != EAGAIN) + { + break; + } + + Sleep(SleepTimeMs); + TimeoutMs -= SleepTimeMs; + } + while (TimeoutMs > 0); + + return Result == 0; #endif } -- cgit v1.2.3 From 5b801efdb39be1af3ec9a50dac0e3c6994bf8847 Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 10:16:05 +0100 Subject: Use semtimedop() in NamedEvent::Wait() for platforms that support it --- zencore/thread.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 063b060c9..f01cba7a8 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -8,6 +8,12 @@ #include #include +#if ZEN_PLATFORM_LINUX +# if !defined(_GNU_SOURCE) +# define _GNU_SOURCE // for semtimedop() +# endif +#endif + #if ZEN_PLATFORM_WINDOWS # include # include @@ -459,6 +465,14 @@ NamedEvent::Wait(int TimeoutMs) return Result == 0; } +#if defined(_GNU_SOURCE) + struct timespec TimeoutValue = { + .tv_sec = TimeoutMs >> 10, + .tv_nsec = (TimeoutMs & 0x3ff) << 20, + }; + int Result = semtimedop(Sem, &SemOp, 1, &TimeoutValue); + return Result == 0; +#else const int SleepTimeMs = 10; SemOp.sem_flg = IPC_NOWAIT; do @@ -475,6 +489,7 @@ NamedEvent::Wait(int TimeoutMs) while (TimeoutMs > 0); return Result == 0; +#endif // _GNU_SOURCE #endif } -- cgit v1.2.3 From 54d0185e39bab7c388749b08368db94201c2ea8d Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 14:23:32 +0100 Subject: Use null-signal kill() to determine if a PID is valid --- zencore/thread.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index f01cba7a8..c710930a6 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -650,9 +650,7 @@ ProcessHandle::IsRunning() const GetExitCodeProcess(m_ProcessHandle, &ExitCode); bActive = (ExitCode == STILL_ACTIVE); #elif ZEN_PLATFORM_LINUX - StringBuilder<64> ProcPath; - ProcPath << "/proc/" << m_Pid; - bActive = (access(ProcPath.c_str(), F_OK) != 0); + bActive = (kill(pid_t(m_Pid), 0) == 0); #else # error Check process control on this platform #endif @@ -1130,13 +1128,8 @@ IsProcessRunning(int pid) CloseHandle(hProc); return true; -#elif ZEN_PLATFORM_LINUX - char Buffer[64]; - sprintf(Buffer, "/proc/%d", pid); - return access(Buffer, F_OK) == 0; -#elif ZEN_PLATFORM_MAC - kill(pid_t(pid), 0); - return errno != ESRCH; +#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC + return (kill(pid_t(pid), 0) == 0); #endif } -- cgit v1.2.3 From 8580a242b6f864b9f9cefbc5723068788ca2076f Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Fri, 7 Jan 2022 14:24:12 +0100 Subject: Use POSIX implementation for ProcessHandle on Mac --- zencore/thread.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index c710930a6..358256b1d 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -622,13 +622,11 @@ ProcessHandle::Initialize(int Pid) #if ZEN_PLATFORM_WINDOWS m_ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, Pid); -#elif ZEN_PLATFORM_LINUX +#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC if (Pid > 0) { m_ProcessHandle = (void*)(intptr_t(Pid)); } -#else -# error Check process control on this platform #endif if (!m_ProcessHandle) @@ -649,10 +647,8 @@ ProcessHandle::IsRunning() const DWORD ExitCode = 0; GetExitCodeProcess(m_ProcessHandle, &ExitCode); bActive = (ExitCode == STILL_ACTIVE); -#elif ZEN_PLATFORM_LINUX +#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC bActive = (kill(pid_t(m_Pid), 0) == 0); -#else -# error Check process control on this platform #endif return bActive; @@ -678,11 +674,9 @@ ProcessHandle::Terminate(int ExitCode) TerminateProcess(m_ProcessHandle, ExitCode); DWORD WaitResult = WaitForSingleObject(m_ProcessHandle, INFINITE); bSuccess = (WaitResult != WAIT_OBJECT_0); -#elif ZEN_PLATFORM_LINUX +#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC ZEN_UNUSED(ExitCode); - bSuccess = (kill(m_Pid, SIGKILL) == 0); -#else -# error Check kill() on this platform + bSuccess = (kill(m_Pid, SIGKILL) == 0); #endif if (!bSuccess) @@ -725,7 +719,7 @@ ProcessHandle::Wait(int TimeoutMs) case WAIT_FAILED: break; } -#elif ZEN_PLATFORM_LINUX +#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC const int SleepMs = 20; timespec SleepTime = {0, SleepMs * 1000 * 1000}; for (int i = 0;; i += SleepMs) @@ -749,8 +743,6 @@ ProcessHandle::Wait(int TimeoutMs) nanosleep(&SleepTime, nullptr); } -#else -# error Check kill() on this platform #endif // What might go wrong here, and what is meaningful to act on? -- cgit v1.2.3 From 9086231f3923c0df6d9ef817441bfae5e134e8ff Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Mon, 10 Jan 2022 12:07:03 +0100 Subject: Converted use of _format UDL to fmt::format --- zencore/thread.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'zencore/thread.cpp') diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 358256b1d..97d44e733 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -310,8 +310,7 @@ NamedEvent::NamedEvent(std::string_view EventName) int Fd = open(EventPath.c_str(), O_RDWR|O_CREAT, 0644); if (Fd < 0) { - using namespace fmt::literals; - ThrowLastError("Failed to create '{}' for named event"_format(EventPath)); + ThrowLastError(fmt::format("Failed to create '{}' for named event", EventPath)); } // Use the file path to generate an IPC key @@ -631,8 +630,7 @@ ProcessHandle::Initialize(int Pid) if (!m_ProcessHandle) { - using namespace fmt::literals; - ThrowLastError("ProcessHandle::Initialize(pid: {}) failed"_format(Pid)); + ThrowLastError(fmt::format("ProcessHandle::Initialize(pid: {}) failed", Pid)); } m_Pid = Pid; @@ -1113,8 +1111,7 @@ IsProcessRunning(int pid) return false; } - using namespace fmt::literals; - ThrowSystemError(Error, "failed to open process with pid {}"_format(pid)); + ThrowSystemError(Error, fmt::format("failed to open process with pid {}", pid)); } CloseHandle(hProc); -- cgit v1.2.3