[libc-commits] [libc] [libc] Assorted improvements to [gs]etitimer (PR #206974)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Mon Jul 6 03:02:48 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/206974
>From 4a6fdc3071117ba4f0d80d7c32b4113e3808c024 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 1 Jul 2026 10:02:42 +0000
Subject: [PATCH 1/3] [libc] Assorted improvements to [gs]etitimer
This started out as a patch adding a syscall wrapper for the two
functions. It still does that, but along the way I (or rather AI)
discovered an edge case in the truncation of microsecond values, where
we could turn bogus values into seemingly valid ones by throwing away
the high-order bits.
Additionally, when writing a test case, I noticed that the (64-bit) kernel
returns EINVAL for these out-or-range values. Our check returns
EOVERFLOW in this case, so I also change our error code in order to
provide an uniform behavior for the test case.
Neither of these (the check and the EINVAL error code) are present in
glibc (which lets truncated usec values through and returns EOVERFLOW on
second truncation), but I think it's better to be consistent with the
64-bit behavior. The EOVERFLOW error also has no foundation in POSIX
whereas EINVAL is mentioned as an error for invalid microseconds.
While in there, I also define ITIMER_REAL, ITIMER_VIRTUAL, and
ITIMER_PROF in linux/sys-time-macros.h and update code to use them
instead of raw numbers.
Assisted by Gemini.
---
libc/hdr/CMakeLists.txt | 9 ++
libc/hdr/sys_time_macros.h | 22 +++++
.../llvm-libc-macros/linux/sys-time-macros.h | 5 ++
libc/include/sys/time.yaml | 6 ++
.../linux/syscall_wrappers/CMakeLists.txt | 43 ++++++++++
.../OSUtil/linux/syscall_wrappers/alarm.h | 49 +++++++++++
.../OSUtil/linux/syscall_wrappers/getitimer.h | 55 +++++++++++++
.../OSUtil/linux/syscall_wrappers/setitimer.h | 82 +++++++++++++++++++
libc/src/sys/time/linux/CMakeLists.txt | 4 +-
libc/src/sys/time/linux/getitimer.cpp | 31 ++-----
libc/src/sys/time/linux/setitimer.cpp | 53 ++----------
libc/src/unistd/linux/CMakeLists.txt | 4 +-
libc/src/unistd/linux/alarm.cpp | 43 ++--------
libc/test/src/sys/time/CMakeLists.txt | 2 +
libc/test/src/sys/time/getitimer_test.cpp | 3 +-
libc/test/src/sys/time/setitimer_test.cpp | 29 ++++++-
16 files changed, 320 insertions(+), 120 deletions(-)
create mode 100644 libc/hdr/sys_time_macros.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index cf3e76d5c005b..4476638c36f52 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -212,6 +212,15 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.sys_ptrace_macros
)
+add_proxy_header_library(
+ sys_time_macros
+ HDRS
+ sys_time_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.sys_time
+ libc.include.llvm-libc-macros.sys_time_macros
+)
+
add_header_library(unistd_overlay HDRS unistd_overlay.h)
add_proxy_header_library(
unistd_macros
diff --git a/libc/hdr/sys_time_macros.h b/libc/hdr/sys_time_macros.h
new file mode 100644
index 0000000000000..e54a659bce29a
--- /dev/null
+++ b/libc/hdr/sys_time_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from sys/time.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_TIME_MACROS_H
+#define LLVM_LIBC_HDR_SYS_TIME_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/sys-time-macros.h"
+
+#else // Overlay mode
+
+#include <sys/time.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_TIME_MACROS_H
diff --git a/libc/include/llvm-libc-macros/linux/sys-time-macros.h b/libc/include/llvm-libc-macros/linux/sys-time-macros.h
index e97819594adcb..677eab50ba098 100644
--- a/libc/include/llvm-libc-macros/linux/sys-time-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-time-macros.h
@@ -9,6 +9,11 @@
#ifndef LLVM_LIBC_MACROS_LINUX_SYS_TIME_MACROS_H
#define LLVM_LIBC_MACROS_LINUX_SYS_TIME_MACROS_H
+// Timer types for setitimer(2).
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
// Add two timevals and put the result in timeval_ptr_result. If the resulting
// usec value is greater than 999,999 then the microseconds are turned into full
// seconds (1,000,000 is subtracted from usec and 1 is added to sec).
diff --git a/libc/include/sys/time.yaml b/libc/include/sys/time.yaml
index f1dcdff354652..5869646a003cd 100644
--- a/libc/include/sys/time.yaml
+++ b/libc/include/sys/time.yaml
@@ -2,6 +2,12 @@ header: sys/time.h
standards:
- posix
macros:
+ - macro_name: ITIMER_REAL
+ macro_header: sys-time-macros.h
+ - macro_name: ITIMER_VIRTUAL
+ macro_header: sys-time-macros.h
+ - macro_name: ITIMER_PROF
+ macro_header: sys-time-macros.h
- macro_name: timeradd
macro_header: sys-time-macros.h
types:
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index f3282c315d9a9..1ce1862df1895 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1,3 +1,18 @@
+add_header_library(
+ alarm
+ HDRS
+ alarm.h
+ DEPENDS
+ libc.hdr.sys_time_macros
+ libc.hdr.types.struct_itimerval
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.linux.syscall_wrappers.setitimer
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+)
+
add_header_library(
getrandom
HDRS
@@ -245,6 +260,34 @@ add_header_library(
libc.include.sys_syscall
)
+add_header_library(
+ getitimer
+ HDRS
+ getitimer.h
+ DEPENDS
+ libc.hdr.types.struct_itimerval
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+)
+
+add_header_library(
+ setitimer
+ HDRS
+ setitimer.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.types.struct_itimerval
+ libc.include.sys_syscall
+ libc.src.__support.CPP.limits
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+)
+
add_header_library(
setsockopt
HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
new file mode 100644
index 0000000000000..68a1ba5e69447
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
@@ -0,0 +1,49 @@
+//===-- Implementation header for alarm -------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for alarm.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ALARM_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ALARM_H
+
+#include "hdr/sys_time_macros.h"
+#include "hdr/types/struct_itimerval.h"
+#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
+#include "src/__support/OSUtil/linux/syscall_wrappers/setitimer.h"
+#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<unsigned int> alarm(unsigned int seconds) {
+#ifdef SYS_alarm
+ return syscall_checked<unsigned int>(SYS_alarm, seconds);
+#elif defined(SYS_setitimer)
+ struct itimerval old_itv;
+ struct itimerval itv = {};
+ itv.it_value.tv_sec = seconds;
+ ErrorOr<int> ret = setitimer(ITIMER_REAL, &itv, &old_itv);
+ if (!ret)
+ return Error(ret.error());
+ return static_cast<unsigned int>(old_itv.it_value.tv_sec +
+ (old_itv.it_value.tv_usec > 0 ? 1 : 0));
+#else
+#error "alarm implementation not available for this architecture"
+#endif
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ALARM_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h
new file mode 100644
index 0000000000000..c9c5384d0b6a9
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h
@@ -0,0 +1,55 @@
+//===-- Implementation header for getitimer ---------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for getitimer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETITIMER_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETITIMER_H
+
+#include "hdr/types/struct_itimerval.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> getitimer(int which, struct itimerval *curr_val) {
+ if constexpr (sizeof(time_t) == sizeof(long)) {
+ return syscall_checked<int>(SYS_getitimer, which, curr_val);
+ } else {
+ // There is no SYS_getitimer_time64 call, so we can't use time_t directly,
+ // and need to convert from long first.
+ long curr_val32[4];
+ long *curr_val32_ptr = curr_val ? curr_val32 : nullptr;
+
+ ErrorOr<int> ret =
+ syscall_checked<int>(SYS_getitimer, which, curr_val32_ptr);
+
+ if (!ret)
+ return ret;
+
+ if (curr_val) {
+ curr_val->it_interval.tv_sec = curr_val32[0];
+ curr_val->it_interval.tv_usec = curr_val32[1];
+ curr_val->it_value.tv_sec = curr_val32[2];
+ curr_val->it_value.tv_usec = curr_val32[3];
+ }
+ return ret;
+ }
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETITIMER_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h
new file mode 100644
index 0000000000000..48f1887bc29ab
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h
@@ -0,0 +1,82 @@
+//===-- Implementation header for setitimer ---------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for setitimer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETITIMER_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETITIMER_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/struct_itimerval.h"
+#include "src/__support/CPP/limits.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> setitimer(int which, const struct itimerval *new_val,
+ struct itimerval *old_val) {
+ if constexpr (sizeof(time_t) == sizeof(long)) {
+ return syscall_checked<int>(SYS_setitimer, which, new_val, old_val);
+ } else {
+ // There is no SYS_setitimer_time64 call, so we can't use time_t directly,
+ // and need to convert it to long first.
+ long old_val32[4];
+ long *old_val32_ptr = old_val ? old_val32 : nullptr;
+ long new_val32[4];
+ long *new_val32_ptr = nullptr;
+
+ if (new_val) {
+ // Check for overflow before casting to 32-bit long. We'll let the kernel
+ // do the final validation. We're just making sure the truncation does not
+ // change the value.
+ auto fits_long = [](auto val) {
+ return val <= cpp::numeric_limits<long>::max() &&
+ val >= cpp::numeric_limits<long>::min();
+ };
+ if (!fits_long(new_val->it_interval.tv_sec) ||
+ !fits_long(new_val->it_value.tv_sec) ||
+ !fits_long(new_val->it_interval.tv_usec) ||
+ !fits_long(new_val->it_value.tv_usec)) {
+ return Error(EINVAL);
+ }
+
+ new_val32[0] = static_cast<long>(new_val->it_interval.tv_sec);
+ new_val32[1] = static_cast<long>(new_val->it_interval.tv_usec);
+ new_val32[2] = static_cast<long>(new_val->it_value.tv_sec);
+ new_val32[3] = static_cast<long>(new_val->it_value.tv_usec);
+ new_val32_ptr = new_val32;
+ }
+
+ ErrorOr<int> ret = syscall_checked<int>(SYS_setitimer, which, new_val32_ptr,
+ old_val32_ptr);
+
+ if (!ret)
+ return ret;
+
+ if (old_val) {
+ old_val->it_interval.tv_sec = old_val32[0];
+ old_val->it_interval.tv_usec = old_val32[1];
+ old_val->it_value.tv_sec = old_val32[2];
+ old_val->it_value.tv_usec = old_val32[3];
+ }
+ return ret;
+ }
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETITIMER_H
diff --git a/libc/src/sys/time/linux/CMakeLists.txt b/libc/src/sys/time/linux/CMakeLists.txt
index 60fbd14f73174..36452dfdea5b6 100644
--- a/libc/src/sys/time/linux/CMakeLists.txt
+++ b/libc/src/sys/time/linux/CMakeLists.txt
@@ -24,7 +24,7 @@ add_entrypoint_object(
../setitimer.h
DEPENDS
libc.hdr.types.struct_itimerval
- libc.include.sys_syscall
+ libc.src.__support.OSUtil.linux.syscall_wrappers.setitimer
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.errno.errno
@@ -38,7 +38,7 @@ add_entrypoint_object(
../getitimer.h
DEPENDS
libc.hdr.types.struct_itimerval
- libc.include.sys_syscall
+ libc.src.__support.OSUtil.linux.syscall_wrappers.getitimer
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.errno.errno
diff --git a/libc/src/sys/time/linux/getitimer.cpp b/libc/src/sys/time/linux/getitimer.cpp
index 2a40491bc95fb..f875bc9b13b7e 100644
--- a/libc/src/sys/time/linux/getitimer.cpp
+++ b/libc/src/sys/time/linux/getitimer.cpp
@@ -7,38 +7,17 @@
//===----------------------------------------------------------------------===//
#include "src/sys/time/getitimer.h"
-#include "hdr/types/struct_itimerval.h"
-#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getitimer.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
-#include <sys/syscall.h>
+#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, getitimer, (int which, struct itimerval *curr_value)) {
- long ret = 0;
- if constexpr (sizeof(time_t) > sizeof(long)) {
- // There is no SYS_getitimer_time64 call, so we can't use time_t directly.
- if (curr_value) {
- long curr_value32[4];
- ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_getitimer, which,
- curr_value32);
- if (!ret) {
- curr_value->it_interval.tv_sec = curr_value32[0];
- curr_value->it_interval.tv_usec = curr_value32[1];
- curr_value->it_value.tv_sec = curr_value32[2];
- curr_value->it_value.tv_usec = curr_value32[3];
- }
- } else {
- ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_getitimer, which, nullptr);
- }
- } else {
- ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_getitimer, which, curr_value);
- }
-
- // On failure, return -1 and set errno.
- if (ret < 0) {
- libc_errno = static_cast<int>(-ret);
+ ErrorOr<int> ret = linux_syscalls::getitimer(which, curr_value);
+ if (!ret) {
+ libc_errno = ret.error();
return -1;
}
return 0;
diff --git a/libc/src/sys/time/linux/setitimer.cpp b/libc/src/sys/time/linux/setitimer.cpp
index 2c2f0d7198204..07cb9180a7f7e 100644
--- a/libc/src/sys/time/linux/setitimer.cpp
+++ b/libc/src/sys/time/linux/setitimer.cpp
@@ -6,62 +6,19 @@
//
//===----------------------------------------------------------------------===//
#include "src/sys/time/setitimer.h"
-#include "hdr/errno_macros.h"
-#include "hdr/types/struct_itimerval.h"
-#include "src/__support/CPP/limits.h"
-#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/setitimer.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
-#include <sys/syscall.h>
+#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, setitimer,
(int which, const struct itimerval *new_value,
struct itimerval *old_value)) {
- long ret = 0;
- if constexpr (sizeof(time_t) > sizeof(long)) {
- // There is no SYS_setitimer_time64 call, so we can't use time_t directly,
- // and need to convert it to long first.
- long old_value32[4];
- long *old_value32_ptr = old_value ? old_value32 : nullptr;
-
- if (new_value) {
- // Check for overflow before casting to 32-bit long.
- if (new_value->it_interval.tv_sec > cpp::numeric_limits<long>::max() ||
- new_value->it_interval.tv_sec < cpp::numeric_limits<long>::min() ||
- new_value->it_value.tv_sec > cpp::numeric_limits<long>::max() ||
- new_value->it_value.tv_sec < cpp::numeric_limits<long>::min()) {
- libc_errno = EOVERFLOW;
- return -1;
- }
-
- long new_value32[4] = {static_cast<long>(new_value->it_interval.tv_sec),
- static_cast<long>(new_value->it_interval.tv_usec),
- static_cast<long>(new_value->it_value.tv_sec),
- static_cast<long>(new_value->it_value.tv_usec)};
-
- ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_setitimer, which,
- new_value32, old_value32_ptr);
- } else {
- ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_setitimer, which, nullptr,
- old_value32_ptr);
- }
-
- if (!ret && old_value) {
- old_value->it_interval.tv_sec = old_value32[0];
- old_value->it_interval.tv_usec = old_value32[1];
- old_value->it_value.tv_sec = old_value32[2];
- old_value->it_value.tv_usec = old_value32[3];
- }
- } else {
- ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_setitimer, which, new_value,
- old_value);
- }
-
- // On failure, return -1 and set errno.
- if (ret < 0) {
- libc_errno = static_cast<int>(-ret);
+ ErrorOr<int> ret = linux_syscalls::setitimer(which, new_value, old_value);
+ if (!ret) {
+ libc_errno = ret.error();
return -1;
}
return 0;
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index af385e9bbed72..168b61bede853 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -5,9 +5,7 @@ add_entrypoint_object(
HDRS
../alarm.h
DEPENDS
- libc.hdr.types.struct_itimerval
- libc.include.sys_syscall
- libc.src.__support.OSUtil.osutil
+ libc.src.__support.OSUtil.linux.syscall_wrappers.alarm
libc.src.__support.common
libc.src.__support.macros.config
)
diff --git a/libc/src/unistd/linux/alarm.cpp b/libc/src/unistd/linux/alarm.cpp
index f849e487a3f96..bc2febff0248f 100644
--- a/libc/src/unistd/linux/alarm.cpp
+++ b/libc/src/unistd/linux/alarm.cpp
@@ -12,50 +12,17 @@
//===----------------------------------------------------------------------===//
#include "src/unistd/alarm.h"
-
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/alarm.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
-#include <sys/syscall.h> // For syscall numbers.
-
-#ifndef SYS_alarm
-#include "hdr/types/struct_itimerval.h"
-#endif
-
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned int, alarm, (unsigned int seconds)) {
-#ifdef SYS_alarm
- return static_cast<unsigned int>(
- LIBC_NAMESPACE::syscall_impl<long>(SYS_alarm, seconds));
-#elif defined(SYS_setitimer)
- // On 32-bit architectures with 64-bit time_t, SYS_setitimer still expects
- // 32-bit fields. We must convert itimerval to use 32-bit fields.
- if constexpr (sizeof(time_t) > sizeof(long)) {
- long itv32[4] = {0, 0, static_cast<long>(seconds), 0};
- long old_itv32[4];
- long ret = LIBC_NAMESPACE::syscall_impl<long>(
- SYS_setitimer, 0 /* ITIMER_REAL */, itv32, old_itv32);
- if (ret < 0)
- return 0;
- return static_cast<unsigned int>(old_itv32[2] + (old_itv32[3] > 0 ? 1 : 0));
- } else {
- struct itimerval itv, old_itv;
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 0;
- itv.it_value.tv_sec = seconds;
- itv.it_value.tv_usec = 0;
- long ret = LIBC_NAMESPACE::syscall_impl<long>(
- SYS_setitimer, 0 /* ITIMER_REAL */, &itv, &old_itv);
- if (ret < 0)
- return 0;
- return static_cast<unsigned int>(old_itv.it_value.tv_sec +
- (old_itv.it_value.tv_usec > 0 ? 1 : 0));
- }
-#else
-#error "alarm implementation not available for this architecture"
-#endif
+ ErrorOr<unsigned int> ret = linux_syscalls::alarm(seconds);
+ if (!ret)
+ return 0;
+ return ret.value();
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/sys/time/CMakeLists.txt b/libc/test/src/sys/time/CMakeLists.txt
index 2468b4ae2cc34..eb9753bb5bf2d 100644
--- a/libc/test/src/sys/time/CMakeLists.txt
+++ b/libc/test/src/sys/time/CMakeLists.txt
@@ -27,6 +27,7 @@ add_libc_unittest(
SRCS
setitimer_test.cpp
DEPENDS
+ libc.hdr.sys_time_macros
libc.include.signal
libc.src.sys.time.setitimer
libc.src.signal.sigaction
@@ -44,6 +45,7 @@ add_libc_unittest(
SRCS
getitimer_test.cpp
DEPENDS
+ libc.hdr.sys_time_macros
libc.src.sys.time.getitimer
libc.src.__support.common
libc.src.errno.errno
diff --git a/libc/test/src/sys/time/getitimer_test.cpp b/libc/test/src/sys/time/getitimer_test.cpp
index c1d6f72701627..93d885760a5af 100644
--- a/libc/test/src/sys/time/getitimer_test.cpp
+++ b/libc/test/src/sys/time/getitimer_test.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "hdr/sys_time_macros.h"
#include "hdr/types/struct_itimerval.h"
#include "src/sys/time/getitimer.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
@@ -23,7 +24,7 @@ TEST_F(LlvmLibcSysTimeGetitimerTest, SmokeTest) {
timer.it_interval.tv_sec = -1;
timer.it_interval.tv_usec = -1;
- ASSERT_THAT(LIBC_NAMESPACE::getitimer(0, &timer),
+ ASSERT_THAT(LIBC_NAMESPACE::getitimer(ITIMER_REAL, &timer),
returns(EQ(0)).with_errno(EQ(0)));
ASSERT_TRUE(timer.it_value.tv_sec == 0);
diff --git a/libc/test/src/sys/time/setitimer_test.cpp b/libc/test/src/sys/time/setitimer_test.cpp
index 115f9e662ed46..aa4feb6aace4d 100644
--- a/libc/test/src/sys/time/setitimer_test.cpp
+++ b/libc/test/src/sys/time/setitimer_test.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "hdr/sys_time_macros.h"
#include "hdr/types/struct_itimerval.h"
#include "hdr/types/struct_sigaction.h"
#include "src/signal/sigaction.h"
@@ -37,7 +38,7 @@ TEST_F(LlvmLibcSysTimeSetitimerTest, SmokeTest) {
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0; // One-shot timer
- ASSERT_THAT(LIBC_NAMESPACE::setitimer(0, &timer, nullptr),
+ ASSERT_THAT(LIBC_NAMESPACE::setitimer(ITIMER_REAL, &timer, nullptr),
returns(EQ(0)).with_errno(EQ(0)));
while (true) {
@@ -49,9 +50,33 @@ TEST_F(LlvmLibcSysTimeSetitimerTest, SmokeTest) {
}
TEST_F(LlvmLibcSysTimeSetitimerTest, InvalidRetTest) {
- struct itimerval timer;
+ struct itimerval timer = {};
// out of range timer type (which)
ASSERT_THAT(LIBC_NAMESPACE::setitimer(99, &timer, nullptr),
returns(NE(0)).with_errno(NE(0)));
+
+ // invalid microseconds (>= 1000000)
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = 1000000;
+ ASSERT_THAT(LIBC_NAMESPACE::setitimer(ITIMER_REAL, &timer, nullptr),
+ returns(EQ(-1)).with_errno(EQ(EINVAL)));
+
+ // negative microseconds
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = -1;
+ ASSERT_THAT(LIBC_NAMESPACE::setitimer(ITIMER_REAL, &timer, nullptr),
+ returns(EQ(-1)).with_errno(EQ(EINVAL)));
+
+ // Test 64-bit microsecond values that would truncate to a valid 32-bit value
+ // (< 1000000). 0x100000047, If truncated to 32-bit integer, becomes 0x47.
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = 0x1'0000'0047;
+ ASSERT_THAT(LIBC_NAMESPACE::setitimer(ITIMER_REAL, &timer, nullptr),
+ returns(EQ(-1)).with_errno(EQ(EINVAL)));
+
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = 0xffff'ffff'0000'0047;
+ ASSERT_THAT(LIBC_NAMESPACE::setitimer(ITIMER_REAL, &timer, nullptr),
+ returns(EQ(-1)).with_errno(EQ(EINVAL)));
}
>From f0ea4e737c14af4736b963756c01163b3fc8442c Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 1 Jul 2026 13:46:38 +0000
Subject: [PATCH 2/3] fix overlay build
---
libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
index 68a1ba5e69447..3a529ce7a23b7 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
@@ -33,7 +33,7 @@ LIBC_INLINE ErrorOr<unsigned int> alarm(unsigned int seconds) {
struct itimerval old_itv;
struct itimerval itv = {};
itv.it_value.tv_sec = seconds;
- ErrorOr<int> ret = setitimer(ITIMER_REAL, &itv, &old_itv);
+ ErrorOr<int> ret = linux_syscalls::setitimer(ITIMER_REAL, &itv, &old_itv);
if (!ret)
return Error(ret.error());
return static_cast<unsigned int>(old_itv.it_value.tv_sec +
>From d62c2f313071fc5da551e678009a5688bb0acbe1 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 6 Jul 2026 10:01:54 +0000
Subject: [PATCH 3/3] fix file headers
---
libc/hdr/sys_time_macros.h | 7 ++++++-
libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h | 2 +-
.../__support/OSUtil/linux/syscall_wrappers/getitimer.h | 2 +-
.../__support/OSUtil/linux/syscall_wrappers/setitimer.h | 2 +-
libc/src/sys/time/linux/CMakeLists.txt | 2 ++
5 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/libc/hdr/sys_time_macros.h b/libc/hdr/sys_time_macros.h
index e54a659bce29a..94fb829783b64 100644
--- a/libc/hdr/sys_time_macros.h
+++ b/libc/hdr/sys_time_macros.h
@@ -1,10 +1,15 @@
-//===-- Definition of macros from sys/time.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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Proxy header for sys/time.h macros.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_SYS_TIME_MACROS_H
#define LLVM_LIBC_HDR_SYS_TIME_MACROS_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
index 3a529ce7a23b7..754b1d273acba 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/alarm.h
@@ -1,4 +1,4 @@
-//===-- Implementation header for alarm -------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h
index c9c5384d0b6a9..86211700ac688 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getitimer.h
@@ -1,4 +1,4 @@
-//===-- Implementation header for getitimer ---------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h
index 48f1887bc29ab..82cb1d84b8d81 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/setitimer.h
@@ -1,4 +1,4 @@
-//===-- Implementation header for setitimer ---------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/sys/time/linux/CMakeLists.txt b/libc/src/sys/time/linux/CMakeLists.txt
index 36452dfdea5b6..e74269d721c56 100644
--- a/libc/src/sys/time/linux/CMakeLists.txt
+++ b/libc/src/sys/time/linux/CMakeLists.txt
@@ -27,6 +27,7 @@ add_entrypoint_object(
libc.src.__support.OSUtil.linux.syscall_wrappers.setitimer
libc.src.__support.OSUtil.osutil
libc.src.__support.common
+ libc.src.__support.macros.config
libc.src.errno.errno
)
@@ -41,5 +42,6 @@ add_entrypoint_object(
libc.src.__support.OSUtil.linux.syscall_wrappers.getitimer
libc.src.__support.OSUtil.osutil
libc.src.__support.common
+ libc.src.__support.macros.config
libc.src.errno.errno
)
More information about the libc-commits
mailing list