[libc-commits] [libc] [libc][Semaphore] Add public sem_t type and entry (PR #213489)
Pengxiang Huang via libc-commits
libc-commits at lists.llvm.org
Sat Aug 1 13:29:41 PDT 2026
https://github.com/Pengxiang-Huang created https://github.com/llvm/llvm-project/pull/213489
Implements #190847
Add the public `sem_t` class that operates on the internal `Semaphore` class. Assisted-by: Claude Code Fable 5.
>From 3832586f1987bb3086dd57de84619412630e0c2f Mon Sep 17 00:00:00 2001
From: Pengxiang Huang <huangpengxiang70 at gmail.com>
Date: Sat, 1 Aug 2026 16:24:22 -0400
Subject: [PATCH] add public sem_t header and proxy that operates on internal
Semaphore class
---
libc/config/linux/x86_64/entrypoints.txt | 13 ++
libc/config/linux/x86_64/headers.txt | 1 +
libc/hdr/CMakeLists.txt | 9 +
libc/hdr/semaphore_macros.h | 22 ++
libc/hdr/types/CMakeLists.txt | 8 +
libc/hdr/types/sem_t.h | 22 ++
libc/include/CMakeLists.txt | 13 ++
libc/include/limits.yaml | 2 +
libc/include/llvm-libc-macros/CMakeLists.txt | 6 +
libc/include/llvm-libc-macros/limits-macros.h | 5 +
.../llvm-libc-macros/semaphore-macros.h | 15 ++
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/sem_t.h | 24 +++
libc/include/semaphore.yaml | 86 ++++++++
libc/src/semaphore/CMakeLists.txt | 77 +++++++
libc/src/semaphore/linux/CMakeLists.txt | 154 +++++++++++++-
libc/src/semaphore/linux/sem_clockwait.cpp | 38 ++++
libc/src/semaphore/linux/sem_close.cpp | 34 +++
libc/src/semaphore/linux/sem_destroy.cpp | 31 +++
libc/src/semaphore/linux/sem_getvalue.cpp | 32 +++
libc/src/semaphore/linux/sem_init.cpp | 33 +++
libc/src/semaphore/linux/sem_open.cpp | 45 ++++
libc/src/semaphore/linux/sem_post.cpp | 34 +++
libc/src/semaphore/linux/sem_timedwait.cpp | 37 ++++
libc/src/semaphore/linux/sem_trywait.cpp | 35 ++++
libc/src/semaphore/linux/sem_unlink.cpp | 26 +++
libc/src/semaphore/linux/sem_wait.cpp | 34 +++
libc/src/semaphore/linux/semaphore.h | 15 +-
libc/src/semaphore/sem_clockwait.h | 24 +++
libc/src/semaphore/sem_close.h | 21 ++
libc/src/semaphore/sem_destroy.h | 21 ++
libc/src/semaphore/sem_getvalue.h | 21 ++
libc/src/semaphore/sem_init.h | 21 ++
libc/src/semaphore/sem_open.h | 21 ++
libc/src/semaphore/sem_post.h | 21 ++
libc/src/semaphore/sem_timedwait.h | 23 +++
libc/src/semaphore/sem_trywait.h | 21 ++
libc/src/semaphore/sem_unlink.h | 20 ++
libc/src/semaphore/sem_wait.h | 21 ++
libc/test/src/semaphore/CMakeLists.txt | 50 +++++
libc/test/src/semaphore/linux/CMakeLists.txt | 3 +-
.../src/semaphore/linux/semaphore_test.cpp | 5 +-
libc/test/src/semaphore/sem_open_test.cpp | 102 +++++++++
libc/test/src/semaphore/sem_test.cpp | 195 ++++++++++++++++++
44 files changed, 1432 insertions(+), 10 deletions(-)
create mode 100644 libc/hdr/semaphore_macros.h
create mode 100644 libc/hdr/types/sem_t.h
create mode 100644 libc/include/llvm-libc-macros/semaphore-macros.h
create mode 100644 libc/include/llvm-libc-types/sem_t.h
create mode 100644 libc/include/semaphore.yaml
create mode 100644 libc/src/semaphore/linux/sem_clockwait.cpp
create mode 100644 libc/src/semaphore/linux/sem_close.cpp
create mode 100644 libc/src/semaphore/linux/sem_destroy.cpp
create mode 100644 libc/src/semaphore/linux/sem_getvalue.cpp
create mode 100644 libc/src/semaphore/linux/sem_init.cpp
create mode 100644 libc/src/semaphore/linux/sem_open.cpp
create mode 100644 libc/src/semaphore/linux/sem_post.cpp
create mode 100644 libc/src/semaphore/linux/sem_timedwait.cpp
create mode 100644 libc/src/semaphore/linux/sem_trywait.cpp
create mode 100644 libc/src/semaphore/linux/sem_unlink.cpp
create mode 100644 libc/src/semaphore/linux/sem_wait.cpp
create mode 100644 libc/src/semaphore/sem_clockwait.h
create mode 100644 libc/src/semaphore/sem_close.h
create mode 100644 libc/src/semaphore/sem_destroy.h
create mode 100644 libc/src/semaphore/sem_getvalue.h
create mode 100644 libc/src/semaphore/sem_init.h
create mode 100644 libc/src/semaphore/sem_open.h
create mode 100644 libc/src/semaphore/sem_post.h
create mode 100644 libc/src/semaphore/sem_timedwait.h
create mode 100644 libc/src/semaphore/sem_trywait.h
create mode 100644 libc/src/semaphore/sem_unlink.h
create mode 100644 libc/src/semaphore/sem_wait.h
create mode 100644 libc/test/src/semaphore/sem_open_test.cpp
create mode 100644 libc/test/src/semaphore/sem_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index bf809e268f585..b39cc972200bf 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1352,6 +1352,19 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.sched.__sched_setcpuzero
libc.src.sched.__sched_xorcpuset
+ # semaphore.h entrypoints
+ libc.src.semaphore.sem_clockwait
+ libc.src.semaphore.sem_close
+ libc.src.semaphore.sem_destroy
+ libc.src.semaphore.sem_getvalue
+ libc.src.semaphore.sem_init
+ libc.src.semaphore.sem_open
+ libc.src.semaphore.sem_post
+ libc.src.semaphore.sem_timedwait
+ libc.src.semaphore.sem_trywait
+ libc.src.semaphore.sem_unlink
+ libc.src.semaphore.sem_wait
+
# setjmp.h entrypoints
libc.src.setjmp.longjmp
libc.src.setjmp.setjmp
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index b8751f7810b30..3aea6394c98cb 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -35,6 +35,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.pwd
libc.include.sched
libc.include.search
+ libc.include.semaphore
libc.include.setjmp
libc.include.signal
libc.include.spawn
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index a3eb7769e3c91..2eb684a7ee181 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -112,6 +112,15 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.sched_macros
)
+add_proxy_header_library(
+ semaphore_macros
+ HDRS
+ semaphore_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-macros.semaphore_macros
+ libc.include.semaphore
+)
+
add_proxy_header_library(
signal_macros
HDRS
diff --git a/libc/hdr/semaphore_macros.h b/libc/hdr/semaphore_macros.h
new file mode 100644
index 0000000000000..88647dd971f11
--- /dev/null
+++ b/libc/hdr/semaphore_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from semaphore.h -----------------------------===//
+//
+// 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_HDR_SEMAPHORE_MACROS_H
+#define LLVM_LIBC_HDR_SEMAPHORE_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/semaphore-macros.h"
+
+#else // Overlay mode
+
+#include <semaphore.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SEMAPHORE_MACROS_H
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 8e4b2175cb7cd..e7f2aa21de4ed 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -341,6 +341,14 @@ add_proxy_header_library(
libc.include.llvm-libc-types.pthread_barrier_t
)
+add_proxy_header_library(
+ sem_t
+ HDRS
+ sem_t.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.sem_t
+)
+
add_proxy_header_library(
pthread_barrierattr_t
HDRS
diff --git a/libc/hdr/types/sem_t.h b/libc/hdr/types/sem_t.h
new file mode 100644
index 0000000000000..f7071a0836d32
--- /dev/null
+++ b/libc/hdr/types/sem_t.h
@@ -0,0 +1,22 @@
+//===-- Proxy for sem_t ---------------------------------------------------===//
+//
+// 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_HDR_TYPES_SEM_T_H
+#define LLVM_LIBC_HDR_TYPES_SEM_T_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/sem_t.h"
+
+#else // Overlay mode
+
+#error "Cannot overlay sem_t"
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_SEM_T_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 196490dcfdcc1..1a25df0990750 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -579,6 +579,19 @@ add_header_macro(
.llvm-libc-types.struct_timespec
)
+add_header_macro(
+ semaphore
+ ../libc/include/semaphore.yaml
+ semaphore.h
+ DEPENDS
+ .llvm_libc_common_h
+ .llvm-libc-macros.semaphore_macros
+ .llvm-libc-types.clockid_t
+ .llvm-libc-types.mode_t
+ .llvm-libc-types.sem_t
+ .llvm-libc-types.struct_timespec
+)
+
add_header_macro(
spawn
../libc/include/spawn.yaml
diff --git a/libc/include/limits.yaml b/libc/include/limits.yaml
index 1c951318fb14c..f14aa9abed9be 100644
--- a/libc/include/limits.yaml
+++ b/libc/include/limits.yaml
@@ -86,6 +86,8 @@ macros:
macro_header: limits-macros.h
- macro_name: PTHREAD_DESTRUCTOR_ITERATIONS
macro_header: limits-macros.h
+ - macro_name: SEM_VALUE_MAX
+ macro_header: limits-macros.h
- macro_name: SSIZE_MAX
macro_header: limits-macros.h
types: []
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 45a1dbc851d2c..59272a603671f 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -201,6 +201,12 @@ add_macro_header(
sched-macros.h
)
+add_macro_header(
+ semaphore_macros
+ HDR
+ semaphore-macros.h
+)
+
add_macro_header(
signal_macros
HDR
diff --git a/libc/include/llvm-libc-macros/limits-macros.h b/libc/include/llvm-libc-macros/limits-macros.h
index 024591eb5b40d..7a6b58e2d598c 100644
--- a/libc/include/llvm-libc-macros/limits-macros.h
+++ b/libc/include/llvm-libc-macros/limits-macros.h
@@ -256,6 +256,11 @@
#define _POSIX_HOST_NAME_MAX 255
#endif
+#ifndef SEM_VALUE_MAX
+/// The maximum value a semaphore may hold.
+#define SEM_VALUE_MAX INT_MAX
+#endif
+
#ifdef __linux__
#ifndef PATH_MAX
diff --git a/libc/include/llvm-libc-macros/semaphore-macros.h b/libc/include/llvm-libc-macros/semaphore-macros.h
new file mode 100644
index 0000000000000..d3a88209f8cde
--- /dev/null
+++ b/libc/include/llvm-libc-macros/semaphore-macros.h
@@ -0,0 +1,15 @@
+//===-- Definition of macros from semaphore.h -----------------------------===//
+//
+// 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_MACROS_SEMAPHORE_MACROS_H
+#define LLVM_LIBC_MACROS_SEMAPHORE_MACROS_H
+
+// The value returned by sem_open on failure.
+#define SEM_FAILED ((sem_t *)0)
+
+#endif // LLVM_LIBC_MACROS_SEMAPHORE_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 3286ebe54d9a2..7111a7b5ed18c 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -119,6 +119,7 @@ add_header(pthread_spinlock_t HDR pthread_spinlock_t.h DEPENDS .pid_t)
add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type)
add_header(pthread_id_np_t HDR pthread_id_np_t.h DEPENDS libc.include.llvm-libc-macros.stdint_macros)
add_header(rlim_t HDR rlim_t.h)
+add_header(sem_t HDR sem_t.h DEPENDS .__futex_word)
add_header(time_t HDR time_t_64.h DEST_HDR time_t.h)
add_header(sighandler_t HDR sighandler_t.h)
add_header(stack_t HDR stack_t.h DEPENDS .size_t)
diff --git a/libc/include/llvm-libc-types/sem_t.h b/libc/include/llvm-libc-types/sem_t.h
new file mode 100644
index 0000000000000..a32a5bf6fc289
--- /dev/null
+++ b/libc/include/llvm-libc-types/sem_t.h
@@ -0,0 +1,24 @@
+//===-- Definition of sem_t type ------------------------------------------===//
+//
+// 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_TYPES_SEM_T_H
+#define LLVM_LIBC_TYPES_SEM_T_H
+
+#include "__futex_word.h"
+
+typedef struct {
+ // The semaphore count. Waiters block on this word.
+ __futex_word __value;
+ // Set to a fixed value by sem_init/sem_open and cleared by sem_destroy, so
+ // that operations on an uninitialized or destroyed semaphore can be detected.
+ unsigned int __canary;
+ // Whether the semaphore is shared between processes.
+ unsigned int __is_shared : 1;
+} sem_t;
+
+#endif // LLVM_LIBC_TYPES_SEM_T_H
diff --git a/libc/include/semaphore.yaml b/libc/include/semaphore.yaml
new file mode 100644
index 0000000000000..4c51174359f1e
--- /dev/null
+++ b/libc/include/semaphore.yaml
@@ -0,0 +1,86 @@
+header: semaphore.h
+standards:
+ - posix
+macros:
+ - macro_name: SEM_FAILED
+ macro_header: semaphore-macros.h
+types:
+ - type_name: clockid_t
+ - type_name: mode_t
+ - type_name: sem_t
+ - type_name: struct_timespec
+functions:
+ - name: sem_clockwait
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *__restrict
+ - type: clockid_t
+ - type: const struct timespec *__restrict
+ - name: sem_close
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *
+ - name: sem_destroy
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *
+ - name: sem_getvalue
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *__restrict
+ - type: int *__restrict
+ - name: sem_init
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *
+ - type: int
+ - type: unsigned
+ - name: sem_open
+ standards:
+ - posix
+ return_type: sem_t *
+ arguments:
+ - type: const char *
+ - type: int
+ - type: '...'
+ - name: sem_post
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *
+ - name: sem_timedwait
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *__restrict
+ - type: const struct timespec *__restrict
+ - name: sem_trywait
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *
+ - name: sem_unlink
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: const char *
+ - name: sem_wait
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: sem_t *
diff --git a/libc/src/semaphore/CMakeLists.txt b/libc/src/semaphore/CMakeLists.txt
index cbe2c334fb571..9d3f6e4e96513 100644
--- a/libc/src/semaphore/CMakeLists.txt
+++ b/libc/src/semaphore/CMakeLists.txt
@@ -5,3 +5,80 @@ endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
+
+add_entrypoint_object(
+ sem_init
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_init
+)
+
+add_entrypoint_object(
+ sem_destroy
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_destroy
+)
+
+add_entrypoint_object(
+ sem_getvalue
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_getvalue
+)
+
+add_entrypoint_object(
+ sem_open
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_open
+)
+
+add_entrypoint_object(
+ sem_close
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_close
+)
+
+add_entrypoint_object(
+ sem_unlink
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_unlink
+)
+
+add_entrypoint_object(
+ sem_post
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_post
+)
+
+add_entrypoint_object(
+ sem_wait
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_wait
+)
+
+add_entrypoint_object(
+ sem_trywait
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_trywait
+)
+
+add_entrypoint_object(
+ sem_timedwait
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_timedwait
+)
+
+add_entrypoint_object(
+ sem_clockwait
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sem_clockwait
+)
diff --git a/libc/src/semaphore/linux/CMakeLists.txt b/libc/src/semaphore/linux/CMakeLists.txt
index bd57b9ee5fc5d..cbc49d07fa0e9 100644
--- a/libc/src/semaphore/linux/CMakeLists.txt
+++ b/libc/src/semaphore/linux/CMakeLists.txt
@@ -4,12 +4,13 @@ add_header_library(
semaphore.h
DEPENDS
libc.hdr.errno_macros
+ libc.hdr.limits_macros
libc.hdr.time_macros
libc.hdr.types.clockid_t
libc.hdr.types.mode_t
libc.hdr.types.struct_timespec
+ libc.include.llvm-libc-types.sem_t
libc.src.__support.CPP.atomic
- libc.src.__support.CPP.limits
libc.src.__support.error_or
libc.src.__support.libc_assert
libc.src.__support.threads.futex_utils
@@ -42,3 +43,154 @@ add_object_library(
libc.src.string.memory_utils.inline_memcpy
libc.src.sys.mman.linux.shm_common
)
+
+add_entrypoint_object(
+ sem_init
+ SRCS
+ sem_init.cpp
+ HDRS
+ ../sem_init.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.limits_macros
+ libc.hdr.types.sem_t
+ libc.src.__support.CPP.new
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_destroy
+ SRCS
+ sem_destroy.cpp
+ HDRS
+ ../sem_destroy.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_getvalue
+ SRCS
+ sem_getvalue.cpp
+ HDRS
+ ../sem_getvalue.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_open
+ SRCS
+ sem_open.cpp
+ HDRS
+ ../sem_open.h
+ DEPENDS
+ .named_semaphore
+ .semaphore
+ libc.hdr.fcntl_macros
+ libc.hdr.semaphore_macros
+ libc.hdr.types.mode_t
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_close
+ SRCS
+ sem_close.cpp
+ HDRS
+ ../sem_close.h
+ DEPENDS
+ .named_semaphore
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_unlink
+ SRCS
+ sem_unlink.cpp
+ HDRS
+ ../sem_unlink.h
+ DEPENDS
+ .named_semaphore
+ .semaphore
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_post
+ SRCS
+ sem_post.cpp
+ HDRS
+ ../sem_post.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_wait
+ SRCS
+ sem_wait.cpp
+ HDRS
+ ../sem_wait.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_trywait
+ SRCS
+ sem_trywait.cpp
+ HDRS
+ ../sem_trywait.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_timedwait
+ SRCS
+ sem_timedwait.cpp
+ HDRS
+ ../sem_timedwait.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.sem_t
+ libc.hdr.types.struct_timespec
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ sem_clockwait
+ SRCS
+ sem_clockwait.cpp
+ HDRS
+ ../sem_clockwait.h
+ DEPENDS
+ .semaphore
+ libc.hdr.errno_macros
+ libc.hdr.types.clockid_t
+ libc.hdr.types.sem_t
+ libc.hdr.types.struct_timespec
+ libc.src.errno.errno
+)
diff --git a/libc/src/semaphore/linux/sem_clockwait.cpp b/libc/src/semaphore/linux/sem_clockwait.cpp
new file mode 100644
index 0000000000000..75def64792668
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_clockwait.cpp
@@ -0,0 +1,38 @@
+//===-- Linux implementation of sem_clockwait -----------------------------===//
+//
+// 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/sem_clockwait.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/sem_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_clockwait,
+ (sem_t *__restrict sem, clockid_t clock_id,
+ const struct timespec *__restrict abstime)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ if (int err = semaphore->clockwait(clock_id, abstime)) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_close.cpp b/libc/src/semaphore/linux/sem_close.cpp
new file mode 100644
index 0000000000000..0dc5a3f074cd6
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_close.cpp
@@ -0,0 +1,34 @@
+//===-- Linux implementation of sem_close ---------------------------------===//
+//
+// 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/sem_close.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_close, (sem_t * sem)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ if (int err = Semaphore::close(semaphore)) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_destroy.cpp b/libc/src/semaphore/linux/sem_destroy.cpp
new file mode 100644
index 0000000000000..3b299020ce336
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_destroy.cpp
@@ -0,0 +1,31 @@
+//===-- Linux implementation of sem_destroy -------------------------------===//
+//
+// 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/sem_destroy.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_destroy, (sem_t * sem)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ semaphore->destroy();
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_getvalue.cpp b/libc/src/semaphore/linux/sem_getvalue.cpp
new file mode 100644
index 0000000000000..0ac5aa7d7696d
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_getvalue.cpp
@@ -0,0 +1,32 @@
+//===-- Linux implementation of sem_getvalue ------------------------------===//
+//
+// 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/sem_getvalue.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_getvalue,
+ (sem_t *__restrict sem, int *__restrict sval)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ *sval = semaphore->getvalue();
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_init.cpp b/libc/src/semaphore/linux/sem_init.cpp
new file mode 100644
index 0000000000000..602567299e577
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_init.cpp
@@ -0,0 +1,33 @@
+//===-- Linux implementation of sem_init ----------------------------------===//
+//
+// 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/sem_init.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/limits_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_init,
+ (sem_t * sem, int pshared, unsigned int value)) {
+ if (value > SEM_VALUE_MAX) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ new (sem) Semaphore(value, /*shared=*/pshared != 0);
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_open.cpp b/libc/src/semaphore/linux/sem_open.cpp
new file mode 100644
index 0000000000000..2ee7f3786278b
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_open.cpp
@@ -0,0 +1,45 @@
+//===-- Linux implementation of sem_open ----------------------------------===//
+//
+// 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/sem_open.h"
+
+#include "hdr/fcntl_macros.h"
+#include "hdr/semaphore_macros.h"
+#include "hdr/types/mode_t.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(sem_t *, sem_open, (const char *name, int oflag, ...)) {
+ mode_t mode = 0;
+ unsigned int value = 0;
+
+ if (oflag & O_CREAT) {
+ va_list varargs;
+ va_start(varargs, oflag);
+ mode = va_arg(varargs, mode_t);
+ value = va_arg(varargs, unsigned int);
+ va_end(varargs);
+ }
+
+ auto sem_or = Semaphore::open(name, oflag, mode, value);
+ if (!sem_or.has_value()) {
+ libc_errno = sem_or.error();
+ return SEM_FAILED;
+ }
+
+ return reinterpret_cast<sem_t *>(sem_or.value());
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_post.cpp b/libc/src/semaphore/linux/sem_post.cpp
new file mode 100644
index 0000000000000..90d8b6627b5ee
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_post.cpp
@@ -0,0 +1,34 @@
+//===-- Linux implementation of sem_post ----------------------------------===//
+//
+// 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/sem_post.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_post, (sem_t * sem)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ if (int err = semaphore->post()) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_timedwait.cpp b/libc/src/semaphore/linux/sem_timedwait.cpp
new file mode 100644
index 0000000000000..3ce182fa1f63b
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_timedwait.cpp
@@ -0,0 +1,37 @@
+//===-- Linux implementation of sem_timedwait -----------------------------===//
+//
+// 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/sem_timedwait.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_timedwait,
+ (sem_t *__restrict sem,
+ const struct timespec *__restrict abstime)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ if (int err = semaphore->timedwait(abstime)) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_trywait.cpp b/libc/src/semaphore/linux/sem_trywait.cpp
new file mode 100644
index 0000000000000..9d40f0b3f5d33
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_trywait.cpp
@@ -0,0 +1,35 @@
+//===-- Linux implementation of sem_trywait -------------------------------===//
+//
+// 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/sem_trywait.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_trywait, (sem_t * sem)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ // An already locked semaphore reports EAGAIN rather than blocking.
+ if (int err = semaphore->trywait()) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_unlink.cpp b/libc/src/semaphore/linux/sem_unlink.cpp
new file mode 100644
index 0000000000000..1c1b2adb34af4
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_unlink.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of sem_unlink --------------------------------===//
+//
+// 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/sem_unlink.h"
+
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_unlink, (const char *name)) {
+ if (int err = Semaphore::unlink(name)) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/sem_wait.cpp b/libc/src/semaphore/linux/sem_wait.cpp
new file mode 100644
index 0000000000000..481e0406c5c83
--- /dev/null
+++ b/libc/src/semaphore/linux/sem_wait.cpp
@@ -0,0 +1,34 @@
+//===-- Linux implementation of sem_wait ----------------------------------===//
+//
+// 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/sem_wait.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/semaphore/linux/semaphore.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sem_wait, (sem_t * sem)) {
+ Semaphore *semaphore = reinterpret_cast<Semaphore *>(sem);
+ if (!semaphore->is_valid()) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ if (int err = semaphore->wait()) {
+ libc_errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/semaphore/linux/semaphore.h b/libc/src/semaphore/linux/semaphore.h
index 8069336b5d53f..2bde8d6bfe084 100644
--- a/libc/src/semaphore/linux/semaphore.h
+++ b/libc/src/semaphore/linux/semaphore.h
@@ -10,12 +10,13 @@
#define LLVM_LIBC_SRC_SEMAPHORE_LINUX_SEMAPHORE_H
#include "hdr/errno_macros.h"
+#include "hdr/limits_macros.h"
#include "hdr/time_macros.h"
#include "hdr/types/clockid_t.h"
#include "hdr/types/mode_t.h"
#include "hdr/types/struct_timespec.h"
+#include "include/llvm-libc-types/sem_t.h"
#include "src/__support/CPP/atomic.h"
-#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/libc_assert.h"
@@ -24,10 +25,6 @@
namespace LIBC_NAMESPACE_DECL {
-// Define SEM_VALUE_MAX as INT_MAX
-constexpr unsigned int SEM_VALUE_MAX =
- static_cast<unsigned int>(cpp::numeric_limits<int>::max());
-
class Semaphore {
Futex value;
unsigned int canary;
@@ -186,6 +183,14 @@ class Semaphore {
static int unlink(const char *name);
};
+// The public sem_t mirrors the layout of the internal Semaphore class.
+// At entrypoints sem_t object operate through a reinterpret_cast,
+// so they must be the same layout.
+static_assert(sizeof(Semaphore) == sizeof(sem_t) &&
+ alignof(Semaphore) == alignof(sem_t),
+ "The public sem_t type must be of the same size and alignment as "
+ "the internal semaphore type.");
+
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_SEMAPHORE_LINUX_SEMAPHORE_H
diff --git a/libc/src/semaphore/sem_clockwait.h b/libc/src/semaphore/sem_clockwait.h
new file mode 100644
index 0000000000000..552b2fee50db4
--- /dev/null
+++ b/libc/src/semaphore/sem_clockwait.h
@@ -0,0 +1,24 @@
+//===-- Implementation header for sem_clockwait function --------*- 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_SEMAPHORE_SEM_CLOCKWAIT_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_CLOCKWAIT_H
+
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/sem_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_clockwait(sem_t *__restrict sem, clockid_t clock_id,
+ const struct timespec *__restrict abstime);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_CLOCKWAIT_H
diff --git a/libc/src/semaphore/sem_close.h b/libc/src/semaphore/sem_close.h
new file mode 100644
index 0000000000000..31048e15d49a0
--- /dev/null
+++ b/libc/src/semaphore/sem_close.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_close function ------------*- 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_SEMAPHORE_SEM_CLOSE_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_CLOSE_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_close(sem_t *sem);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_CLOSE_H
diff --git a/libc/src/semaphore/sem_destroy.h b/libc/src/semaphore/sem_destroy.h
new file mode 100644
index 0000000000000..3e088981108cf
--- /dev/null
+++ b/libc/src/semaphore/sem_destroy.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_destroy function ----------*- 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_SEMAPHORE_SEM_DESTROY_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_DESTROY_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_destroy(sem_t *sem);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_DESTROY_H
diff --git a/libc/src/semaphore/sem_getvalue.h b/libc/src/semaphore/sem_getvalue.h
new file mode 100644
index 0000000000000..3f21966826969
--- /dev/null
+++ b/libc/src/semaphore/sem_getvalue.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_getvalue function ---------*- 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_SEMAPHORE_SEM_GETVALUE_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_GETVALUE_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_getvalue(sem_t *__restrict sem, int *__restrict sval);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_GETVALUE_H
diff --git a/libc/src/semaphore/sem_init.h b/libc/src/semaphore/sem_init.h
new file mode 100644
index 0000000000000..609df125d0722
--- /dev/null
+++ b/libc/src/semaphore/sem_init.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_init function -------------*- 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_SEMAPHORE_SEM_INIT_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_INIT_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_init(sem_t *sem, int pshared, unsigned int value);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_INIT_H
diff --git a/libc/src/semaphore/sem_open.h b/libc/src/semaphore/sem_open.h
new file mode 100644
index 0000000000000..853bdb9bd8a0a
--- /dev/null
+++ b/libc/src/semaphore/sem_open.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_open function -------------*- 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_SEMAPHORE_SEM_OPEN_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_OPEN_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+sem_t *sem_open(const char *name, int oflag, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_OPEN_H
diff --git a/libc/src/semaphore/sem_post.h b/libc/src/semaphore/sem_post.h
new file mode 100644
index 0000000000000..a0b572dbcf965
--- /dev/null
+++ b/libc/src/semaphore/sem_post.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_post function -------------*- 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_SEMAPHORE_SEM_POST_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_POST_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_post(sem_t *sem);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_POST_H
diff --git a/libc/src/semaphore/sem_timedwait.h b/libc/src/semaphore/sem_timedwait.h
new file mode 100644
index 0000000000000..a62c79331901b
--- /dev/null
+++ b/libc/src/semaphore/sem_timedwait.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for sem_timedwait function --------*- 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_SEMAPHORE_SEM_TIMEDWAIT_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_TIMEDWAIT_H
+
+#include "hdr/types/sem_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_timedwait(sem_t *__restrict sem,
+ const struct timespec *__restrict abstime);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_TIMEDWAIT_H
diff --git a/libc/src/semaphore/sem_trywait.h b/libc/src/semaphore/sem_trywait.h
new file mode 100644
index 0000000000000..e6c9a11900abf
--- /dev/null
+++ b/libc/src/semaphore/sem_trywait.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_trywait function ----------*- 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_SEMAPHORE_SEM_TRYWAIT_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_TRYWAIT_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_trywait(sem_t *sem);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_TRYWAIT_H
diff --git a/libc/src/semaphore/sem_unlink.h b/libc/src/semaphore/sem_unlink.h
new file mode 100644
index 0000000000000..664e321e58877
--- /dev/null
+++ b/libc/src/semaphore/sem_unlink.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for sem_unlink function -----------*- 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_SEMAPHORE_SEM_UNLINK_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_UNLINK_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_unlink(const char *name);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_UNLINK_H
diff --git a/libc/src/semaphore/sem_wait.h b/libc/src/semaphore/sem_wait.h
new file mode 100644
index 0000000000000..de2de47d3a6f2
--- /dev/null
+++ b/libc/src/semaphore/sem_wait.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sem_wait function -------------*- 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_SEMAPHORE_SEM_WAIT_H
+#define LLVM_LIBC_SRC_SEMAPHORE_SEM_WAIT_H
+
+#include "hdr/types/sem_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sem_wait(sem_t *sem);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SEMAPHORE_SEM_WAIT_H
diff --git a/libc/test/src/semaphore/CMakeLists.txt b/libc/test/src/semaphore/CMakeLists.txt
index 07095686cac2c..25da2332a263a 100644
--- a/libc/test/src/semaphore/CMakeLists.txt
+++ b/libc/test/src/semaphore/CMakeLists.txt
@@ -1,3 +1,53 @@
+add_custom_target(libc_semaphore_unittests)
+
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
+
+add_libc_test(
+ sem_test
+ SUITE
+ libc_semaphore_unittests
+ SRCS
+ sem_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.limits_macros
+ libc.hdr.time_macros
+ libc.hdr.types.sem_t
+ libc.hdr.types.struct_timespec
+ libc.src.__support.time.clock_gettime
+ libc.src.errno.errno
+ libc.src.semaphore.sem_clockwait
+ libc.src.semaphore.sem_destroy
+ libc.src.semaphore.sem_getvalue
+ libc.src.semaphore.sem_init
+ libc.src.semaphore.sem_post
+ libc.src.semaphore.sem_timedwait
+ libc.src.semaphore.sem_trywait
+ libc.src.semaphore.sem_wait
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_test(
+ sem_open_test
+ SUITE
+ libc_semaphore_unittests
+ SRCS
+ sem_open_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fcntl_macros
+ libc.hdr.semaphore_macros
+ libc.hdr.types.sem_t
+ libc.src.errno.errno
+ libc.src.semaphore.sem_close
+ libc.src.semaphore.sem_getvalue
+ libc.src.semaphore.sem_open
+ libc.src.semaphore.sem_post
+ libc.src.semaphore.sem_unlink
+ libc.src.semaphore.sem_wait
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/semaphore/linux/CMakeLists.txt b/libc/test/src/semaphore/linux/CMakeLists.txt
index c28b823d3c743..53fce2315c056 100644
--- a/libc/test/src/semaphore/linux/CMakeLists.txt
+++ b/libc/test/src/semaphore/linux/CMakeLists.txt
@@ -1,5 +1,3 @@
-add_custom_target(libc_semaphore_unittests)
-
add_libc_test(
semaphore_test
SUITE
@@ -9,6 +7,7 @@ add_libc_test(
DEPENDS
libc.hdr.errno_macros
libc.hdr.fcntl_macros
+ libc.hdr.limits_macros
libc.hdr.time_macros
libc.hdr.types.struct_timespec
libc.src.__support.time.clock_gettime
diff --git a/libc/test/src/semaphore/linux/semaphore_test.cpp b/libc/test/src/semaphore/linux/semaphore_test.cpp
index 2ce28ce3c0a54..87f166e2aff8b 100644
--- a/libc/test/src/semaphore/linux/semaphore_test.cpp
+++ b/libc/test/src/semaphore/linux/semaphore_test.cpp
@@ -8,6 +8,7 @@
#include "hdr/errno_macros.h"
#include "hdr/fcntl_macros.h"
+#include "hdr/limits_macros.h"
#include "hdr/time_macros.h"
#include "hdr/types/struct_timespec.h"
#include "src/__support/time/clock_gettime.h"
@@ -90,9 +91,9 @@ TEST(LlvmLibcSemaphoreTest, TimedWaitNullTime) {
TEST(LlvmLibcSemaphoreTest, PostOverflow) {
// The value exceeds maximum, post() must fail with EOVERFLOW
- Semaphore sem(LIBC_NAMESPACE::SEM_VALUE_MAX, /*is_shared=*/false);
+ Semaphore sem(SEM_VALUE_MAX, /*is_shared=*/false);
ASSERT_EQ(sem.post(), EOVERFLOW);
- ASSERT_EQ(sem.getvalue(), static_cast<int>(LIBC_NAMESPACE::SEM_VALUE_MAX));
+ ASSERT_EQ(sem.getvalue(), SEM_VALUE_MAX);
}
TEST(LlvmLibcSemaphoreTest, TimedWaitTimeout) {
diff --git a/libc/test/src/semaphore/sem_open_test.cpp b/libc/test/src/semaphore/sem_open_test.cpp
new file mode 100644
index 0000000000000..31d4d5a359358
--- /dev/null
+++ b/libc/test/src/semaphore/sem_open_test.cpp
@@ -0,0 +1,102 @@
+//===-- Unittests for named POSIX semaphores ------------------------------===//
+//
+// 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 "hdr/errno_macros.h"
+#include "hdr/fcntl_macros.h"
+#include "hdr/semaphore_macros.h"
+#include "hdr/types/sem_t.h"
+#include "src/semaphore/sem_close.h"
+#include "src/semaphore/sem_getvalue.h"
+#include "src/semaphore/sem_open.h"
+#include "src/semaphore/sem_post.h"
+#include "src/semaphore/sem_unlink.h"
+#include "src/semaphore/sem_wait.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcSemOpenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcSemOpenTest, OpenCloseUnlink) {
+ const char *name = APPEND_LIBC_TEST("/llvmlibc_sem_open");
+
+ // Clear any leftover from a previous run
+ LIBC_NAMESPACE::sem_unlink(name);
+ LIBC_NAMESPACE::libc_errno = 0;
+
+ sem_t *sem = LIBC_NAMESPACE::sem_open(name, O_CREAT | O_EXCL, 0644, 7);
+ ASSERT_NE(sem, SEM_FAILED);
+ ASSERT_ERRNO_SUCCESS();
+
+ int value = -1;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_getvalue(sem, &value), Succeeds());
+ EXPECT_EQ(value, 7);
+
+ // A named semaphore supports the same operations as an unnamed one.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_wait(sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_post(sem), Succeeds());
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_close(sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_unlink(name), Succeeds());
+}
+
+TEST_F(LlvmLibcSemOpenTest, OpenExisting) {
+ const char *name = APPEND_LIBC_TEST("/llvmlibc_sem_open_existing");
+
+ LIBC_NAMESPACE::sem_unlink(name);
+ LIBC_NAMESPACE::libc_errno = 0;
+
+ sem_t *first = LIBC_NAMESPACE::sem_open(name, O_CREAT | O_EXCL, 0644, 10);
+ ASSERT_NE(first, SEM_FAILED);
+
+ // The name already exists, so the value argument is ignored.
+ sem_t *second = LIBC_NAMESPACE::sem_open(name, O_CREAT, 0644, 99);
+ ASSERT_NE(second, SEM_FAILED);
+
+ int value = -1;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_getvalue(second, &value), Succeeds());
+ EXPECT_EQ(value, 10);
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_close(second), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_close(first), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_unlink(name), Succeeds());
+}
+
+TEST_F(LlvmLibcSemOpenTest, OpenExclusiveTwiceFails) {
+ const char *name = APPEND_LIBC_TEST("/llvmlibc_sem_open_excl");
+
+ LIBC_NAMESPACE::sem_unlink(name);
+ LIBC_NAMESPACE::libc_errno = 0;
+
+ sem_t *sem = LIBC_NAMESPACE::sem_open(name, O_CREAT | O_EXCL, 0644, 1);
+ ASSERT_NE(sem, SEM_FAILED);
+
+ EXPECT_EQ(LIBC_NAMESPACE::sem_open(name, O_CREAT | O_EXCL, 0644, 1),
+ SEM_FAILED);
+ ASSERT_ERRNO_EQ(EEXIST);
+ LIBC_NAMESPACE::libc_errno = 0;
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_close(sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_unlink(name), Succeeds());
+}
+
+TEST_F(LlvmLibcSemOpenTest, OpenNonExistent) {
+ const char *name = APPEND_LIBC_TEST("/llvmlibc_sem_missing");
+
+ // Without O_CREAT the name must already exist.
+ EXPECT_EQ(LIBC_NAMESPACE::sem_open(name, 0), SEM_FAILED);
+ ASSERT_ERRNO_EQ(ENOENT);
+}
+
+TEST_F(LlvmLibcSemOpenTest, UnlinkNonExistent) {
+ const char *name = APPEND_LIBC_TEST("/llvmlibc_sem_missing_unlink");
+
+ EXPECT_THAT(LIBC_NAMESPACE::sem_unlink(name), Fails(ENOENT));
+}
diff --git a/libc/test/src/semaphore/sem_test.cpp b/libc/test/src/semaphore/sem_test.cpp
new file mode 100644
index 0000000000000..3749876ff1ea9
--- /dev/null
+++ b/libc/test/src/semaphore/sem_test.cpp
@@ -0,0 +1,195 @@
+//===-- Unittests for unnamed POSIX semaphores ----------------------------===//
+//
+// 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 "hdr/errno_macros.h"
+#include "hdr/limits_macros.h"
+#include "hdr/time_macros.h"
+#include "hdr/types/sem_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/time/clock_gettime.h"
+#include "src/semaphore/sem_clockwait.h"
+#include "src/semaphore/sem_destroy.h"
+#include "src/semaphore/sem_getvalue.h"
+#include "src/semaphore/sem_init.h"
+#include "src/semaphore/sem_post.h"
+#include "src/semaphore/sem_timedwait.h"
+#include "src/semaphore/sem_trywait.h"
+#include "src/semaphore/sem_wait.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcSemTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+// Returns an absolute deadline a few milliseconds past now on the given clock.
+static timespec deadline_in_10ms(clockid_t clock_id) {
+ timespec ts{};
+ LIBC_NAMESPACE::internal::clock_gettime(clock_id, &ts);
+ ts.tv_nsec += 10'000'000;
+ if (ts.tv_nsec >= 1'000'000'000) {
+ ts.tv_sec += 1;
+ ts.tv_nsec -= 1'000'000'000;
+ }
+ return ts;
+}
+
+TEST_F(LlvmLibcSemTest, InitGetValueDestroy) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 3), Succeeds());
+
+ int value = -1;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_getvalue(&sem, &value), Succeeds());
+ EXPECT_EQ(value, 3);
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, InitValueTooLarge) {
+ sem_t sem;
+ // A count above SEM_VALUE_MAX cannot be represented.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(
+ &sem, 0, static_cast<unsigned int>(SEM_VALUE_MAX) + 1),
+ Fails(EINVAL));
+}
+
+TEST_F(LlvmLibcSemTest, InitShared) {
+ sem_t sem;
+ // A non-zero pshared is accepted; the semaphore then uses the shared futex
+ // addressing mode.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 1, 1), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_wait(&sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_post(&sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, UseAfterDestroy) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 1), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+
+ // The canary no longer matches, so every operation reports EINVAL rather
+ // than acting on a destroyed semaphore.
+ int value = -1;
+ EXPECT_THAT(LIBC_NAMESPACE::sem_getvalue(&sem, &value), Fails(EINVAL));
+ EXPECT_THAT(LIBC_NAMESPACE::sem_post(&sem), Fails(EINVAL));
+ EXPECT_THAT(LIBC_NAMESPACE::sem_wait(&sem), Fails(EINVAL));
+ EXPECT_THAT(LIBC_NAMESPACE::sem_trywait(&sem), Fails(EINVAL));
+ EXPECT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Fails(EINVAL));
+
+ timespec ts = deadline_in_10ms(CLOCK_REALTIME);
+ EXPECT_THAT(LIBC_NAMESPACE::sem_timedwait(&sem, &ts), Fails(EINVAL));
+ EXPECT_THAT(LIBC_NAMESPACE::sem_clockwait(&sem, CLOCK_MONOTONIC, &ts),
+ Fails(EINVAL));
+}
+
+TEST_F(LlvmLibcSemTest, PostAndWait) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 0), Succeeds());
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_post(&sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_post(&sem), Succeeds());
+
+ int value = -1;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_getvalue(&sem, &value), Succeeds());
+ EXPECT_EQ(value, 2);
+
+ // The count is positive, so neither wait blocks.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_wait(&sem), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_wait(&sem), Succeeds());
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_getvalue(&sem, &value), Succeeds());
+ EXPECT_EQ(value, 0);
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, TryWait) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 1), Succeeds());
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_trywait(&sem), Succeeds());
+
+ // The count is now zero, so a non-blocking wait reports EAGAIN.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_trywait(&sem), Fails(EAGAIN));
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, PostOverflow) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(
+ &sem, 0, static_cast<unsigned int>(SEM_VALUE_MAX)),
+ Succeeds());
+
+ // Incrementing past SEM_VALUE_MAX is refused and leaves the count alone.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_post(&sem), Fails(EOVERFLOW));
+
+ int value = -1;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_getvalue(&sem, &value), Succeeds());
+ EXPECT_EQ(value, SEM_VALUE_MAX);
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, TimedWaitLocksImmediately) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 1), Succeeds());
+
+ // The semaphore can be locked right away, so the deadline is never read.
+ ASSERT_THAT(LIBC_NAMESPACE::sem_timedwait(&sem, nullptr), Succeeds());
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, TimedWaitTimeout) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 0), Succeeds());
+
+ timespec ts = deadline_in_10ms(CLOCK_REALTIME);
+ ASSERT_THAT(LIBC_NAMESPACE::sem_timedwait(&sem, &ts), Fails(ETIMEDOUT));
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, TimedWaitInvalidTimespec) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 0), Succeeds());
+
+ timespec ts{};
+ ts.tv_sec = 1;
+ ts.tv_nsec = 1'000'000'001;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_timedwait(&sem, &ts), Fails(EINVAL));
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, ClockWaitMonotonicTimeout) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 0), Succeeds());
+
+ timespec ts = deadline_in_10ms(CLOCK_MONOTONIC);
+ ASSERT_THAT(LIBC_NAMESPACE::sem_clockwait(&sem, CLOCK_MONOTONIC, &ts),
+ Fails(ETIMEDOUT));
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
+
+TEST_F(LlvmLibcSemTest, ClockWaitUnsupportedClock) {
+ sem_t sem;
+ ASSERT_THAT(LIBC_NAMESPACE::sem_init(&sem, 0, 0), Succeeds());
+
+ timespec ts{};
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ ASSERT_THAT(
+ LIBC_NAMESPACE::sem_clockwait(&sem, static_cast<clockid_t>(99), &ts),
+ Fails(EINVAL));
+
+ ASSERT_THAT(LIBC_NAMESPACE::sem_destroy(&sem), Succeeds());
+}
More information about the libc-commits
mailing list