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..3851037e4161f 100644 --- a/libc/src/__support/time/CMakeLists.txt +++ b/libc/src/__support/time/CMakeLists.txt @@ -19,3 +19,12 @@ add_object_library( DEPENDS libc.src.__support.time.${LIBC_TARGET_OS}.clock_gettime ) + +if(TARGET libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime) + add_object_library( + clock_settime + ALIAS + DEPENDS + libc.src.__support.time.${LIBC_TARGET_OS}.clock_settime + ) +endif() 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.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..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, struct 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/clock_settime.cpp b/libc/src/time/linux/clock_settime.cpp new file mode 100644 index 0000000000000..3c582cf0b4646 --- /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 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/src/time/linux/nanosleep.cpp b/libc/src/time/linux/nanosleep.cpp index e5df1585df988..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 struct timespec *req, struct 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 a4d4372332732..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, (struct timespec * ts, int base)) { +LLVM_LIBC_FUNCTION(int, timespec_get, (timespec * ts, int base)) { clockid_t clockid; switch (base) { case TIME_UTC: 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); +}