Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/headers/time.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Implementation Status
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| clock_nanosleep | | | | | | | | | | | | | |
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| clock_settime | | | | | | | | | | | | | |
| clock_settime | |check| | |check| | | |check| | | | | | | | | | |
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ctime | |check| | |check| | | |check| | | | | | | | | | |
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
Expand Down
7 changes: 7 additions & 0 deletions libc/include/time.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions libc/src/__support/time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
22 changes: 22 additions & 0 deletions libc/src/__support/time/clock_settime.h
Original file line number Diff line number Diff line change
@@ -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<int> clock_settime(clockid_t clockid, const timespec *ts);
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_TIME_CLOCK_SETTIME_H
15 changes: 15 additions & 0 deletions libc/src/__support/time/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions libc/src/__support/time/linux/clock_settime.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h>

#if defined(SYS_clock_settime64)
#include <linux/time_types.h>
#endif

namespace LIBC_NAMESPACE_DECL {
namespace internal {
ErrorOr<int> clock_settime(clockid_t clockid, const timespec *ts) {
int ret;
#if defined(SYS_clock_settime)
ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_settime,
static_cast<long>(clockid),
reinterpret_cast<long>(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<int>(SYS_clock_settime64,
static_cast<long>(clockid),
reinterpret_cast<long>(&ts64));
if (ret == 0) {
ts->tv_sec = static_cast<decltype(ts->tv_sec)>(ts64.tv_sec);
ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(ts64.tv_nsec);
}
Comment on lines +35 to +43
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: shouldn't we copy values from ts into ts64 before calling doing syscall? E.g. :

#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{};
    // Populate the 64-bit kernel structure from the user-provided timespec.
    ts64.tv_sec = static_cast<decltype(ts64.tv_sec)>(ts->tv_sec);
    ts64.tv_nsec = static_cast<decltype(ts64.tv_nsec)>(ts->tv_nsec);

    ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_settime64,
                                            static_cast<long>(clockid),
                                            reinterpret_cast<long>(&ts64));
#else
...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should do the round trip?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SchrodingerZhu , what do you mean?

#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
8 changes: 8 additions & 0 deletions libc/src/time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

22 changes: 22 additions & 0 deletions libc/src/time/clock_settime.h
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions libc/src/time/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions libc/src/time/linux/clock_settime.cpp
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions libc/test/src/time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 31 additions & 0 deletions libc/test/src/time/clock_settime_test.cpp
Original file line number Diff line number Diff line change
@@ -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;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should also be a test where the syscall succeeds, we want to check both sides of the branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but the problem with that is that it would require the user the user to run the test as privileged user (through sudo or as root).

That's the question that I mentioned above, and I'm not exactly sure how to ensure that when some unprivileged user runs it, they would be able to run the test successfully.

#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<clockid_t>(-1), &ts);
ASSERT_EQ(result, -1);
ASSERT_ERRNO_EQ(EINVAL);
}
Loading