[libc-commits] [libc] [libc][time] Implement timer_create and timer_delete. (PR #217920)
via libc-commits
libc-commits at lists.llvm.org
Fri Aug 21 20:52:29 PDT 2026
https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/217920
>From bebb71142c288086e504ea4a52f845f8089262ea Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 21 Aug 2026 14:10:33 +0000
Subject: [PATCH 1/5] [libc][time] Implement timer_create.
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/include/time.yaml | 8 ++
.../linux/syscall_wrappers/CMakeLists.txt | 16 ++++
.../linux/syscall_wrappers/timer_create.h | 81 +++++++++++++++++++
libc/src/time/CMakeLists.txt | 7 ++
libc/src/time/linux/CMakeLists.txt | 17 ++++
libc/src/time/linux/timer_create.cpp | 33 ++++++++
libc/src/time/timer_create.h | 29 +++++++
libc/test/src/time/CMakeLists.txt | 19 +++++
libc/test/src/time/timer_create_test.cpp | 78 ++++++++++++++++++
12 files changed, 291 insertions(+)
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
create mode 100644 libc/src/time/linux/timer_create.cpp
create mode 100644 libc/src/time/timer_create.h
create mode 100644 libc/test/src/time/timer_create_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 468b00efad35e..08ecf19bdba86 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1330,6 +1330,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.nanosleep
libc.src.time.time
libc.src.time.timespec_get
+ libc.src.time.timer_create
# unistd.h entrypoints
libc.src.unistd.__llvm_libc_syscall
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index ca6a3d872c71d..50dfdc0985e5d 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1525,6 +1525,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.strftime_l
libc.src.time.time
libc.src.time.timespec_get
+ libc.src.time.timer_create
# locale.h entrypoints
libc.src.locale.localeconv
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9f7da5e10b66c..8f6d7bce8abb7 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1539,6 +1539,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.strftime_l
libc.src.time.time
libc.src.time.timespec_get
+ libc.src.time.timer_create
# locale.h entrypoints
libc.src.locale.localeconv
diff --git a/libc/include/time.yaml b/libc/include/time.yaml
index a7c0cc7cc3e8e..71ea97dabb522 100644
--- a/libc/include/time.yaml
+++ b/libc/include/time.yaml
@@ -154,3 +154,11 @@ functions:
arguments:
- type: struct timespec *
- type: int
+ - name: timer_create
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: clockid_t
+ - type: struct sigevent *__restrict
+ - type: timer_t *__restrict
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 0041db9a24cbd..b41bc16f0438a 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1005,3 +1005,19 @@ add_header_library(
libc.src.__support.macros.config
libc.include.sys_syscall
)
+
+add_header_library(
+ timer_create
+ HDRS
+ timer_create.h
+ DEPENDS
+ libc.hdr.types.clockid_t
+ libc.hdr.types.pid_t
+ libc.hdr.types.struct_sigevent
+ libc.hdr.types.timer_t
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
new file mode 100644
index 0000000000000..9124d8c250bb7
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for timer_create syscall wrapper.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_CREATE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_CREATE_H
+
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_sigevent.h"
+#include "hdr/types/timer_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+#define __SIGEV_MAX_SIZE 64
+#define __SIGEV_PAD_SIZE \
+ ((__SIGEV_MAX_SIZE - sizeof(int) * 2 - sizeof(sigval)) / sizeof(int))
+
+// Linux kernel ABI layout for struct sigevent (64 bytes total):
+// https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/siginfo.h
+// https://man7.org/linux/man-pages/man2/timer_create.2.html
+struct KernelSigevent {
+ sigval sigev_value;
+ int sigev_signo;
+ int sigev_notify;
+ union {
+ int _pad[__SIGEV_PAD_SIZE];
+ pid_t _tid;
+ struct {
+ void (*_function)(sigval);
+ void *_attribute;
+ } _sigev_thread;
+ } _sigev_un;
+
+ LIBC_INLINE KernelSigevent() = default;
+
+ LIBC_INLINE KernelSigevent(const sigevent &sev) {
+ sigev_value = sev.sigev_value;
+ sigev_signo = sev.sigev_signo;
+ sigev_notify = sev.sigev_notify;
+ _sigev_un._tid = sev.sigev_notify_thread_id;
+ _sigev_un._sigev_thread._function = sev.sigev_notify_function;
+ _sigev_un._sigev_thread._attribute = sev.sigev_notify_attributes;
+ }
+};
+
+#undef __SIGEV_MAX_SIZE
+#undef __SIGEV_PAD_SIZE
+
+LIBC_INLINE ErrorOr<int> timer_create(clockid_t clockid, const sigevent *sevp,
+ timer_t *timerid) {
+#ifdef SYS_timer_create
+ if (!sevp)
+ return syscall_checked<int>(SYS_timer_create, clockid, nullptr, timerid);
+
+ KernelSigevent ksev(*sevp);
+ return syscall_checked<int>(SYS_timer_create, clockid, &ksev, timerid);
+#else
+#error "SYS_timer_create syscall not available."
+#endif
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_CREATE_H
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index 8a4c71968712c..9006a35c00bc7 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -299,3 +299,10 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_OS}.clock_settime
)
+
+add_entrypoint_object(
+ timer_create
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.timer_create
+)
diff --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt
index f3cd822498a57..1c0ec1c67c31a 100644
--- a/libc/src/time/linux/CMakeLists.txt
+++ b/libc/src/time/linux/CMakeLists.txt
@@ -72,3 +72,20 @@ add_entrypoint_object(
libc.src.__support.time.clock_settime
libc.src.errno.errno
)
+
+add_entrypoint_object(
+ timer_create
+ SRCS
+ timer_create.cpp
+ HDRS
+ ../timer_create.h
+ DEPENDS
+ libc.hdr.types.clockid_t
+ libc.hdr.types.struct_sigevent
+ libc.hdr.types.timer_t
+ libc.src.__support.OSUtil.linux.syscall_wrappers.timer_create
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.errno.errno
+)
diff --git a/libc/src/time/linux/timer_create.cpp b/libc/src/time/linux/timer_create.cpp
new file mode 100644
index 0000000000000..a5ca734c10da6
--- /dev/null
+++ b/libc/src/time/linux/timer_create.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of timer_create function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/time/timer_create.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/timer_create.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, timer_create,
+ (clockid_t clockid, sigevent *__restrict sevp,
+ timer_t *__restrict timerid)) {
+ auto result = linux_syscalls::timer_create(clockid, sevp, timerid);
+ if (!result) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/timer_create.h b/libc/src/time/timer_create.h
new file mode 100644
index 0000000000000..c8466536b7d4e
--- /dev/null
+++ b/libc/src/time/timer_create.h
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for timer_create function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_TIMER_CREATE_H
+#define LLVM_LIBC_SRC_TIME_TIMER_CREATE_H
+
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/struct_sigevent.h"
+#include "hdr/types/timer_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int timer_create(clockid_t clockid, sigevent *__restrict sevp,
+ timer_t *__restrict timerid);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_TIMER_CREATE_H
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 58f19ebf0d060..adb61d2f6633b 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -143,6 +143,25 @@ add_libc_test(
libc.test.UnitTest.ErrnoCheckingTest
)
+add_libc_test(
+ timer_create_test
+ SUITE
+ libc_time_unittests
+ SRCS
+ timer_create_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.signal_macros
+ libc.hdr.time_macros
+ libc.hdr.types.clockid_t
+ libc.hdr.types.struct_sigevent
+ libc.hdr.types.timer_t
+ libc.src.__support.OSUtil.osutil
+ libc.src.time.timer_create
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_test(
difftime_test
SUITE
diff --git a/libc/test/src/time/timer_create_test.cpp b/libc/test/src/time/timer_create_test.cpp
new file mode 100644
index 0000000000000..339bede11de66
--- /dev/null
+++ b/libc/test/src/time/timer_create_test.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for timer_create.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/signal_macros.h"
+#include "hdr/time_macros.h"
+#include "hdr/types/clockid_t.h"
+#include "hdr/types/struct_sigevent.h"
+#include "hdr/types/timer_t.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/time/timer_create.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::any_of;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcTimerCreateTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcTimerCreateTest, NullSigevent) {
+ timer_t timerid;
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid),
+ Succeeds(0));
+
+#ifdef SYS_timer_delete
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_timer_delete, timerid);
+#endif
+}
+
+TEST_F(LlvmLibcTimerCreateTest, ValidSigeventSigevNone) {
+ struct sigevent se;
+ se.sigev_notify = SIGEV_NONE;
+ timer_t timerid;
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_MONOTONIC, &se, &timerid),
+ Succeeds(0));
+
+#ifdef SYS_timer_delete
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_timer_delete, timerid);
+#endif
+}
+
+TEST_F(LlvmLibcTimerCreateTest, ValidSigeventSigevSignal) {
+ struct sigevent se;
+ se.sigev_notify = SIGEV_SIGNAL;
+ se.sigev_signo = SIGALRM;
+ se.sigev_value.sival_int = 42;
+ timer_t timerid;
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, &se, &timerid),
+ Succeeds(0));
+
+#ifdef SYS_timer_delete
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_timer_delete, timerid);
+#endif
+}
+
+TEST_F(LlvmLibcTimerCreateTest, InvalidClockId) {
+ timer_t timerid;
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(static_cast<clockid_t>(-1), nullptr,
+ &timerid),
+ Fails(EINVAL));
+}
+
+TEST_F(LlvmLibcTimerCreateTest, NullTimerId) {
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, nullptr),
+ Fails(any_of(EINVAL, EFAULT)));
+}
>From af9089dff8fd0a059b45ce9086db907ef6e9cff1 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 21 Aug 2026 17:46:56 +0000
Subject: [PATCH 2/5] Fix timer_create and add timer_delete.
---
libc/config/linux/aarch64/entrypoints.txt | 2 +
libc/config/linux/riscv/entrypoints.txt | 2 +
libc/config/linux/x86_64/entrypoints.txt | 2 +
libc/include/time.yaml | 7 +++
.../linux/syscall_wrappers/CMakeLists.txt | 16 ++++++
.../linux/syscall_wrappers/timer_create.h | 16 ++++--
.../linux/syscall_wrappers/timer_delete.h | 38 +++++++++++++
libc/src/time/CMakeLists.txt | 8 +++
libc/src/time/linux/CMakeLists.txt | 16 ++++++
libc/src/time/linux/timer_delete.cpp | 31 +++++++++++
libc/src/time/timer_delete.h | 26 +++++++++
libc/test/src/time/CMakeLists.txt | 5 +-
.../{timer_create_test.cpp => timer_test.cpp} | 55 +++++++++++++------
13 files changed, 200 insertions(+), 24 deletions(-)
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/timer_delete.h
create mode 100644 libc/src/time/linux/timer_delete.cpp
create mode 100644 libc/src/time/timer_delete.h
rename libc/test/src/time/{timer_create_test.cpp => timer_test.cpp} (55%)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 08ecf19bdba86..eb4ad38db3cd3 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1331,6 +1331,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.time
libc.src.time.timespec_get
libc.src.time.timer_create
+ libc.src.time.timer_delete
+
# unistd.h entrypoints
libc.src.unistd.__llvm_libc_syscall
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 50dfdc0985e5d..12f004989597c 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1526,6 +1526,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.time
libc.src.time.timespec_get
libc.src.time.timer_create
+ libc.src.time.timer_delete
+
# locale.h entrypoints
libc.src.locale.localeconv
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 8f6d7bce8abb7..34733ed9346d4 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1540,6 +1540,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.time
libc.src.time.timespec_get
libc.src.time.timer_create
+ libc.src.time.timer_delete
+
# locale.h entrypoints
libc.src.locale.localeconv
diff --git a/libc/include/time.yaml b/libc/include/time.yaml
index 71ea97dabb522..147bd6f5643a6 100644
--- a/libc/include/time.yaml
+++ b/libc/include/time.yaml
@@ -162,3 +162,10 @@ functions:
- type: clockid_t
- type: struct sigevent *__restrict
- type: timer_t *__restrict
+ - name: timer_delete
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: timer_t
+
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index b41bc16f0438a..d0dd04bfb1d59 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1011,13 +1011,29 @@ add_header_library(
HDRS
timer_create.h
DEPENDS
+ libc.hdr.signal_macros
libc.hdr.types.clockid_t
libc.hdr.types.pid_t
libc.hdr.types.struct_sigevent
libc.hdr.types.timer_t
libc.include.sys_syscall
+ libc.src.__support.CPP.cstddef
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
libc.src.__support.macros.config
)
+
+add_header_library(
+ timer_delete
+ HDRS
+ timer_delete.h
+ DEPENDS
+ libc.hdr.types.timer_t
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+)
+
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
index 9124d8c250bb7..f23a22126e67f 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
@@ -14,10 +14,12 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_CREATE_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_CREATE_H
+#include "hdr/signal_macros.h"
#include "hdr/types/clockid_t.h"
#include "hdr/types/pid_t.h"
#include "hdr/types/struct_sigevent.h"
#include "hdr/types/timer_t.h"
+#include "src/__support/CPP/cstddef.h"
#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
#include "src/__support/common.h"
#include "src/__support/error_or.h"
@@ -49,13 +51,19 @@ struct KernelSigevent {
LIBC_INLINE KernelSigevent() = default;
- LIBC_INLINE KernelSigevent(const sigevent &sev) {
+ LIBC_INLINE KernelSigevent(const sigevent &sev) : _sigev_un{} {
sigev_value = sev.sigev_value;
sigev_signo = sev.sigev_signo;
sigev_notify = sev.sigev_notify;
- _sigev_un._tid = sev.sigev_notify_thread_id;
- _sigev_un._sigev_thread._function = sev.sigev_notify_function;
- _sigev_un._sigev_thread._attribute = sev.sigev_notify_attributes;
+ // Zero initialize `_sigev_un`.
+ for (size_t i = 0; i < __SIGEV_PAD_SIZE; ++i)
+ _sigev_un._pad[i] = 0;
+ if ((sev.sigev_notify & SIGEV_THREAD_ID) != 0) {
+ _sigev_un._tid = sev.sigev_notify_thread_id;
+ } else if (sev.sigev_notify == SIGEV_THREAD) {
+ _sigev_un._sigev_thread._function = sev.sigev_notify_function;
+ _sigev_un._sigev_thread._attribute = sev.sigev_notify_attributes;
+ }
}
};
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_delete.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_delete.h
new file mode 100644
index 0000000000000..bc41a6d6d2ed1
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_delete.h
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for timer_delete syscall wrapper.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_DELETE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_DELETE_H
+
+#include "hdr/types/timer_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> timer_delete(timer_t timerid) {
+#ifdef SYS_timer_delete
+ return syscall_checked<int>(SYS_timer_delete, timerid);
+#else
+#error "SYS_timer_delete syscall not available."
+#endif
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_DELETE_H
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index 9006a35c00bc7..49ca72376090c 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -306,3 +306,11 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_OS}.timer_create
)
+
+add_entrypoint_object(
+ timer_delete
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.timer_delete
+)
+
diff --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt
index 1c0ec1c67c31a..3f91aa3528405 100644
--- a/libc/src/time/linux/CMakeLists.txt
+++ b/libc/src/time/linux/CMakeLists.txt
@@ -89,3 +89,19 @@ add_entrypoint_object(
libc.src.__support.macros.config
libc.src.errno.errno
)
+
+add_entrypoint_object(
+ timer_delete
+ SRCS
+ timer_delete.cpp
+ HDRS
+ ../timer_delete.h
+ DEPENDS
+ libc.hdr.types.timer_t
+ libc.src.__support.OSUtil.linux.syscall_wrappers.timer_delete
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.errno.errno
+)
+
diff --git a/libc/src/time/linux/timer_delete.cpp b/libc/src/time/linux/timer_delete.cpp
new file mode 100644
index 0000000000000..bbf2d621003e1
--- /dev/null
+++ b/libc/src/time/linux/timer_delete.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of timer_delete function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/time/timer_delete.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/timer_delete.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, timer_delete, (timer_t timerid)) {
+ auto result = linux_syscalls::timer_delete(timerid);
+ if (!result) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/timer_delete.h b/libc/src/time/timer_delete.h
new file mode 100644
index 0000000000000..cc326b1a16e2a
--- /dev/null
+++ b/libc/src/time/timer_delete.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for timer_delete function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_TIMER_DELETE_H
+#define LLVM_LIBC_SRC_TIME_TIMER_DELETE_H
+
+#include "hdr/types/timer_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int timer_delete(timer_t timerid);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_TIMER_DELETE_H
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index adb61d2f6633b..a2247ed4cd679 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -144,11 +144,11 @@ add_libc_test(
)
add_libc_test(
- timer_create_test
+ timer_test
SUITE
libc_time_unittests
SRCS
- timer_create_test.cpp
+ timer_test.cpp
DEPENDS
libc.hdr.errno_macros
libc.hdr.signal_macros
@@ -158,6 +158,7 @@ add_libc_test(
libc.hdr.types.timer_t
libc.src.__support.OSUtil.osutil
libc.src.time.timer_create
+ libc.src.time.timer_delete
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
diff --git a/libc/test/src/time/timer_create_test.cpp b/libc/test/src/time/timer_test.cpp
similarity index 55%
rename from libc/test/src/time/timer_create_test.cpp
rename to libc/test/src/time/timer_test.cpp
index 339bede11de66..3d9d02f6c84eb 100644
--- a/libc/test/src/time/timer_create_test.cpp
+++ b/libc/test/src/time/timer_test.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// Unittests for timer_create.
+/// Unittests for posix timers (timer_create, timer_delete).
///
//===----------------------------------------------------------------------===//
@@ -19,6 +19,7 @@
#include "hdr/types/timer_t.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/time/timer_create.h"
+#include "src/time/timer_delete.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
@@ -27,31 +28,25 @@
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::any_of;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
-using LlvmLibcTimerCreateTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LlvmLibcTimerTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-TEST_F(LlvmLibcTimerCreateTest, NullSigevent) {
+TEST_F(LlvmLibcTimerTest, NullSigevent) {
timer_t timerid;
ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid),
Succeeds(0));
-
-#ifdef SYS_timer_delete
- LIBC_NAMESPACE::syscall_impl<int>(SYS_timer_delete, timerid);
-#endif
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0));
}
-TEST_F(LlvmLibcTimerCreateTest, ValidSigeventSigevNone) {
+TEST_F(LlvmLibcTimerTest, ValidSigeventSigevNone) {
struct sigevent se;
se.sigev_notify = SIGEV_NONE;
timer_t timerid;
ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_MONOTONIC, &se, &timerid),
Succeeds(0));
-
-#ifdef SYS_timer_delete
- LIBC_NAMESPACE::syscall_impl<int>(SYS_timer_delete, timerid);
-#endif
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0));
}
-TEST_F(LlvmLibcTimerCreateTest, ValidSigeventSigevSignal) {
+TEST_F(LlvmLibcTimerTest, ValidSigeventSigevSignal) {
struct sigevent se;
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = SIGALRM;
@@ -59,20 +54,44 @@ TEST_F(LlvmLibcTimerCreateTest, ValidSigeventSigevSignal) {
timer_t timerid;
ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, &se, &timerid),
Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0));
+}
-#ifdef SYS_timer_delete
- LIBC_NAMESPACE::syscall_impl<int>(SYS_timer_delete, timerid);
-#endif
+#if defined(SYS_gettid) && defined(SIGEV_THREAD_ID)
+TEST_F(LlvmLibcTimerTest, ValidSigeventSigevThreadId) {
+ struct sigevent se;
+ se.sigev_notify = SIGEV_THREAD_ID;
+ se.sigev_signo = SIGALRM;
+ se.sigev_value.sival_int = 42;
+ se.sigev_notify_thread_id = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_gettid);
+ timer_t timerid;
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, &se, &timerid),
+ Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0));
}
+#endif
-TEST_F(LlvmLibcTimerCreateTest, InvalidClockId) {
+TEST_F(LlvmLibcTimerTest, InvalidClockId) {
timer_t timerid;
ASSERT_THAT(LIBC_NAMESPACE::timer_create(static_cast<clockid_t>(-1), nullptr,
&timerid),
Fails(EINVAL));
}
-TEST_F(LlvmLibcTimerCreateTest, NullTimerId) {
+TEST_F(LlvmLibcTimerTest, NullTimerId) {
ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, nullptr),
Fails(any_of(EINVAL, EFAULT)));
}
+
+TEST_F(LlvmLibcTimerTest, DeleteInvalidTimerId) {
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(reinterpret_cast<timer_t>(-1)),
+ Fails(EINVAL));
+}
+
+TEST_F(LlvmLibcTimerTest, CreateAndDelete) {
+ timer_t timerid;
+ ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid),
+ Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Fails(EINVAL));
+}
>From 616ae8084b2731031af7838cd5fb66dcb3472688 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 21 Aug 2026 17:51:07 +0000
Subject: [PATCH 3/5] Remove unneccessary cstddef and size_t.
---
.../__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt | 1 -
.../__support/OSUtil/linux/syscall_wrappers/timer_create.h | 4 +---
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index d0dd04bfb1d59..50a0dc40bc719 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1017,7 +1017,6 @@ add_header_library(
libc.hdr.types.struct_sigevent
libc.hdr.types.timer_t
libc.include.sys_syscall
- libc.src.__support.CPP.cstddef
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
index f23a22126e67f..89563416db165 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
@@ -19,7 +19,6 @@
#include "hdr/types/pid_t.h"
#include "hdr/types/struct_sigevent.h"
#include "hdr/types/timer_t.h"
-#include "src/__support/CPP/cstddef.h"
#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
#include "src/__support/common.h"
#include "src/__support/error_or.h"
@@ -55,8 +54,7 @@ struct KernelSigevent {
sigev_value = sev.sigev_value;
sigev_signo = sev.sigev_signo;
sigev_notify = sev.sigev_notify;
- // Zero initialize `_sigev_un`.
- for (size_t i = 0; i < __SIGEV_PAD_SIZE; ++i)
+ for (unsigned i = 0; i < __SIGEV_PAD_SIZE; ++i)
_sigev_un._pad[i] = 0;
if ((sev.sigev_notify & SIGEV_THREAD_ID) != 0) {
_sigev_un._tid = sev.sigev_notify_thread_id;
>From 973289eb0db3fc1f430d08191c91d54f2e01fde6 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Sat, 22 Aug 2026 03:42:48 +0000
Subject: [PATCH 4/5] Address comments
---
libc/config/linux/aarch64/entrypoints.txt | 1 -
libc/config/linux/riscv/entrypoints.txt | 1 -
libc/config/linux/x86_64/entrypoints.txt | 1 -
libc/test/src/time/CMakeLists.txt | 2 +-
libc/test/src/time/timer_test.cpp | 7 +++----
5 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index eb4ad38db3cd3..8a58e90bc8688 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1333,7 +1333,6 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.timer_create
libc.src.time.timer_delete
-
# unistd.h entrypoints
libc.src.unistd.__llvm_libc_syscall
libc.src.unistd._exit
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 12f004989597c..0cb1033cf203d 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1528,7 +1528,6 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.timer_create
libc.src.time.timer_delete
-
# locale.h entrypoints
libc.src.locale.localeconv
libc.src.locale.duplocale
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 34733ed9346d4..f708b4271e900 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1542,7 +1542,6 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.timer_create
libc.src.time.timer_delete
-
# locale.h entrypoints
libc.src.locale.localeconv
libc.src.locale.duplocale
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index a2247ed4cd679..cf4c18e8d9d37 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -156,9 +156,9 @@ add_libc_test(
libc.hdr.types.clockid_t
libc.hdr.types.struct_sigevent
libc.hdr.types.timer_t
- libc.src.__support.OSUtil.osutil
libc.src.time.timer_create
libc.src.time.timer_delete
+ libc.src.unistd.gettid
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
diff --git a/libc/test/src/time/timer_test.cpp b/libc/test/src/time/timer_test.cpp
index 3d9d02f6c84eb..e9b20d9615314 100644
--- a/libc/test/src/time/timer_test.cpp
+++ b/libc/test/src/time/timer_test.cpp
@@ -17,13 +17,12 @@
#include "hdr/types/clockid_t.h"
#include "hdr/types/struct_sigevent.h"
#include "hdr/types/timer_t.h"
-#include "src/__support/OSUtil/syscall.h"
#include "src/time/timer_create.h"
#include "src/time/timer_delete.h"
+#include "src/unistd/gettid.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::any_of;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
@@ -57,13 +56,13 @@ TEST_F(LlvmLibcTimerTest, ValidSigeventSigevSignal) {
ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0));
}
-#if defined(SYS_gettid) && defined(SIGEV_THREAD_ID)
+#ifdef SIGEV_THREAD_ID
TEST_F(LlvmLibcTimerTest, ValidSigeventSigevThreadId) {
struct sigevent se;
se.sigev_notify = SIGEV_THREAD_ID;
se.sigev_signo = SIGALRM;
se.sigev_value.sival_int = 42;
- se.sigev_notify_thread_id = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_gettid);
+ se.sigev_notify_thread_id = LIBC_NAMESPACE::gettid();
timer_t timerid;
ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, &se, &timerid),
Succeeds(0));
>From fb8b5c4d6cc7bc103a8c48bb7cdb5e71964f13d9 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Sat, 22 Aug 2026 03:52:09 +0000
Subject: [PATCH 5/5] Update comments.
---
.../__support/OSUtil/linux/syscall_wrappers/timer_create.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
index 89563416db165..25abfffe7ac3b 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/timer_create.h
@@ -56,6 +56,10 @@ struct KernelSigevent {
sigev_notify = sev.sigev_notify;
for (unsigned i = 0; i < __SIGEV_PAD_SIZE; ++i)
_sigev_un._pad[i] = 0;
+ // Linux kernel treats SIGEV_THREAD_ID as a bitwise mask, while the
+ // remaining POSIX values as distinct enums:
+ // https://github.com/torvalds/linux/blob/master/kernel/time/posix-timers.c#L405
+ // https://github.com/torvalds/linux/blob/master/kernel/time/posix-timers.c#L525
if ((sev.sigev_notify & SIGEV_THREAD_ID) != 0) {
_sigev_un._tid = sev.sigev_notify_thread_id;
} else if (sev.sigev_notify == SIGEV_THREAD) {
More information about the libc-commits
mailing list