-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc] Implement timespec_get
#116102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc] Implement timespec_get
#116102
Conversation
`timespec_get` is C standard counterpart to POSIX `clock_gettime`. On Linux we simply use `clock_gettime`. On baremetal we introduce a new external API `__llvm_libc_time_utc_get` that should be implemented by the vendor.
@llvm/pr-subscribers-libc Author: Petr Hosek (petrhosek) Changes
Full diff: https://github.com/llvm/llvm-project/pull/116102.diff 18 Files Affected:
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index b85ae1119345dd..9027717acb4dae 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.time.gmtime
libc.src.time.gmtime_r
libc.src.time.mktime
+ libc.src.time.timespec_get
# internal entrypoints
libc.startup.baremetal.init
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 199a030ee6371e..afae2b3e082be3 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -205,6 +205,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.time.gmtime
libc.src.time.gmtime_r
libc.src.time.mktime
+ libc.src.time.timespec_get
# internal entrypoints
libc.startup.baremetal.init
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 74ca3742977a5f..effa5b12d87ac4 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -999,6 +999,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.mktime
libc.src.time.nanosleep
libc.src.time.time
+ libc.src.time.timespec_get
# 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 5419462d4f5b3b..5a48baf104159f 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -937,6 +937,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.mktime
libc.src.time.nanosleep
libc.src.time.time
+ libc.src.time.timespec_get
# unistd.h entrypoints
libc.src.unistd.__llvm_libc_syscall
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 957e28bd66cc4c..7365b53e8add82 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1082,6 +1082,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.mktime
libc.src.time.nanosleep
libc.src.time.time
+ libc.src.time.timespec_get
# locale.h entrypoints
libc.src.locale.localeconv
diff --git a/libc/include/llvm-libc-macros/time-macros.h b/libc/include/llvm-libc-macros/time-macros.h
index 6d49ed484d5d48..02f2f7bfa7051d 100644
--- a/libc/include/llvm-libc-macros/time-macros.h
+++ b/libc/include/llvm-libc-macros/time-macros.h
@@ -7,4 +7,6 @@
#include "linux/time-macros.h"
#endif
+#define TIME_UTC 1
+
#endif // LLVM_LIBC_MACROS_TIME_MACROS_H
diff --git a/libc/newhdrgen/yaml/time.yaml b/libc/newhdrgen/yaml/time.yaml
index 69b40bef3160dd..3f745e5ee33868 100644
--- a/libc/newhdrgen/yaml/time.yaml
+++ b/libc/newhdrgen/yaml/time.yaml
@@ -96,3 +96,10 @@ functions:
return_type: time_t
arguments:
- type: time_t *
+ - name: timespec_get
+ standard:
+ - stdc
+ return_type: int
+ arguments:
+ - type: struct timespec *
+ - type: int
diff --git a/libc/src/__support/OSUtil/baremetal/CMakeLists.txt b/libc/src/__support/OSUtil/baremetal/CMakeLists.txt
index 8f9200ad0bd96e..5b02709315f9b1 100644
--- a/libc/src/__support/OSUtil/baremetal/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/baremetal/CMakeLists.txt
@@ -3,8 +3,10 @@ add_object_library(
SRCS
io.cpp
exit.cpp
+ time.cpp
HDRS
io.h
+ time.h
DEPENDS
libc.src.__support.common
libc.src.__support.CPP.string_view
diff --git a/libc/src/__support/OSUtil/baremetal/time.cpp b/libc/src/__support/OSUtil/baremetal/time.cpp
new file mode 100644
index 00000000000000..63f0624b4cda4e
--- /dev/null
+++ b/libc/src/__support/OSUtil/baremetal/time.cpp
@@ -0,0 +1,21 @@
+//===---------- Baremetal implementation of time utils ----------*- 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 "time.h"
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+extern "C" int __llvm_libc_time_utc_get(struct timespec *ts);
+
+int time_utc_get(struct timespec *ts) {
+ return __llvm_libc_time_utc_get(ts);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/OSUtil/baremetal/time.h b/libc/src/__support/OSUtil/baremetal/time.h
new file mode 100644
index 00000000000000..8c3ded377c7376
--- /dev/null
+++ b/libc/src/__support/OSUtil/baremetal/time.h
@@ -0,0 +1,21 @@
+//===---------- Baremetal implementation of time utils ----------*- 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_OSUTIL_BAREMETAL_TIME_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_BAREMETAL_TIME_H
+
+#include "include/llvm-libc-types/struct_timespec.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int time_utc_get(struct timespec *ts);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_BAREMETAL_IO_H
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index b3318e7ca87fa5..f18e74a15e6fc2 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -111,6 +111,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.time
)
+add_entrypoint_object(
+ timespec_get
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.timespec_get
+)
+
add_entrypoint_object(
clock
ALIAS
diff --git a/libc/src/time/baremetal/CMakeLists.txt b/libc/src/time/baremetal/CMakeLists.txt
new file mode 100644
index 00000000000000..4bddfa691d7c2a
--- /dev/null
+++ b/libc/src/time/baremetal/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_entrypoint_object(
+ timespec_get
+ SRCS
+ timespec_get.cpp
+ HDRS
+ ../timespec_get.h
+ DEPENDS
+ libc.hdr.time_macros
+ libc.hdr.types.struct_timespec
+ libc.src.__support.OSUtil.osutil
+)
diff --git a/libc/src/time/baremetal/timespec_get.cpp b/libc/src/time/baremetal/timespec_get.cpp
new file mode 100644
index 00000000000000..93ae4e9c9d1731
--- /dev/null
+++ b/libc/src/time/baremetal/timespec_get.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation of timespec_get for baremetal ----------------------===//
+//
+// 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/timespec_get.h"
+#include "hdr/time_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/OSUtil/baremetal/time.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec *ts, int base)) {
+ if (base != TIME_UTC) {
+ return 0;
+ }
+
+ return time_utc_get(ts);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt
index c15fb44ad5d123..31fd7d1e64c85c 100644
--- a/libc/src/time/linux/CMakeLists.txt
+++ b/libc/src/time/linux/CMakeLists.txt
@@ -11,6 +11,19 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ timespec_get
+ SRCS
+ timespec_get.cpp
+ HDRS
+ ../timespec_get.h
+ DEPENDS
+ libc.hdr.time_macros
+ libc.hdr.types.struct_timespec
+ libc.src.__support.time.linux.clock_gettime
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
clock
SRCS
diff --git a/libc/src/time/linux/timespec_get.cpp b/libc/src/time/linux/timespec_get.cpp
new file mode 100644
index 00000000000000..fa236cd3eaebee
--- /dev/null
+++ b/libc/src/time/linux/timespec_get.cpp
@@ -0,0 +1,31 @@
+//===-- Implementation of timespec_get for Linux --------------------------===//
+//
+// 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/timespec_get.h"
+#include "hdr/time_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/time/linux/clock_gettime.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec *ts, int base)) {
+ if (base != TIME_UTC) {
+ return 0;
+ }
+
+ auto result = internal::clock_gettime(CLOCK_REALTIME, ts);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return 0;
+ }
+ return base;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/timespec_get.h b/libc/src/time/timespec_get.h
new file mode 100644
index 00000000000000..32ba159a941606
--- /dev/null
+++ b/libc/src/time/timespec_get.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of timespec_get --------------------*- 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_TIMESPEC_GET_H
+#define LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
+
+#include "src/__support/macros/config.h"
+#include <time.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int timespec_get(struct timespec *ts, int base);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index bba01f063fed27..7151526b72b26d 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -162,6 +162,16 @@ add_libc_unittest(
libc.src.errno.errno
)
+add_libc_test(
+ timespec_get_test
+ SUITE
+ libc_time_unittests
+ SRCS
+ timespec_get_test.cpp
+ DEPENDS
+ libc.src.time.timespec_get
+)
+
add_libc_test(
clock_test
SUITE
diff --git a/libc/test/src/time/timespec_get_test.cpp b/libc/test/src/time/timespec_get_test.cpp
new file mode 100644
index 00000000000000..5bbd3db651d8a7
--- /dev/null
+++ b/libc/test/src/time/timespec_get_test.cpp
@@ -0,0 +1,32 @@
+//===-- Unittests for timespec_get ----------------------------------------===//
+//
+// 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/macros/properties/architectures.h"
+#include "src/time/timespec_get.h"
+#include "test/UnitTest/Test.h"
+
+#include <time.h>
+
+TEST(LlvmLibcTimespecGet, Utc) {
+#ifndef LIBC_TARGET_ARCH_IS_GPU
+ timespec ts;
+ int result;
+ result = LIBC_NAMESPACE::timespec_get(&ts, TIME_UTC);
+ ASSERT_EQ(result, TIME_UTC);
+ ASSERT_GT(ts.tv_sec, time_t(0));
+#endif
+}
+
+TEST(LlvmLibcTimespecGet, Unknown) {
+#ifndef LIBC_TARGET_ARCH_IS_GPU
+ timespec ts;
+ int result;
+ result = LIBC_NAMESPACE::timespec_get(&ts, 0);
+ ASSERT_EQ(result, 0);
+#endif
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patch!
int result; | ||
result = LIBC_NAMESPACE::timespec_get(&ts, 0); | ||
ASSERT_EQ(result, 0); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come these tests are disabled on the GPU?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GPU doesn't support UTC clock, it only implements monotonic clock. I could do the same for TIME_MONOTONIC
and for TIME_UTC
just return 0
. @jhuber6 what do you think?
libc/src/time/linux/timespec_get.cpp
Outdated
namespace LIBC_NAMESPACE_DECL { | ||
|
||
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) { | ||
if (base != TIME_UTC) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please file a TODO (then link to it from a comment in the sources) about supporting the other specified bases (TIME_MONOTONIC
, TIME_ACTIVE
, and TIME_THREAD_ACTIVE
). Especially since 7.29.2.6.5 recommends:
Because of its wider value range and improved indications on error, timespec_get with time base TIME_ACTIVE should be used instead of clock by new code whenever possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't aware of these, looks they were added in the latest standard (and aren't even mentioned on https://en.cppreference.com/w/c/chrono/timespec_get). I implemented all of them for Linux since it was straightforward.
clock_gettime is a POSIX API that may not be available on platforms like baremetal; timespec_get is the C11 equivalent. This change adds support for using timespec_get instead of clock_gettime to improve compatibility with non-POSIX platforms. For now, this is only enabled with LLVM libc which implemented timespec_get in llvm#116102, but in the future this can be expanded to other platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
FunctionSpec< | ||
"timespec_get", | ||
RetValSpec<IntType>, | ||
[ | ||
ArgSpec<StructTimeSpecPtr>, | ||
ArgSpec<IntType>, | ||
] | ||
>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since #117220 is close to landing, it might be best to skip adding anything to the old headergen files.
…timespec_get is defined After llvm/llvm-project#116102 we shouldn't need that workaround anymore. Original-Bug: 382538608 Original-Reviewed-on: https://fuchsia-review.googlesource.com/c/infra/recipes/+/1169452 Original-Revision: d3ff723f1c9a4cfc412452714d61b8169a4bff36 GitOrigin-RevId: 3f506a9f38779518d8bf23fa7f6d45d87af6ace6 Change-Id: I69d8386c90aaa0ef5c529fc0160a699762f878a2
clock_gettime is a POSIX API that may not be available on platforms like baremetal; timespec_get is the C11 equivalent. This change adds support for using timespec_get instead of clock_gettime to improve compatibility with non-POSIX platforms. For now, this is only enabled with LLVM libc which implemented timespec_get in #116102, but in the future this can be expanded to other platforms. Related to #84879.
timespec_get
is C standard counterpart to POSIXclock_gettime
. On Linux we simply useclock_gettime
. On baremetal we introduce a new external API__llvm_libc_timespec_get_utc
that should be implemented by the vendor.