From c49e5b15e0f86080d7d33e4e31aecfb701f8f96f Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Mon, 13 Apr 2026 14:05:03 +0200 Subject: Some minor polish from tourist branch (#949) - Replace per-type fmt::formatter specializations (StringBuilderBase, NiceBase) with a single generic formatter using a HasStringViewConversion concept - Add ThousandsNum for comma-separated integer formatting (e.g. "1,234,567") - Thread naming now accepts a sort hint for trace ordering - Fix main thread trace registration to use actual thread ID and sort first - Add ExpandEnvironmentVariables() for expanding %VAR% references in strings, with tests - Add ParseHexBytes() overload with expected byte count validation - Add Flag_BelowNormalPriority to CreateProcOptions (BELOW_NORMAL_PRIORITY_CLASS on Windows, setpriority on POSIX) - Add PrettyScroll progress bar mode that pins the status line to the bottom of the terminal using scroll regions, with signal handler cleanup for Ctrl+C/SIGTERM --- src/zencore/thread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/zencore/thread.cpp') diff --git a/src/zencore/thread.cpp b/src/zencore/thread.cpp index 067e66c0d..fd72afaa7 100644 --- a/src/zencore/thread.cpp +++ b/src/zencore/thread.cpp @@ -99,7 +99,7 @@ SetNameInternal(DWORD thread_id, const char* name) #endif void -SetCurrentThreadName([[maybe_unused]] std::string_view ThreadName) +SetCurrentThreadName([[maybe_unused]] std::string_view ThreadName, [[maybe_unused]] int32_t SortHint) { constexpr std::string_view::size_type MaxThreadNameLength = 255; std::string_view LimitedThreadName = ThreadName.substr(0, MaxThreadNameLength); @@ -108,7 +108,7 @@ SetCurrentThreadName([[maybe_unused]] std::string_view ThreadName) const int ThreadId = GetCurrentThreadId(); #if ZEN_WITH_TRACE - trace::ThreadRegister(ThreadNameZ.c_str(), /* system id */ ThreadId, /* sort id */ 0); + trace::ThreadRegister(ThreadNameZ.c_str(), /* system id */ ThreadId, /* sort id */ SortHint); #endif // ZEN_WITH_TRACE #if ZEN_PLATFORM_WINDOWS -- cgit v1.2.3 From 9cf0e8812e50f499f401e217c55a442768f03a31 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Wed, 22 Apr 2026 09:09:08 +0200 Subject: fix NamedEvent ftok() race on Linux/macOS (#1001) - `ftok()` internally re-`stat()`s the path and fails with `ENOENT` if another owner's destructor unlinks the backing file between our `open()` and `ftok()`; the held fd does not protect against this - derive the IPC key via `fstat()` on the fd instead, using the same `(ino & 0xffff) | ((dev & 0xff) << 16) | (proj << 24)` formula that glibc and macOS `ftok()` compute internally - fixes intermittent "Failed to create an SysV IPC key" failures on macOS, where the slower on-disk /tmp widens the race window --- src/zencore/thread.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/zencore/thread.cpp') diff --git a/src/zencore/thread.cpp b/src/zencore/thread.cpp index fd72afaa7..1f4004373 100644 --- a/src/zencore/thread.cpp +++ b/src/zencore/thread.cpp @@ -336,13 +336,17 @@ NamedEvent::NamedEvent(std::string_view EventName) } fchmod(Fd, 0666); - // Use the file path to generate an IPC key - key_t IpcKey = ftok(EventPath.c_str(), 1); - if (IpcKey < 0) + // Derive the IPC key via fstat() on the fd instead of ftok() on the path: + // another owner's destructor can unlink the backing file between our open() + // and ftok(), in which case ftok's internal stat() fails with ENOENT. The + // formula below matches what glibc/macOS ftok() compute internally. + struct stat IpcStat; + if (fstat(Fd, &IpcStat) < 0) { close(Fd); - ThrowLastError("Failed to create an SysV IPC key"); + ThrowLastError("Failed to stat backing file for SysV IPC key"); } + const key_t IpcKey = key_t((IpcStat.st_ino & 0xffff) | ((IpcStat.st_dev & 0xff) << 16) | (1 << 24)); // Use the key to create/open the semaphore int Sem = semget(IpcKey, 1, 0600 | IPC_CREAT); -- cgit v1.2.3