[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