From 2c0ef107eea86381f17015fcd57c0b17d3c3cd22 Mon Sep 17 00:00:00 2001 From: Anton Shepelev Date: Thu, 2 Oct 2025 13:21:18 -0700 Subject: [PATCH 1/5] - Implemented a clock_settime syscall wrapper for Linux - Implemented unit-tests for the feature --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/riscv/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/docs/headers/time.rst | 2 +- libc/include/time.yaml | 7 +++ libc/src/__support/time/CMakeLists.txt | 7 +++ libc/src/__support/time/clock_settime.h | 22 ++++++++ libc/src/__support/time/linux/CMakeLists.txt | 15 ++++++ .../__support/time/linux/clock_settime.cpp | 53 +++++++++++++++++++ libc/src/time/CMakeLists.txt | 8 +++ libc/src/time/clock_settime.h | 22 ++++++++ libc/src/time/linux/CMakeLists.txt | 13 +++++ libc/src/time/linux/clock_settime.cpp | 30 +++++++++++ libc/test/src/time/CMakeLists.txt | 15 ++++++ libc/test/src/time/clock_settime_test.cpp | 31 +++++++++++ 15 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 libc/src/__support/time/clock_settime.h create mode 100644 libc/src/__support/time/linux/clock_settime.cpp create mode 100644 libc/src/time/clock_settime.h create mode 100644 libc/src/time/linux/clock_settime.cpp create mode 100644 libc/test/src/time/clock_settime_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 00c4b2ec0f828..605b76718fd64 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -1142,6 +1142,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.ctime_r libc.src.time.clock libc.src.time.clock_gettime + libc.src.time.clock_settime libc.src.time.difftime libc.src.time.gettimeofday libc.src.time.gmtime diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 89e3653186d13..97cd7fdef7a07 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -1267,6 +1267,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.ctime_r libc.src.time.clock libc.src.time.clock_gettime + libc.src.time.clock_settime libc.src.time.difftime libc.src.time.gettimeofday libc.src.time.gmtime diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 0bb8a683c5b01..59357822ec537 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -1305,6 +1305,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.ctime_r libc.src.time.clock libc.src.time.clock_gettime + libc.src.time.clock_settime libc.src.time.difftime libc.src.time.gettimeofday libc.src.time.gmtime diff --git a/libc/docs/headers/time.rst b/libc/docs/headers/time.rst index 55bc1a17ee285..00b0dd472de5c 100644 --- a/libc/docs/headers/time.rst +++ b/libc/docs/headers/time.rst @@ -71,7 +71,7 @@ Implementation Status +---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ | clock_nanosleep | | | | | | | | | | | | | | +---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ -| clock_settime | | | | | | | | | | | | | | +| clock_settime | |check| | |check| | | |check| | | | | | | | | | | +---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ | ctime | |check| | |check| | | |check| | | | | | | | | | | +---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ diff --git a/libc/include/time.yaml b/libc/include/time.yaml index 2f8024298fad1..7b86838a7dca2 100644 --- a/libc/include/time.yaml +++ b/libc/include/time.yaml @@ -67,6 +67,13 @@ functions: arguments: - type: clockid_t - type: struct timespec * + - name: clock_settime + standard: + - POSIX + return_type: int + arguments: + - type: clockid_t + - type: const struct timespec * - name: difftime standard: - stdc diff --git a/libc/src/__support/time/CMakeLists.txt b/libc/src/__support/time/CMakeLists.txt index 8247e792e8410..8dbcb914fcc5b 100644 --- a/libc/src/__support/time/CMakeLists.txt +++ b/libc/src/__support/time/CMakeLists.txt @@ -19,3 +19,10 @@ add_object_library( DEPENDS libc.src.__support.time.${LIBC_TARGET_OS}.clock_gettime ) + +add_object_library( + clock_settime + ALIAS + DEPENDS + libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime +) diff --git a/libc/src/__support/time/clock_settime.h b/libc/src/__support/time/clock_settime.h new file mode 100644 index 0000000000000..d8d305cadf4b9 --- /dev/null +++ b/libc/src/__support/time/clock_settime.h @@ -0,0 +1,22 @@ +//===--- clock_settime linux implementation ---------------------*- 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___SUPPORT_TIME_CLOCK_SETTIME_H +#define LLVM_LIBC_SRC___SUPPORT_TIME_CLOCK_SETTIME_H + +#include "hdr/types/clockid_t.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/error_or.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { +ErrorOr clock_settime(clockid_t clockid, const timespec *ts); +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_TIME_CLOCK_SETTIME_H diff --git a/libc/src/__support/time/linux/CMakeLists.txt b/libc/src/__support/time/linux/CMakeLists.txt index 6fec7eeba99ad..478529502b403 100644 --- a/libc/src/__support/time/linux/CMakeLists.txt +++ b/libc/src/__support/time/linux/CMakeLists.txt @@ -14,6 +14,21 @@ add_object_library( libc.src.__support.OSUtil.linux.vdso ) +add_object_library( + clock_settime + HDRS + ../clock_settime.h + SRCS + clock_settime.cpp + DEPENDS + libc.include.sys_syscall + libc.hdr.types.struct_timespec + libc.hdr.types.clockid_t + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.OSUtil.osutil +) + add_header_library( clock_conversion HDRS diff --git a/libc/src/__support/time/linux/clock_settime.cpp b/libc/src/__support/time/linux/clock_settime.cpp new file mode 100644 index 0000000000000..d81889ebc469d --- /dev/null +++ b/libc/src/__support/time/linux/clock_settime.cpp @@ -0,0 +1,53 @@ +//===--- clock_settime linux implementation ---------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/__support/time/clock_settime.h" +#include "hdr/types/clockid_t.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include + +#if defined(SYS_clock_settime64) +#include +#endif + +namespace LIBC_NAMESPACE_DECL { +namespace internal { +ErrorOr clock_settime(clockid_t clockid, const timespec *ts) { + int ret; +#if defined(SYS_clock_settime) + ret = LIBC_NAMESPACE::syscall_impl(SYS_clock_settime, + static_cast(clockid), + reinterpret_cast(ts)); +#elif defined(SYS_clock_settime64) + static_assert( + sizeof(time_t) == sizeof(int64_t), + "SYS_clock_settime64 requires struct timespec with 64-bit members."); + + __kernel_timespec ts64{}; + + ret = LIBC_NAMESPACE::syscall_impl(SYS_clock_settime64, + static_cast(clockid), + reinterpret_cast(&ts64)); + if (ret == 0) { + ts->tv_sec = static_casttv_sec)>(ts64.tv_sec); + ts->tv_nsec = static_casttv_nsec)>(ts64.tv_nsec); + } +#else +#error "SYS_clock_settime and SYS_clock_settime64 syscalls not available." +#endif + if (ret < 0) + return Error(-ret); + return ret; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt index ec942e38d1af5..4d647c22c3239 100644 --- a/libc/src/time/CMakeLists.txt +++ b/libc/src/time/CMakeLists.txt @@ -245,3 +245,11 @@ add_entrypoint_object( DEPENDS .${LIBC_TARGET_OS}.clock_getres ) + +add_entrypoint_object( + clock_settime + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.clock_settime +) + diff --git a/libc/src/time/clock_settime.h b/libc/src/time/clock_settime.h new file mode 100644 index 0000000000000..9321dd1074101 --- /dev/null +++ b/libc/src/time/clock_settime.h @@ -0,0 +1,22 @@ +//===-- Implementation header for clock_settime function --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_TIME_CLOCK_SETTIME_H +#define LLVM_LIBC_SRC_TIME_CLOCK_SETTIME_H + +#include "hdr/types/clockid_t.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int clock_settime(clockid_t clockid, const timespec *tp); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_TIME_CLOCK_SETTIME_H diff --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt index a6ec7c7c06963..6ea04597063cb 100644 --- a/libc/src/time/linux/CMakeLists.txt +++ b/libc/src/time/linux/CMakeLists.txt @@ -54,6 +54,19 @@ add_entrypoint_object( libc.src.errno.errno ) +add_entrypoint_object( + clock_settime + SRCS + clock_settime.cpp + HDRS + ../clock_settime.h + DEPENDS + libc.hdr.types.clockid_t + libc.hdr.types.struct_timespec + libc.src.__support.time.clock_settime + libc.src.errno.errno +) + add_entrypoint_object( gettimeofday SRCS diff --git a/libc/src/time/linux/clock_settime.cpp b/libc/src/time/linux/clock_settime.cpp new file mode 100644 index 0000000000000..1f39ca6efa02d --- /dev/null +++ b/libc/src/time/linux/clock_settime.cpp @@ -0,0 +1,30 @@ +//===---------- Linux implementation of the POSIX clock_settime function --===// +// +// 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/time/clock_settime.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/time/clock_settime.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, clock_settime, + (clockid_t clockid, const struct timespec *ts)) { + auto result = internal::clock_settime(clockid, ts); + + // A negative return value indicates an error with the magnitude of the + // value being the error code. + if (!result.has_value()) { + libc_errno = result.error(); + return -1; + } + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt index 03e5428292418..c8e113f06d50b 100644 --- a/libc/test/src/time/CMakeLists.txt +++ b/libc/test/src/time/CMakeLists.txt @@ -124,6 +124,21 @@ add_libc_test( libc.src.time.clock_getres ) +add_libc_test( + clock_settime_test + SUITE + libc_time_unittests + SRCS + clock_settime_test.cpp + DEPENDS + libc.src.time.clock_settime + libc.hdr.types.time_t + libc.hdr.types.struct_timespec + libc.hdr.time_macros + libc.hdr.errno_macros + libc.test.UnitTest.ErrnoCheckingTest +) + add_libc_unittest( difftime_test SUITE diff --git a/libc/test/src/time/clock_settime_test.cpp b/libc/test/src/time/clock_settime_test.cpp new file mode 100644 index 0000000000000..881db1f75120d --- /dev/null +++ b/libc/test/src/time/clock_settime_test.cpp @@ -0,0 +1,31 @@ +//===-- Unittests for clock_settime ---------------------------------------===// +// +// 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/time_macros.h" +#include "hdr/types/struct_timespec.h" +#include "src/time/clock_settime.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcClockSetTime = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +#ifdef CLOCK_MONOTONIC +TEST_F(LlvmLibcClockSetTime, MonotonicIsNotSettable) { + timespec ts = {0, 0}; + int result = LIBC_NAMESPACE::clock_settime(CLOCK_MONOTONIC, &ts); + ASSERT_EQ(result, -1); + ASSERT_ERRNO_EQ(EINVAL); +} +#endif // CLOCK_MONOTONIC + +TEST_F(LlvmLibcClockSetTime, InvalidClockId) { + timespec ts = {0, 0}; + int result = LIBC_NAMESPACE::clock_settime(static_cast(-1), &ts); + ASSERT_EQ(result, -1); + ASSERT_ERRNO_EQ(EINVAL); +} From 06ac55c61287325c50011720b1be285cd7bee310 Mon Sep 17 00:00:00 2001 From: Anton Shepelev Date: Thu, 2 Oct 2025 13:49:43 -0700 Subject: [PATCH 2/5] - Fixed CMake to include the implementation only on Linux for now --- libc/src/__support/time/CMakeLists.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libc/src/__support/time/CMakeLists.txt b/libc/src/__support/time/CMakeLists.txt index 8dbcb914fcc5b..04744da3fc981 100644 --- a/libc/src/__support/time/CMakeLists.txt +++ b/libc/src/__support/time/CMakeLists.txt @@ -20,9 +20,11 @@ add_object_library( libc.src.__support.time.${LIBC_TARGET_OS}.clock_gettime ) -add_object_library( - clock_settime - ALIAS - DEPENDS - libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime -) +if(LIBC_TARGET_OS_IS_LINUX) + add_object_library( + clock_settime + ALIAS + DEPENDS + libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime + ) +endif() From 7105bef4ec67c3f3a433005370591ca9bf79d31d Mon Sep 17 00:00:00 2001 From: Anton Shepelev Date: Fri, 3 Oct 2025 09:04:17 -0700 Subject: [PATCH 3/5] - Changed CMake for clock_settime() to be more flexible for future targets --- libc/src/__support/time/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/__support/time/CMakeLists.txt b/libc/src/__support/time/CMakeLists.txt index 04744da3fc981..3851037e4161f 100644 --- a/libc/src/__support/time/CMakeLists.txt +++ b/libc/src/__support/time/CMakeLists.txt @@ -20,7 +20,7 @@ add_object_library( libc.src.__support.time.${LIBC_TARGET_OS}.clock_gettime ) -if(LIBC_TARGET_OS_IS_LINUX) +if(TARGET libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime) add_object_library( clock_settime ALIAS From 366ad9ac759cb84764595f790c5f83f8323c6343 Mon Sep 17 00:00:00 2001 From: Anton Shepelev Date: Fri, 3 Oct 2025 09:28:17 -0700 Subject: [PATCH 4/5] - Removed redundant 'struct' keyword --- libc/src/time/linux/clock.cpp | 2 +- libc/src/time/linux/clock_gettime.cpp | 2 +- libc/src/time/linux/clock_settime.cpp | 2 +- libc/src/time/linux/nanosleep.cpp | 2 +- libc/src/time/linux/timespec_get.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libc/src/time/linux/clock.cpp b/libc/src/time/linux/clock.cpp index c38697cd0668e..c560bd10be83c 100644 --- a/libc/src/time/linux/clock.cpp +++ b/libc/src/time/linux/clock.cpp @@ -19,7 +19,7 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(clock_t, clock, ()) { using namespace time_units; - struct timespec ts; + timespec ts; auto result = internal::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); if (!result.has_value()) { libc_errno = result.error(); diff --git a/libc/src/time/linux/clock_gettime.cpp b/libc/src/time/linux/clock_gettime.cpp index b3fcd2b22f9da..a77d92e05474c 100644 --- a/libc/src/time/linux/clock_gettime.cpp +++ b/libc/src/time/linux/clock_gettime.cpp @@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL { // TODO(michaelrj): Move this into time/linux with the other syscalls. LLVM_LIBC_FUNCTION(int, clock_gettime, - (clockid_t clockid, struct timespec *ts)) { + (clockid_t clockid, timespec *ts)) { auto result = internal::clock_gettime(clockid, ts); // A negative return value indicates an error with the magnitude of the diff --git a/libc/src/time/linux/clock_settime.cpp b/libc/src/time/linux/clock_settime.cpp index 1f39ca6efa02d..3c582cf0b4646 100644 --- a/libc/src/time/linux/clock_settime.cpp +++ b/libc/src/time/linux/clock_settime.cpp @@ -15,7 +15,7 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, clock_settime, - (clockid_t clockid, const struct timespec *ts)) { + (clockid_t clockid, const timespec *ts)) { auto result = internal::clock_settime(clockid, ts); // A negative return value indicates an error with the magnitude of the diff --git a/libc/src/time/linux/nanosleep.cpp b/libc/src/time/linux/nanosleep.cpp index e5df1585df988..7b0a4a3efd719 100644 --- a/libc/src/time/linux/nanosleep.cpp +++ b/libc/src/time/linux/nanosleep.cpp @@ -19,7 +19,7 @@ namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, nanosleep, - (const struct timespec *req, struct timespec *rem)) { + (const timespec *req, timespec *rem)) { #if SYS_nanosleep int ret = LIBC_NAMESPACE::syscall_impl(SYS_nanosleep, req, rem); #elif defined(SYS_clock_nanosleep_time64) diff --git a/libc/src/time/linux/timespec_get.cpp b/libc/src/time/linux/timespec_get.cpp index a4d4372332732..e90f492b65e8f 100644 --- a/libc/src/time/linux/timespec_get.cpp +++ b/libc/src/time/linux/timespec_get.cpp @@ -15,7 +15,7 @@ namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) { +LLVM_LIBC_FUNCTION(int, timespec_get, (timespec *ts, int base)) { clockid_t clockid; switch (base) { case TIME_UTC: From bd265d2e7eece441530867b6e3a07066e96af7a4 Mon Sep 17 00:00:00 2001 From: Anton Shepelev Date: Fri, 3 Oct 2025 09:35:07 -0700 Subject: [PATCH 5/5] clang-format --- libc/src/time/linux/clock_gettime.cpp | 3 +-- libc/src/time/linux/nanosleep.cpp | 3 +-- libc/src/time/linux/timespec_get.cpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libc/src/time/linux/clock_gettime.cpp b/libc/src/time/linux/clock_gettime.cpp index a77d92e05474c..52ace2a743dd4 100644 --- a/libc/src/time/linux/clock_gettime.cpp +++ b/libc/src/time/linux/clock_gettime.cpp @@ -15,8 +15,7 @@ namespace LIBC_NAMESPACE_DECL { // TODO(michaelrj): Move this into time/linux with the other syscalls. -LLVM_LIBC_FUNCTION(int, clock_gettime, - (clockid_t clockid, timespec *ts)) { +LLVM_LIBC_FUNCTION(int, clock_gettime, (clockid_t clockid, timespec *ts)) { auto result = internal::clock_gettime(clockid, ts); // A negative return value indicates an error with the magnitude of the diff --git a/libc/src/time/linux/nanosleep.cpp b/libc/src/time/linux/nanosleep.cpp index 7b0a4a3efd719..a30b97de40492 100644 --- a/libc/src/time/linux/nanosleep.cpp +++ b/libc/src/time/linux/nanosleep.cpp @@ -18,8 +18,7 @@ namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, nanosleep, - (const timespec *req, timespec *rem)) { +LLVM_LIBC_FUNCTION(int, nanosleep, (const timespec *req, timespec *rem)) { #if SYS_nanosleep int ret = LIBC_NAMESPACE::syscall_impl(SYS_nanosleep, req, rem); #elif defined(SYS_clock_nanosleep_time64) diff --git a/libc/src/time/linux/timespec_get.cpp b/libc/src/time/linux/timespec_get.cpp index e90f492b65e8f..031cb9f83b1c3 100644 --- a/libc/src/time/linux/timespec_get.cpp +++ b/libc/src/time/linux/timespec_get.cpp @@ -15,7 +15,7 @@ namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, timespec_get, (timespec *ts, int base)) { +LLVM_LIBC_FUNCTION(int, timespec_get, (timespec * ts, int base)) { clockid_t clockid; switch (base) { case TIME_UTC: