[libc-commits] [libc] Add named posix semaphore lifetime operations on linux (PR #192278)
via libc-commits
libc-commits at lists.llvm.org
Wed Apr 15 08:35:33 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Pengxiang Huang (Pengxiang-Huang)
<details>
<summary>Changes</summary>
This implements the second part of #<!-- -->190847
Specifically, this pr adds `sem_open`, `sem_close`, and `sem_unlink` for posix semaphore on linux.
https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_open.html
https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_close.html
https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_unlink.html
Since it targets on linux implementation, two extra things are added:
1. add system call wrappers for `mmap`, `munmap`, `link`, `unlink`, and `ftruncate`. Those are necessary for the implementation of semaphore on linux. Wrappers is added based on the refactor proposal: https://libc.llvm.org/dev/syscall_wrapper_refactor.html.
2. refactor the previous semaphore implementation, put it under `linux/` since its based on linux.
---
Patch is 25.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/192278.diff
12 Files Affected:
- (modified) libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt (+64)
- (added) libc/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h (+41)
- (added) libc/src/__support/OSUtil/linux/syscall_wrappers/link.h (+39)
- (added) libc/src/__support/OSUtil/linux/syscall_wrappers/mmap.h (+44)
- (added) libc/src/__support/OSUtil/linux/syscall_wrappers/munmap.h (+31)
- (added) libc/src/__support/OSUtil/linux/syscall_wrappers/unlink.h (+38)
- (modified) libc/src/semaphore/CMakeLists.txt (+1-8)
- (added) libc/src/semaphore/linux/CMakeLists.txt (+36)
- (added) libc/src/semaphore/linux/named_semaphore.cpp (+223)
- (renamed) libc/src/semaphore/linux/semaphore.h (+20-6)
- (modified) libc/test/src/semaphore/CMakeLists.txt (+4-1)
- (modified) libc/test/src/semaphore/semaphore_test.cpp (+95-1)
``````````diff
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 3d5ef62d09e66..6242b438cad25 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -131,3 +131,67 @@ add_header_library(
libc.hdr.types.struct_timespec
libc.include.sys_syscall
)
+
+add_header_library(
+ mmap
+ HDRS
+ mmap.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.hdr.types.off_t
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ munmap
+ HDRS
+ munmap.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ ftruncate
+ HDRS
+ ftruncate.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.hdr.types.off_t
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ link
+ HDRS
+ link.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.hdr.fcntl_macros
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ unlink
+ HDRS
+ unlink.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.hdr.fcntl_macros
+ libc.include.sys_syscall
+)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h
new file mode 100644
index 0000000000000..6835de85d3321
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h
@@ -0,0 +1,41 @@
+//===-- Implementation header for ftruncate ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_FTRUNCATE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_FTRUNCATE_H
+
+#include "hdr/types/off_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> ftruncate(int fd, off_t len) {
+#ifdef SYS_ftruncate
+ int ret = syscall_impl<int>(SYS_ftruncate, fd, len);
+#elif defined(SYS_ftruncate64)
+ // Same as ftruncate but can handle large offsets on 32-bit systems.
+ static_assert(sizeof(off_t) == 8);
+ int ret = syscall_impl<int>(SYS_ftruncate64, fd, (long)len,
+ (long)(((uint64_t)(len)) >> 32));
+#else
+#error "ftruncate and ftruncate64 syscalls not available."
+#endif
+ if (ret < 0)
+ return Error(-static_cast<int>(ret));
+ return 0;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_FTRUNCATE_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/link.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/link.h
new file mode 100644
index 0000000000000..048299b995588
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/link.h
@@ -0,0 +1,39 @@
+//===-- Implementation header for link --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LINK_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LINK_H
+
+#include "hdr/fcntl_macros.h" // AT_FDCWD
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> link(const char *oldpath, const char *newpath) {
+#ifdef SYS_link
+ int ret = syscall_impl<int>(SYS_link, oldpath, newpath);
+#elif defined(SYS_linkat)
+ int ret =
+ syscall_impl<int>(SYS_linkat, AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
+#else
+#error "link and linkat syscalls not available."
+#endif
+ if (ret < 0)
+ return Error(-static_cast<int>(ret));
+ return 0;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LINK_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/mmap.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/mmap.h
new file mode 100644
index 0000000000000..27147307e2cfb
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/mmap.h
@@ -0,0 +1,44 @@
+//===-- Implementation header for mmap --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_MMAP_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_MMAP_H
+
+#include "hdr/types/off_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl, is_valid_mmap
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <linux/param.h> // EXEC_PAGESIZE
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<void *> mmap(void *addr, size_t size, int prot, int flags,
+ int fd, off_t offset) {
+#ifdef SYS_mmap2
+ long mmap_offset = static_cast<long>(offset / EXEC_PAGESIZE);
+ long ret = syscall_impl<long>(SYS_mmap2, reinterpret_cast<long>(addr), size,
+ prot, flags, fd, mmap_offset);
+#elif defined(SYS_mmap)
+ long mmap_offset = static_cast<long>(offset);
+ long ret = syscall_impl<long>(SYS_mmap, reinterpret_cast<long>(addr), size,
+ prot, flags, fd, mmap_offset);
+#else
+#error "mmap or mmap2 syscalls not available."
+#endif
+ if (!linux_utils::is_valid_mmap(ret))
+ return Error(static_cast<int>(-ret));
+ return reinterpret_cast<void *>(ret);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_MMAP_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/munmap.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/munmap.h
new file mode 100644
index 0000000000000..d6678cc59f7d8
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/munmap.h
@@ -0,0 +1,31 @@
+//===-- Implementation header for munmap ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_MUNMAP_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_MUNMAP_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> munmap(void *addr, size_t size) {
+ int ret = syscall_impl<int>(SYS_munmap, reinterpret_cast<long>(addr), size);
+ if (ret < 0)
+ return Error(-static_cast<int>(ret));
+ return 0;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_MUNMAP_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/unlink.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/unlink.h
new file mode 100644
index 0000000000000..5549f794a3014
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/unlink.h
@@ -0,0 +1,38 @@
+//===-- Implementation header for unlink ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_UNLINK_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_UNLINK_H
+
+#include "hdr/fcntl_macros.h" // AT_FDCWD
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> unlink(const char *path) {
+#ifdef SYS_unlink
+ int ret = syscall_impl<int>(SYS_unlink, path);
+#elif defined(SYS_unlinkat)
+ int ret = syscall_impl<int>(SYS_unlinkat, AT_FDCWD, path, 0);
+#else
+#error "unlink and unlinkat syscalls not available."
+#endif
+ if (ret < 0)
+ return Error(-static_cast<int>(ret));
+ return 0;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_UNLINK_H
diff --git a/libc/src/semaphore/CMakeLists.txt b/libc/src/semaphore/CMakeLists.txt
index ac73eb8e87b56..a1034f9954740 100644
--- a/libc/src/semaphore/CMakeLists.txt
+++ b/libc/src/semaphore/CMakeLists.txt
@@ -1,8 +1 @@
-add_header_library(
- posix_semaphore
- HDRS
- posix_semaphore.h
- DEPENDS
- libc.src.__support.CPP.atomic
- libc.src.__support.threads.linux.futex_utils
-)
+add_subdirectory(linux)
diff --git a/libc/src/semaphore/linux/CMakeLists.txt b/libc/src/semaphore/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..c30b50a1e5166
--- /dev/null
+++ b/libc/src/semaphore/linux/CMakeLists.txt
@@ -0,0 +1,36 @@
+add_header_library(
+ semaphore
+ HDRS
+ semaphore.h
+ DEPENDS
+ libc.hdr.types.mode_t
+ libc.src.__support.CPP.atomic
+ libc.src.__support.error_or
+ libc.src.__support.threads.linux.futex_utils
+)
+
+add_object_library(
+ named_semaphore
+ SRCS
+ named_semaphore.cpp
+ HDRS
+ semaphore.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.fcntl_macros
+ libc.src.__support.CPP.array
+ libc.src.__support.CPP.limits
+ libc.src.__support.CPP.new
+ libc.src.__support.CPP.string_view
+ libc.src.__support.error_or
+ libc.src.__support.OSUtil.linux.syscall_wrappers.close
+ libc.src.__support.OSUtil.linux.syscall_wrappers.ftruncate
+ libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom
+ libc.src.__support.OSUtil.linux.syscall_wrappers.link
+ libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
+ libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
+ libc.src.__support.OSUtil.linux.syscall_wrappers.open
+ libc.src.__support.OSUtil.linux.syscall_wrappers.unlink
+ libc.src.string.memory_utils.inline_memcpy
+)
diff --git a/libc/src/semaphore/linux/named_semaphore.cpp b/libc/src/semaphore/linux/named_semaphore.cpp
new file mode 100644
index 0000000000000..e97ac625df13c
--- /dev/null
+++ b/libc/src/semaphore/linux/named_semaphore.cpp
@@ -0,0 +1,223 @@
+//===-- Named semaphore implementation for Linux --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/semaphore/linux/semaphore.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/fcntl_macros.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/link.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/unlink.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+
+#include <linux/limits.h> // NAME_MAX
+#include <linux/mman.h> // PROT_READ, PROT_WRITE, MAP_SHARED
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace {
+
+// define SEM_VALUE_MAX as INT_MAX
+constexpr unsigned int SEM_VALUE_MAX =
+ static_cast<unsigned int>(cpp::numeric_limits<int>::max());
+
+// Named semaphores are backed by files in /dev/shm/.
+// a prefix "sem." is added to avoid name collision.
+constexpr cpp::string_view SEM_PREFIX = "/dev/shm/sem.";
+
+// use temporary file to solve data race and guarantee atomic publish.
+// Temporary file use different prefix.
+constexpr cpp::string_view SEM_TMP_PREFIX = "/dev/shm/sem.tmp_";
+
+// 8 random bytes from getrandom() produce a 16 character hex suffix, giving
+// 2^64 possible temp names to avoid collision.
+constexpr size_t RANDOM_SUFFIX_BYTES = 8;
+constexpr size_t RANDOM_SUFFIX_HEX_LEN = RANDOM_SUFFIX_BYTES * 2;
+
+// fixed-size buffers for semaphore paths. SemPath holds the final path
+// and TmpPath holds the temp path.
+using SemPath = cpp::array<char, NAME_MAX + SEM_PREFIX.size() + 1>;
+using TmpPath =
+ cpp::array<char, SEM_TMP_PREFIX.size() + RANDOM_SUFFIX_HEX_LEN + 1>;
+
+// O_NOFOLLOW prevents symlink attacks to /dev/shm/. O_CLOEXEC ensures the
+// fd is not leaked to child processes across exec.
+constexpr int DEFAULT_OFLAGS = O_NOFOLLOW | O_CLOEXEC;
+
+ErrorOr<SemPath> translate_name(const char *name) {
+ cpp::string_view sv(name);
+
+ // name must start with '/'.
+ if (sv.empty() || sv.front() != '/')
+ return Error(EINVAL);
+
+ // remove leading '/'.
+ sv = sv.substr(1);
+
+ // name must not be empty, must not contain '/', and must not be "." or "..".
+ if (sv.empty() || sv.contains('/') || sv == "." || sv == "..")
+ return Error(EINVAL);
+
+ // name lenghth must in range.
+ if (sv.size() > NAME_MAX)
+ return Error(ENAMETOOLONG);
+
+ // copy the prefix and name into final name buffer.
+ SemPath buffer;
+ inline_memcpy(buffer.data(), SEM_PREFIX.data(), SEM_PREFIX.size());
+ inline_memcpy(buffer.data() + SEM_PREFIX.size(), sv.data(), sv.size());
+ buffer[SEM_PREFIX.size() + sv.size()] = '\0';
+ return buffer;
+}
+
+ErrorOr<TmpPath> generate_tmp_path() {
+ // fill out 8 random bytes.
+ cpp::array<uint8_t, RANDOM_SUFFIX_BYTES> rand_bytes;
+ auto ret = linux_syscalls::getrandom(rand_bytes.data(), rand_bytes.size(), 0);
+ if (!ret.has_value())
+ return Error(ret.error());
+
+ TmpPath path;
+ inline_memcpy(path.data(), SEM_TMP_PREFIX.data(), SEM_TMP_PREFIX.size());
+
+ // Encode each random byte as two hex digits, and fill out tmp path.
+ constexpr char hex_table[] = "0123456789abcdef";
+ char *dst = path.data() + SEM_TMP_PREFIX.size();
+ for (size_t i = 0; i < RANDOM_SUFFIX_BYTES; ++i) {
+ *dst++ = hex_table[rand_bytes[i] >> 4];
+ *dst++ = hex_table[rand_bytes[i] & 0xf];
+ }
+ *dst = '\0';
+ return path;
+}
+
+// map an open semaphore fd into memory.
+ErrorOr<Semaphore *> map_semaphore(int fd) {
+ auto mmap_or = linux_syscalls::mmap(
+ nullptr, sizeof(Semaphore), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ linux_syscalls::close(fd);
+
+ if (!mmap_or.has_value())
+ return Error(mmap_or.error());
+
+ return reinterpret_cast<Semaphore *>(mmap_or.value());
+}
+
+// open an existing named semaphore file and map it.
+ErrorOr<Semaphore *> open_existing(const char *path) {
+ auto fd_or = linux_syscalls::open(path, O_RDWR | DEFAULT_OFLAGS, 0);
+ if (!fd_or.has_value())
+ return Error(fd_or.error());
+ return map_semaphore(fd_or.value());
+}
+
+} // anonymous namespace
+
+ErrorOr<Semaphore *> Semaphore::open(const char *name, int oflag, mode_t mode,
+ unsigned int value) {
+ auto path_or = translate_name(name);
+ if (!path_or.has_value())
+ return Error(path_or.error());
+
+ // open an existing semaphore.
+ if (!(oflag & O_CREAT))
+ return open_existing(path_or->data());
+
+ // check semaphore value.
+ if (value > SEM_VALUE_MAX)
+ return Error(EINVAL);
+
+ // two step creation:
+ // 1. create and fully initialize a temporary file.
+ // 2. link() it and publish to the final path atomically.
+ // This ensures no other process can observe a partially-initialized
+ // semaphore through the final path. If link() fails with EEXIST and
+ // O_EXCL is not set, fall back to opening the existing semaphore.
+
+ auto tmp_or = generate_tmp_path();
+ if (!tmp_or.has_value())
+ return Error(tmp_or.error());
+
+ // if two process happen to map the same random tmp_path, though rare
+ // in 2^64 namespace, one succees and the other return EEXIST.
+ auto fd_or = linux_syscalls::open(
+ tmp_or->data(), O_RDWR | O_CREAT | O_EXCL | DEFAULT_OFLAGS, mode);
+ if (!fd_or.has_value())
+ return Error(fd_or.error());
+
+ int fd = fd_or.value();
+
+ // resizing temporary semaphore backing file.
+ auto trunc_or =
+ linux_syscalls::ftruncate(fd, static_cast<off_t>(sizeof(Semaphore)));
+ if (!trunc_or.has_value()) {
+ linux_syscalls::close(fd);
+ linux_syscalls::unlink(tmp_or->data());
+ return Error(trunc_or.error());
+ }
+
+ // map_semaphore closes the fd.
+ auto sem_or = map_semaphore(fd);
+ if (!sem_or.has_value()) {
+ linux_syscalls::unlink(tmp_or->data());
+ return Error(sem_or.error());
+ }
+
+ Semaphore *sem = sem_or.value();
+ new (sem) Semaphore(value);
+
+ // atomically publish the fully initialized semaphore.
+ auto link_or = linux_syscalls::link(tmp_or->data(), path_or->data());
+
+ // temp file is no longer needed.
+ linux_syscalls::unlink(tmp_or->data());
+
+ // link() succees
+ if (link_or.has_value())
+ return sem;
+
+ // link() fail, clean up the mapping.
+ linux_syscalls::munmap(sem, sizeof(Semaphore));
+
+ // if the name already exists and O_EXCL was not set, open existing.
+ if (link_or.error() == EEXIST && !(oflag & O_EXCL))
+ return open_existing(path_or->data());
+
+ return Error(link_or.error());
+}
+
+int Semaphore::close(Semaphore *sem) {
+ auto result = linux_syscalls::munmap(sem, sizeof(Semaphore));
+ if (!result.has_value())
+ return result.error();
+ return 0;
+}
+
+int Semaphore::unlink(const char *name) {
+ auto path_or = translate_name(name);
+ if (!path_or.has_value())
+ return path_or.error();
+
+ auto result = linux_syscalls::unlink(path_or->data());
+ if (!result.has_value())
+ return result.error();
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/posix_semaphore.h b/libc/src/semaphore/linux/semaphore.h
similarity index 67%
rename from libc/src/semaphore/posix_semaphore.h
rename to libc/src/semaphore/linux/semaphore.h
index 7b14d41165a96..77198e385301b 100644...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/192278
More information about the libc-commits
mailing list