[libc-commits] [libc] bed9fa2 - [libc][sys/sem] Add sys v sem headers and syscall wrapper implementation (#185914)
via libc-commits
libc-commits at lists.llvm.org
Thu Mar 19 07:12:12 PDT 2026
Author: Pengxiang Huang
Date: 2026-03-19T10:12:06-04:00
New Revision: bed9fa2de54aafcb854dfb4cee7617db15895a99
URL: https://github.com/llvm/llvm-project/commit/bed9fa2de54aafcb854dfb4cee7617db15895a99
DIFF: https://github.com/llvm/llvm-project/commit/bed9fa2de54aafcb854dfb4cee7617db15895a99.diff
LOG: [libc][sys/sem] Add sys v sem headers and syscall wrapper implementation (#185914)
Fix #182161
Based on the last PR #182700 implementing sys/ipc.
Added:
libc/hdr/sys_ipc_macros.h
libc/hdr/sys_sem_macros.h
libc/hdr/types/struct_sembuf.h
libc/hdr/types/struct_semid_ds.h
libc/hdr/types/struct_seminfo.h
libc/include/llvm-libc-macros/linux/sys-sem-macros.h
libc/include/llvm-libc-macros/sys-sem-macros.h
libc/include/llvm-libc-types/struct_sembuf.h
libc/include/llvm-libc-types/struct_semid_ds.h
libc/include/llvm-libc-types/struct_seminfo.h
libc/include/sys/sem.yaml
libc/src/sys/sem/CMakeLists.txt
libc/src/sys/sem/linux/CMakeLists.txt
libc/src/sys/sem/linux/semctl.cpp
libc/src/sys/sem/linux/semget.cpp
libc/src/sys/sem/linux/semop.cpp
libc/src/sys/sem/semctl.h
libc/src/sys/sem/semget.h
libc/src/sys/sem/semop.h
libc/test/integration/src/sys/CMakeLists.txt
libc/test/integration/src/sys/sem/CMakeLists.txt
libc/test/integration/src/sys/sem/sem_test.cpp
libc/test/src/sys/sem/CMakeLists.txt
libc/test/src/sys/sem/linux/CMakeLists.txt
libc/test/src/sys/sem/linux/sem_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/config/linux/x86_64/headers.txt
libc/hdr/CMakeLists.txt
libc/hdr/types/CMakeLists.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-macros/CMakeLists.txt
libc/include/llvm-libc-macros/linux/CMakeLists.txt
libc/include/llvm-libc-macros/linux/sys-ipc-macros.h
libc/include/llvm-libc-types/CMakeLists.txt
libc/src/sys/CMakeLists.txt
libc/test/integration/src/CMakeLists.txt
libc/test/src/sys/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 1039c28eb5c6f..e76f2f2ee523d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -288,6 +288,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.resource.getrlimit
libc.src.sys.resource.setrlimit
+ # sys/sem.h entrypoints
+ libc.src.sys.sem.semget
+ libc.src.sys.sem.semctl
+ libc.src.sys.sem.semop
+
# sys/sendfile entrypoints
libc.src.sys.sendfile.sendfile
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 543d151465663..157740033aabf 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -45,6 +45,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_random
libc.include.sys_resource
libc.include.sys_select
+ libc.include.sys_sem
libc.include.sys_socket
libc.include.sys_stat
libc.include.sys_statvfs
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 8a1f40e64ca16..0a496206f4909 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -149,6 +149,24 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.sys_ioctl_macros
)
+add_proxy_header_library(
+ sys_ipc_macros
+ HDRS
+ sys_ipc_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.sys_ipc
+ libc.include.llvm-libc-macros.sys_ipc_macros
+)
+
+add_proxy_header_library(
+ sys_sem_macros
+ HDRS
+ sys_sem_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.sys_sem
+ libc.include.llvm-libc-macros.sys_sem_macros
+)
+
add_proxy_header_library(
sys_socket_macros
HDRS
diff --git a/libc/hdr/sys_ipc_macros.h b/libc/hdr/sys_ipc_macros.h
new file mode 100644
index 0000000000000..f62ae4b6ed259
--- /dev/null
+++ b/libc/hdr/sys_ipc_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from sys/ipc.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_SYS_IPC_MACROS_H
+#define LLVM_LIBC_HDR_SYS_IPC_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/sys-ipc-macros.h"
+
+#else // Overlay mode
+
+#include <sys/ipc.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_IPC_MACROS_H
diff --git a/libc/hdr/sys_sem_macros.h b/libc/hdr/sys_sem_macros.h
new file mode 100644
index 0000000000000..1082840ea5983
--- /dev/null
+++ b/libc/hdr/sys_sem_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from sys/sem.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_SYS_SEM_MACROS_H
+#define LLVM_LIBC_HDR_SYS_SEM_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/sys-sem-macros.h"
+
+#else // Overlay mode
+
+#include <sys/sem.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_SEM_MACROS_H
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 84a26ecf8fb5e..68b74700aef9a 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -514,6 +514,33 @@ add_proxy_header_library(
libc.include.sys_resource
)
+add_proxy_header_library(
+ struct_semid_ds
+ HDRS
+ struct_semid_ds.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.struct_semid_ds
+ libc.include.sys_sem
+)
+
+add_proxy_header_library(
+ struct_sembuf
+ HDRS
+ struct_sembuf.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.struct_sembuf
+ libc.include.sys_sem
+)
+
+add_proxy_header_library(
+ struct_seminfo
+ HDRS
+ struct_seminfo.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.struct_seminfo
+ libc.include.sys_sem
+)
+
add_proxy_header_library(
gid_t
HDRS
diff --git a/libc/hdr/types/struct_sembuf.h b/libc/hdr/types/struct_sembuf.h
new file mode 100644
index 0000000000000..d5efcbaa01526
--- /dev/null
+++ b/libc/hdr/types/struct_sembuf.h
@@ -0,0 +1,22 @@
+//===-- Proxy for struct sembuf -------------------------------------------===//
+//
+// 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_STRUCT_SEMBUF_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_SEMBUF_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_sembuf.h"
+
+#else // Overlay mode
+
+#include <sys/sem.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_SEMBUF_H
diff --git a/libc/hdr/types/struct_semid_ds.h b/libc/hdr/types/struct_semid_ds.h
new file mode 100644
index 0000000000000..f4d8b36362d41
--- /dev/null
+++ b/libc/hdr/types/struct_semid_ds.h
@@ -0,0 +1,22 @@
+//===-- Proxy for struct semid_ds -----------------------------------------===//
+//
+// 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_STRUCT_SEMID_DS_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_SEMID_DS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_semid_ds.h"
+
+#else // Overlay mode
+
+#include <sys/sem.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_SEMID_DS_H
diff --git a/libc/hdr/types/struct_seminfo.h b/libc/hdr/types/struct_seminfo.h
new file mode 100644
index 0000000000000..86259425712da
--- /dev/null
+++ b/libc/hdr/types/struct_seminfo.h
@@ -0,0 +1,22 @@
+//===-- Proxy for struct seminfo ------------------------------------------===//
+//
+// 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_STRUCT_SEMINFO_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_SEMINFO_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_seminfo.h"
+
+#else // Overlay mode
+
+#include <sys/sem.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_SEMINFO_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 9eae20c820e98..e0e2e058da859 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -660,6 +660,21 @@ add_header_macro(
.llvm-libc-types.struct_timeval
)
+add_header_macro(
+ sys_sem
+ ../libc/include/sys/sem.yaml
+ sys/sem.h
+ DEPENDS
+ .llvm_libc_common_h
+ .llvm-libc-macros.sys_sem_macros
+ .llvm-libc-types.key_t
+ .llvm-libc-types.size_t
+ .llvm-libc-types.struct_ipc_perm
+ .llvm-libc-types.struct_semid_ds
+ .llvm-libc-types.struct_sembuf
+ .llvm-libc-types.struct_seminfo
+)
+
add_header_macro(
sys_sendfile
../libc/include/sys/sendfile.yaml
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 553879e27d3d2..6a91b394a8786 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -232,6 +232,12 @@ add_macro_header(
sys-ipc-macros.h
)
+add_macro_header(
+ sys_sem_macros
+ HDR
+ sys-sem-macros.h
+)
+
add_macro_header(
sys_stat_macros
HDR
diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt
index 60376641b50f6..e6a95457a5b91 100644
--- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt
@@ -46,6 +46,12 @@ add_header(
sys-random-macros.h
)
+add_header(
+ sys_sem_macros
+ HDR
+ sys-sem-macros.h
+)
+
add_header(
sys_socket_macros
HDR
diff --git a/libc/include/llvm-libc-macros/linux/sys-ipc-macros.h b/libc/include/llvm-libc-macros/linux/sys-ipc-macros.h
index 87546ac314d83..6c8443cef5b3c 100644
--- a/libc/include/llvm-libc-macros/linux/sys-ipc-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-ipc-macros.h
@@ -20,5 +20,6 @@
#define IPC_RMID 0
#define IPC_SET 1
#define IPC_STAT 2
+#define IPC_INFO 3
#endif // LLVM_LIBC_MACROS_LINUX_SYS_IPC_MACROS_H
diff --git a/libc/include/llvm-libc-macros/linux/sys-sem-macros.h b/libc/include/llvm-libc-macros/linux/sys-sem-macros.h
new file mode 100644
index 0000000000000..1ca62e6b1e29d
--- /dev/null
+++ b/libc/include/llvm-libc-macros/linux/sys-sem-macros.h
@@ -0,0 +1,29 @@
+//===-- Definition of macros from sys/sem.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_LINUX_SYS_SEM_MACROS_H
+#define LLVM_LIBC_MACROS_LINUX_SYS_SEM_MACROS_H
+
+// semop flags
+#define SEM_UNDO 0x1000
+
+// semctl command definitions
+#define GETPID 11
+#define GETVAL 12
+#define GETALL 13
+#define GETNCNT 14
+#define GETZCNT 15
+#define SETVAL 16
+#define SETALL 17
+
+// linux specific extensions
+#define SEM_STAT 18
+#define SEM_INFO 19
+#define SEM_STAT_ANY 20
+
+#endif // LLVM_LIBC_MACROS_LINUX_SYS_SEM_MACROS_H
diff --git a/libc/include/llvm-libc-macros/sys-sem-macros.h b/libc/include/llvm-libc-macros/sys-sem-macros.h
new file mode 100644
index 0000000000000..801f82e79f5d4
--- /dev/null
+++ b/libc/include/llvm-libc-macros/sys-sem-macros.h
@@ -0,0 +1,16 @@
+//===-- Macros defined in sys/sem.h header file ---------------------------===//
+//
+// 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_SYS_SEM_MACROS_H
+#define LLVM_LIBC_MACROS_SYS_SEM_MACROS_H
+
+#ifdef __linux__
+#include "linux/sys-sem-macros.h"
+#endif
+
+#endif // LLVM_LIBC_MACROS_SYS_SEM_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index b03e4fa830b05..44b3a7e82bee1 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -101,6 +101,15 @@ add_header(
add_header(struct_pollfd HDR struct_pollfd.h)
add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t)
add_header(struct_sched_param HDR struct_sched_param.h)
+add_header(struct_sembuf HDR struct_sembuf.h)
+add_header(struct_seminfo HDR struct_seminfo.h)
+add_header(
+ struct_semid_ds
+ HDR struct_semid_ds.h
+ DEPENDS
+ .struct_ipc_perm
+ .time_t
+)
add_header(struct_timeval HDR struct_timeval.h DEPENDS .suseconds_t .time_t)
add_header(struct_itimerval HDR struct_itimerval.h DEPENDS .struct_timeval)
add_header(struct_rusage HDR struct_rusage.h DEPENDS .struct_timeval)
diff --git a/libc/include/llvm-libc-types/struct_sembuf.h b/libc/include/llvm-libc-types/struct_sembuf.h
new file mode 100644
index 0000000000000..8358effdf790b
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_sembuf.h
@@ -0,0 +1,19 @@
+//===-- Definition of struct sembuf ---------------------------------------===//
+//
+// 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_STRUCT_SEMBUF_H
+#define LLVM_LIBC_TYPES_STRUCT_SEMBUF_H
+
+struct sembuf {
+ // changed to unsigned short from short since POSIX issue 7
+ unsigned short sem_num;
+ short sem_op;
+ short sem_flg;
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_SEMBUF_H
diff --git a/libc/include/llvm-libc-types/struct_semid_ds.h b/libc/include/llvm-libc-types/struct_semid_ds.h
new file mode 100644
index 0000000000000..775f52604b0a3
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_semid_ds.h
@@ -0,0 +1,33 @@
+//===-- Definition of struct semid_ds -------------------------------------===//
+//
+// 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_STRUCT_SEMID_DS_H
+#define LLVM_LIBC_TYPES_STRUCT_SEMID_DS_H
+
+#include "struct_ipc_perm.h"
+#include "time_t.h"
+
+struct semid_ds {
+ struct ipc_perm sem_perm;
+#ifdef __linux__
+ time_t sem_otime;
+ unsigned long __unused1;
+ time_t sem_ctime;
+ unsigned long __unused2;
+#else
+ time_t sem_otime;
+ time_t sem_ctime;
+#endif
+ unsigned long sem_nsems;
+#ifdef __linux__
+ unsigned long __unused3;
+ unsigned long __unused4;
+#endif
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_SEMID_DS_H
diff --git a/libc/include/llvm-libc-types/struct_seminfo.h b/libc/include/llvm-libc-types/struct_seminfo.h
new file mode 100644
index 0000000000000..90610ac828a7f
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_seminfo.h
@@ -0,0 +1,27 @@
+//===-- Definition of struct seminfo --------------------------------------===//
+//
+// 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_STRUCT_SEMINFO_H
+#define LLVM_LIBC_TYPES_STRUCT_SEMINFO_H
+
+#ifdef __linux__
+struct seminfo {
+ int semmap;
+ int semmni;
+ int semmns;
+ int semmnu;
+ int semmsl;
+ int semopm;
+ int semume;
+ int semusz;
+ int semvmx;
+ int semaem;
+};
+#endif
+
+#endif // LLVM_LIBC_TYPES_STRUCT_SEMINFO_H
diff --git a/libc/include/sys/sem.yaml b/libc/include/sys/sem.yaml
new file mode 100644
index 0000000000000..6e583d669d250
--- /dev/null
+++ b/libc/include/sys/sem.yaml
@@ -0,0 +1,84 @@
+header: sys/sem.h
+standards:
+ - posix
+ - linux
+macros:
+ - macro_name: SEM_UNDO
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: GETNCNT
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: GETPID
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: GETVAL
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: GETALL
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: GETZCNT
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: SETVAL
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: SETALL
+ macro_header: sys-sem-macros.h
+ standards:
+ - posix
+ - macro_name: SEM_STAT
+ macro_header: sys-sem-macros.h
+ standards:
+ - linux
+ - macro_name: SEM_INFO
+ macro_header: sys-sem-macros.h
+ standards:
+ - linux
+ - macro_name: SEM_STAT_ANY
+ macro_header: sys-sem-macros.h
+ standards:
+ - linux
+types:
+ - type_name: key_t
+ - type_name: size_t
+ - type_name: struct_ipc_perm
+ - type_name: struct_semid_ds
+ - type_name: struct_sembuf
+ - type_name: struct_seminfo
+ standards:
+ - linux
+functions:
+ - name: semctl
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: int
+ - type: int
+ - type: int
+ - type: '...'
+ - name: semget
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: key_t
+ - type: int
+ - type: int
+ - name: semop
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: int
+ - type: struct sembuf *
+ - type: size_t
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index 1c17ec31a8592..41becce798ddd 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -6,6 +6,7 @@ add_subdirectory(random)
add_subdirectory(resource)
add_subdirectory(select)
add_subdirectory(socket)
+add_subdirectory(sem)
add_subdirectory(sendfile)
add_subdirectory(stat)
add_subdirectory(statvfs)
diff --git a/libc/src/sys/sem/CMakeLists.txt b/libc/src/sys/sem/CMakeLists.txt
new file mode 100644
index 0000000000000..4b9bd851b9d2d
--- /dev/null
+++ b/libc/src/sys/sem/CMakeLists.txt
@@ -0,0 +1,24 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+ semget
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.semget
+)
+
+add_entrypoint_object(
+ semctl
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.semctl
+)
+
+add_entrypoint_object(
+ semop
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.semop
+)
diff --git a/libc/src/sys/sem/linux/CMakeLists.txt b/libc/src/sys/sem/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..0be957ab660d0
--- /dev/null
+++ b/libc/src/sys/sem/linux/CMakeLists.txt
@@ -0,0 +1,46 @@
+add_entrypoint_object(
+ semget
+ SRCS
+ semget.cpp
+ HDRS
+ ../semget.h
+ DEPENDS
+ libc.hdr.types.key_t
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ semctl
+ SRCS
+ semctl.cpp
+ HDRS
+ ../semctl.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.sys_ipc_macros
+ libc.hdr.sys_sem_macros
+ libc.hdr.types.struct_semid_ds
+ libc.hdr.types.struct_seminfo
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ semop
+ SRCS
+ semop.cpp
+ HDRS
+ ../semop.h
+ DEPENDS
+ libc.hdr.types.size_t
+ libc.hdr.types.struct_sembuf
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.errno.errno
+)
diff --git a/libc/src/sys/sem/linux/semctl.cpp b/libc/src/sys/sem/linux/semctl.cpp
new file mode 100644
index 0000000000000..1dd38f773004e
--- /dev/null
+++ b/libc/src/sys/sem/linux/semctl.cpp
@@ -0,0 +1,101 @@
+//===-- Linux implementation of semctl ------------------------------------===//
+//
+// 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/sys/sem/semctl.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/sys_ipc_macros.h"
+#include "hdr/sys_sem_macros.h"
+#include "hdr/types/struct_semid_ds.h"
+#include "hdr/types/struct_seminfo.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include <stdarg.h>
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, semctl, (int semid, int semnum, int cmd, ...)) {
+ // used to parse the fourth varargs argument
+ // its expected to be explicitly declared by application as an union type:
+ // union semun {
+ // int val;
+ // struct semid_ds *buf;
+ // unsigned short *array;
+ // struct seminfo *__buf; (* linux specific *)
+ // } arg;
+ unsigned long cmd_arg = 0;
+
+ // parse cmd_arg based on the flags
+ switch (cmd) {
+ // does not use the vargs
+ case IPC_RMID:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ break;
+
+ // use vargs as int, semun->val
+ case SETVAL: {
+ va_list vargs;
+ va_start(vargs, cmd);
+ cmd_arg = static_cast<unsigned long>(va_arg(vargs, int));
+ va_end(vargs);
+ break;
+ }
+
+ // use vargs as semid_ds*, semun->buf
+ case IPC_SET:
+ case IPC_STAT:
+ case SEM_STAT:
+ case SEM_STAT_ANY: {
+ va_list vargs;
+ va_start(vargs, cmd);
+ cmd_arg = reinterpret_cast<unsigned long>(va_arg(vargs, struct semid_ds *));
+ va_end(vargs);
+ break;
+ }
+
+ // use vargs as short*, semun->array
+ case GETALL:
+ case SETALL: {
+ va_list vargs;
+ va_start(vargs, cmd);
+ cmd_arg = reinterpret_cast<unsigned long>(va_arg(vargs, unsigned short *));
+ va_end(vargs);
+ break;
+ }
+
+ // linux specific, use vargs as seminfo*, semun->__buf
+ case IPC_INFO:
+ case SEM_INFO: {
+ va_list vargs;
+ va_start(vargs, cmd);
+ cmd_arg = reinterpret_cast<unsigned long>(va_arg(vargs, struct seminfo *));
+ va_end(vargs);
+ break;
+ }
+
+ // unrecognized flags
+ default:
+ libc_errno = EINVAL;
+ return -1;
+ }
+
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_semctl, semid, semnum, cmd,
+ cmd_arg);
+ if (ret < 0) {
+ libc_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/sem/linux/semget.cpp b/libc/src/sys/sem/linux/semget.cpp
new file mode 100644
index 0000000000000..b5a69056ccbd8
--- /dev/null
+++ b/libc/src/sys/sem/linux/semget.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of semget ------------------------------------===//
+//
+// 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/sys/sem/semget.h"
+
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, semget, (key_t key, int nsems, int semflg)) {
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_semget, key, nsems, semflg);
+ if (ret < 0) {
+ libc_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/sem/linux/semop.cpp b/libc/src/sys/sem/linux/semop.cpp
new file mode 100644
index 0000000000000..97d7d12daf898
--- /dev/null
+++ b/libc/src/sys/sem/linux/semop.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of semop -------------------------------------===//
+//
+// 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/sys/sem/semop.h"
+
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, semop, (int semid, struct sembuf *sops, size_t nsops)) {
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_semop, semid, sops, nsops);
+ if (ret < 0) {
+ libc_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/sem/semctl.h b/libc/src/sys/sem/semctl.h
new file mode 100644
index 0000000000000..b7046edba18b9
--- /dev/null
+++ b/libc/src/sys/sem/semctl.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for semctl ------------------------*- 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_SYS_SEM_SEMCTL_H
+#define LLVM_LIBC_SRC_SYS_SEM_SEMCTL_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int semctl(int semid, int semnum, int cmd, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SEM_SEMCTL_H
diff --git a/libc/src/sys/sem/semget.h b/libc/src/sys/sem/semget.h
new file mode 100644
index 0000000000000..7730b21eb0f7d
--- /dev/null
+++ b/libc/src/sys/sem/semget.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for semget ------------------------*- 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_SYS_SEM_SEMGET_H
+#define LLVM_LIBC_SRC_SYS_SEM_SEMGET_H
+
+#include "hdr/types/key_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int semget(key_t key, int nsems, int semflg);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SEM_SEMGET_H
diff --git a/libc/src/sys/sem/semop.h b/libc/src/sys/sem/semop.h
new file mode 100644
index 0000000000000..c1af69bd9218e
--- /dev/null
+++ b/libc/src/sys/sem/semop.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for semop -------------------------*- 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_SYS_SEM_SEMOP_H
+#define LLVM_LIBC_SRC_SYS_SEM_SEMOP_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/struct_sembuf.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int semop(int semid, struct sembuf *sops, size_t nsops);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SEM_SEMOP_H
diff --git a/libc/test/integration/src/CMakeLists.txt b/libc/test/integration/src/CMakeLists.txt
index 1104b3de99e9b..47c0716dc22b4 100644
--- a/libc/test/integration/src/CMakeLists.txt
+++ b/libc/test/integration/src/CMakeLists.txt
@@ -4,4 +4,5 @@ add_subdirectory(spawn)
add_subdirectory(stdio)
add_subdirectory(stdlib)
add_subdirectory(threads)
+add_subdirectory(sys)
add_subdirectory(unistd)
diff --git a/libc/test/integration/src/sys/CMakeLists.txt b/libc/test/integration/src/sys/CMakeLists.txt
new file mode 100644
index 0000000000000..9a6b3cd220e86
--- /dev/null
+++ b/libc/test/integration/src/sys/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(sem)
diff --git a/libc/test/integration/src/sys/sem/CMakeLists.txt b/libc/test/integration/src/sys/sem/CMakeLists.txt
new file mode 100644
index 0000000000000..286ccb72dae90
--- /dev/null
+++ b/libc/test/integration/src/sys/sem/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_custom_target(sys-sem-integration-tests)
+add_dependencies(libc-integration-tests sys-sem-integration-tests)
+
+add_integration_test(
+ sem_test
+ SUITE
+ sys-sem-integration-tests
+ SRCS
+ sem_test.cpp
+ DEPENDS
+ libc.hdr.fcntl_macros
+ libc.hdr.sys_ipc_macros
+ libc.hdr.sys_sem_macros
+ libc.hdr.types.struct_sembuf
+ libc.src.__support.threads.sleep
+ libc.src.fcntl.open
+ libc.src.signal.kill
+ libc.src.stdlib.exit
+ libc.src.sys.ipc.ftok
+ libc.src.sys.sem.semctl
+ libc.src.sys.sem.semget
+ libc.src.sys.sem.semop
+ libc.src.sys.wait.waitpid
+ libc.src.unistd.close
+ libc.src.unistd.fork
+ libc.src.unistd.unlink
+ libc.include.signal
+ libc.include.sys_wait
+)
diff --git a/libc/test/integration/src/sys/sem/sem_test.cpp b/libc/test/integration/src/sys/sem/sem_test.cpp
new file mode 100644
index 0000000000000..0d8532df89bea
--- /dev/null
+++ b/libc/test/integration/src/sys/sem/sem_test.cpp
@@ -0,0 +1,171 @@
+//===-- Integration test for sys/sem --------------------------------------===//
+//
+// 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/__support/threads/sleep.h"
+#include "src/fcntl/open.h"
+#include "src/signal/kill.h"
+#include "src/stdlib/exit.h"
+#include "src/sys/ipc/ftok.h"
+#include "src/sys/sem/semctl.h"
+#include "src/sys/sem/semget.h"
+#include "src/sys/sem/semop.h"
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/close.h"
+#include "src/unistd/fork.h"
+#include "src/unistd/unlink.h"
+
+#include "test/IntegrationTest/test.h"
+
+#include "hdr/fcntl_macros.h"
+#include "hdr/sys_ipc_macros.h"
+#include "hdr/sys_sem_macros.h"
+#include "hdr/types/struct_sembuf.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+// child try IPC_CREAT|IPC_EXCL,
+// but expect EEXIST then fall back to get the existing semaphore.
+static int sem_joiner_get(key_t semkey) {
+ // this expect to fail and return -1 because we used the same key
+ // and this semaphore has been initialized.
+ int sid = LIBC_NAMESPACE::semget(semkey, 1, IPC_CREAT | IPC_EXCL | 0666);
+ if (sid == -1 && errno == EEXIST)
+ // get the initialized semaphore id
+ sid = LIBC_NAMESPACE::semget(semkey, 0, 0);
+ return sid;
+}
+
+// fork a child that acquires the semaphore and hold untill killed.
+// returns child pid.
+static pid_t fork_sem_holder(key_t semkey) {
+ pid_t pid = LIBC_NAMESPACE::fork();
+ if (pid == 0) {
+ int sid = sem_joiner_get(semkey);
+ if (sid < 0)
+ LIBC_NAMESPACE::exit(1);
+ // try acquire and hold
+ // set flag to UNDO if process terminate unexpectedly
+ struct sembuf acq = {0, -1, SEM_UNDO};
+ if (LIBC_NAMESPACE::semop(sid, &acq, 1) != 0)
+ LIBC_NAMESPACE::exit(2);
+
+ // hold the semaphore until killed by parent.
+ while (1)
+ LIBC_NAMESPACE::sleep_briefly();
+ }
+ return pid;
+}
+
+// fork a child that tries to acquire (IPC_NOWAIT).
+// exit code: 0 = acquired, 1 = EAGAIN (full, try later again), 2+ = error.
+static pid_t fork_sem_try_acquire(key_t semkey) {
+ pid_t pid = LIBC_NAMESPACE::fork();
+ if (pid == 0) {
+ int sid = sem_joiner_get(semkey);
+ if (sid < 0)
+ LIBC_NAMESPACE::exit(3);
+ // try acquire
+ struct sembuf acq = {0, -1, SEM_UNDO | IPC_NOWAIT};
+
+ if (LIBC_NAMESPACE::semop(sid, &acq, 1) == 0)
+ LIBC_NAMESPACE::exit(0); // acquired
+
+ // exit with code 1 if EAGAIN
+ LIBC_NAMESPACE::exit(errno == EAGAIN ? 1 : 2);
+ }
+ return pid;
+}
+
+// wait for child to terminate.
+static int wait_for_child(pid_t pid) {
+ int status;
+ LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ return status;
+}
+
+// semaphore gate that allows at most two processes to enter
+void sem_gate_test() {
+ constexpr const char *TEST_FILE = "/tmp/sem_gate_test";
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_WRONLY, 0666);
+ ASSERT_TRUE(fd >= 0);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_TRUE(LIBC_NAMESPACE::close(fd) == 0);
+
+ key_t semkey = LIBC_NAMESPACE::ftok(TEST_FILE, 'a');
+ ASSERT_TRUE(semkey != key_t(-1));
+ ASSERT_ERRNO_SUCCESS();
+
+ // clean up stale semaphore from previous run because semaphore
+ // are kernel persistent, they can remain on the system if previous
+ // test fail and exit.
+ int old_semid = LIBC_NAMESPACE::semget(semkey, 1, 0);
+ if (old_semid != -1)
+ LIBC_NAMESPACE::semctl(old_semid, 0, IPC_RMID);
+ errno = 0;
+
+ // create a semaphore
+ int semid = LIBC_NAMESPACE::semget(semkey, 1, IPC_CREAT | IPC_EXCL | 0666);
+ ASSERT_TRUE(semid >= 0);
+ ASSERT_ERRNO_SUCCESS();
+
+ // increment the first semaphore by 2 that allows two processes to access
+ struct sembuf sbuf = {0, 2, 0};
+ ASSERT_TRUE(LIBC_NAMESPACE::semop(semid, &sbuf, 1) == 0);
+
+ // verify the first semaphore value
+ ASSERT_TRUE(LIBC_NAMESPACE::semctl(semid, 0, GETVAL) == 2);
+
+ // fork two children to hold the semaphore
+ pid_t holder1 = fork_sem_holder(semkey);
+ ASSERT_TRUE(holder1 > 0);
+ pid_t holder2 = fork_sem_holder(semkey);
+ ASSERT_TRUE(holder2 > 0);
+
+ // wait until both children have acquired so semaphore value reaches 0.
+ while (LIBC_NAMESPACE::semctl(semid, 0, GETVAL) > 0)
+ LIBC_NAMESPACE::sleep_briefly();
+
+ // check my current semaphore value is 0
+ ASSERT_TRUE(LIBC_NAMESPACE::semctl(semid, 0, GETVAL) == 0);
+
+ // now the semaphore gate is full
+ // fork another process to try to acquire it
+ pid_t blocked = fork_sem_try_acquire(semkey);
+ ASSERT_TRUE(blocked > 0);
+ int blocked_status = wait_for_child(blocked);
+ // check the exit status
+ ASSERT_TRUE(WIFEXITED(blocked_status));
+ ASSERT_EQ(WEXITSTATUS(blocked_status), 1); // EAGAIN (blocked)
+
+ // kill the first holder to make one slot avalaible in semaphore
+ LIBC_NAMESPACE::kill(holder1, SIGKILL);
+ wait_for_child(holder1);
+ ASSERT_TRUE(LIBC_NAMESPACE::semctl(semid, 0, GETVAL) == 1);
+
+ // then fork child again to try acquire
+ pid_t unblocked = fork_sem_try_acquire(semkey);
+ ASSERT_TRUE(unblocked > 0);
+ int unblocked_status = wait_for_child(unblocked);
+ // this child should get it since the slot is avalaible now
+ ASSERT_TRUE(WIFEXITED(unblocked_status));
+ ASSERT_EQ(WEXITSTATUS(unblocked_status), 0); // acquired
+
+ // cleanup
+ LIBC_NAMESPACE::kill(holder2, SIGKILL);
+ wait_for_child(holder2);
+ ASSERT_TRUE(LIBC_NAMESPACE::semctl(semid, 0, IPC_RMID) == 0);
+ ASSERT_TRUE(LIBC_NAMESPACE::unlink(TEST_FILE) == 0);
+}
+
+TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv,
+ [[maybe_unused]] char **envp) {
+ sem_gate_test();
+ return 0;
+}
diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt
index 3b5ea64fb1448..444f86f5d00a9 100644
--- a/libc/test/src/sys/CMakeLists.txt
+++ b/libc/test/src/sys/CMakeLists.txt
@@ -15,3 +15,4 @@ add_subdirectory(ipc)
add_subdirectory(uio)
add_subdirectory(time)
add_subdirectory(ioctl)
+add_subdirectory(sem)
diff --git a/libc/test/src/sys/sem/CMakeLists.txt b/libc/test/src/sys/sem/CMakeLists.txt
new file mode 100644
index 0000000000000..b4bbe81c92ff2
--- /dev/null
+++ b/libc/test/src/sys/sem/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${LIBC_TARGET_OS})
+endif()
diff --git a/libc/test/src/sys/sem/linux/CMakeLists.txt b/libc/test/src/sys/sem/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..7713c3c927b92
--- /dev/null
+++ b/libc/test/src/sys/sem/linux/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_custom_target(libc_sys_sem_unittests)
+
+add_libc_unittest(
+ sem_test
+ SUITE
+ libc_sys_sem_unittests
+ SRCS
+ sem_test.cpp
+ DEPENDS
+ libc.hdr.sys_ipc_macros
+ libc.hdr.sys_sem_macros
+ libc.hdr.types.struct_sembuf
+ libc.hdr.types.struct_semid_ds
+ libc.src.errno.errno
+ libc.src.sys.sem.semget
+ libc.src.sys.sem.semctl
+ libc.src.sys.sem.semop
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/sys/sem/linux/sem_test.cpp b/libc/test/src/sys/sem/linux/sem_test.cpp
new file mode 100644
index 0000000000000..0e21189f9bfbf
--- /dev/null
+++ b/libc/test/src/sys/sem/linux/sem_test.cpp
@@ -0,0 +1,72 @@
+//===-- Unittests for sys/sem.h entrypoints ------------------------------===//
+//
+// 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/sys_ipc_macros.h"
+#include "hdr/sys_sem_macros.h"
+#include "hdr/types/struct_sembuf.h"
+#include "hdr/types/struct_semid_ds.h"
+#include "src/sys/sem/semctl.h"
+#include "src/sys/sem/semget.h"
+#include "src/sys/sem/semop.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcSysSemTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
+
+TEST_F(LlvmLibcSysSemTest, SemgetSemctlSemopFlow) {
+
+ // create a semaphore
+ int semid =
+ LIBC_NAMESPACE::semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0600);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(semid, -1);
+
+ union semun set_val;
+ set_val.val = 1;
+
+ // set the semaphore value to 1
+ ASSERT_THAT(LIBC_NAMESPACE::semctl(semid, 0, SETVAL, set_val), Succeeds(0));
+
+ // get the value of semaphore should be 1
+ ASSERT_THAT(LIBC_NAMESPACE::semctl(semid, 0, GETVAL), Succeeds(1));
+
+ // decrement the semaphore value with IPC_NOWAIT flag
+ struct sembuf decrement_op = {0, -1, IPC_NOWAIT};
+ ASSERT_THAT(LIBC_NAMESPACE::semop(semid, &decrement_op, 1), Succeeds(0));
+
+ // get the value of semaphore should be 0
+ ASSERT_THAT(LIBC_NAMESPACE::semctl(semid, 0, GETVAL), Succeeds(0));
+
+ // increment the semaphore with IPC_NOWAIT flag
+ struct sembuf increment_op = {0, 1, IPC_NOWAIT};
+ ASSERT_THAT(LIBC_NAMESPACE::semop(semid, &increment_op, 1), Succeeds(0));
+
+ // get the semaphore value should be 1
+ ASSERT_THAT(LIBC_NAMESPACE::semctl(semid, 0, GETVAL), Succeeds(1));
+
+ // get the IPC stats
+ struct semid_ds sem_ds;
+ union semun stat_arg;
+ stat_arg.buf = &sem_ds;
+ ASSERT_THAT(LIBC_NAMESPACE::semctl(semid, 0, IPC_STAT, stat_arg),
+ Succeeds(0));
+
+ // the number of sem is 1
+ ASSERT_EQ(sem_ds.sem_nsems, 1UL);
+
+ // destroy the semaphore
+ ASSERT_THAT(LIBC_NAMESPACE::semctl(semid, 0, IPC_RMID), Succeeds(0));
+}
More information about the libc-commits
mailing list