[libc-commits] [libc] 22ea0e5 - [libc] Add Linux implementations of time and clock functions.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Tue Oct 25 11:06:14 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-10-25T18:06:05Z
New Revision: 22ea0e5d9b2eb388cb235f798aacd2170f77b6e1
URL: https://github.com/llvm/llvm-project/commit/22ea0e5d9b2eb388cb235f798aacd2170f77b6e1
DIFF: https://github.com/llvm/llvm-project/commit/22ea0e5d9b2eb388cb235f798aacd2170f77b6e1.diff
LOG: [libc] Add Linux implementations of time and clock functions.
Reviewed By: michaelrj
Differential Revision: https://reviews.llvm.org/D136666
Added:
libc/include/llvm-libc-types/clock_t.h
libc/src/time/clock.h
libc/src/time/linux/CMakeLists.txt
libc/src/time/linux/clock.cpp
libc/src/time/linux/time.cpp
libc/src/time/time_func.h
libc/test/src/time/clock_test.cpp
libc/test/src/time/time_test.cpp
Modified:
libc/config/linux/api.td
libc/config/linux/x86_64/entrypoints.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-macros/linux/time-macros.h
libc/include/llvm-libc-types/CMakeLists.txt
libc/spec/stdc.td
libc/src/time/CMakeLists.txt
libc/test/src/time/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index dfd2b9adde693..6b69e3ff85f4a 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -172,7 +172,7 @@ def StdlibAPI : PublicAPI<"stdlib.h"> {
}
def TimeAPI : PublicAPI<"time.h"> {
- let Types = ["time_t", "struct tm", "struct timespec", "clockid_t",];
+ let Types = ["clock_t", "time_t", "struct tm", "struct timespec", "clockid_t",];
}
def ErrnoAPI : PublicAPI<"errno.h"> {
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 6e870bc834b2f..91a3bf97d1a76 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -443,12 +443,14 @@ if(LLVM_LIBC_FULL_BUILD)
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
+ libc.src.time.clock_gettime
+ libc.src.time.clock
libc.src.time.
diff time
libc.src.time.gmtime
libc.src.time.gmtime_r
libc.src.time.mktime
libc.src.time.nanosleep
- libc.src.time.clock_gettime
+ libc.src.time.time
# unistd.h entrypoints
libc.src.unistd.environ
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 135e659a74684..cb0e885622bc7 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -93,6 +93,7 @@ add_gen_header(
.llvm_libc_common_h
.llvm-libc-macros.time_macros
.llvm-libc-types.time_t
+ .llvm-libc-types.clock_t
.llvm-libc-types.clockid_t
.llvm-libc-types.struct_tm
.llvm-libc-types.struct_timespec
diff --git a/libc/include/llvm-libc-macros/linux/time-macros.h b/libc/include/llvm-libc-macros/linux/time-macros.h
index c2dea4d5796af..ace27cb2e9eb4 100644
--- a/libc/include/llvm-libc-macros/linux/time-macros.h
+++ b/libc/include/llvm-libc-macros/linux/time-macros.h
@@ -21,4 +21,6 @@
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9
+#define CLOCKS_PER_SEC 1000000
+
#endif //__LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index aa3fe46507787..1c667d5a55b7a 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -16,6 +16,7 @@ add_header(__thread_type HDR __thread_type.h)
add_header(blkcnt_t HDR blkcnt_t.h)
add_header(blksize_t HDR blksize_t.h)
add_header(cc_t HDR cc_t.h)
+add_header(clock_t HDR clock_t.h)
add_header(clockid_t HDR clockid_t.h)
add_header(cnd_t HDR cnd_t.h)
add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off64_t)
diff --git a/libc/include/llvm-libc-types/clock_t.h b/libc/include/llvm-libc-types/clock_t.h
new file mode 100644
index 0000000000000..b7969d602c6b3
--- /dev/null
+++ b/libc/include/llvm-libc-types/clock_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of clock_t type ----------------------------------------===//
+//
+// 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_TYPES_CLOCK_T_H__
+#define __LLVM_LIBC_TYPES_CLOCK_T_H__
+
+typedef long clock_t;
+
+#endif // __LLVM_LIBC_TYPES_CLOCK_T_H__
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 3981d0d355f99..bc3778053ae25 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -3,6 +3,7 @@ def StdC : StandardSpec<"stdc"> {
NamedType StructTmType = NamedType<"struct tm">;
PtrType StructTmPtr = PtrType<StructTmType>;
PtrType TimeTTypePtr = PtrType<TimeTType>;
+ NamedType ClockT = NamedType<"clock_t">;
NamedType DivTType = NamedType<"div_t">;
NamedType LDivTType = NamedType<"ldiv_t">;
@@ -917,8 +918,9 @@ def StdC : StandardSpec<"stdc"> {
"time.h",
[], // Macros
[ // Types
- StructTmType,
- TimeTType,
+ ClockT,
+ StructTmType,
+ TimeTType,
],
[], // Enumerations
[
@@ -935,6 +937,11 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<CharPtr>,
]
>,
+ FunctionSpec<
+ "clock",
+ RetValSpec<ClockT>,
+ [ArgSpec<VoidType>]
+ >,
FunctionSpec<
"
diff time",
RetValSpec<DoubleType>,
@@ -961,6 +968,11 @@ def StdC : StandardSpec<"stdc"> {
RetValSpec<TimeTType>,
[ArgSpec<StructTmPtr>]
>,
+ FunctionSpec<
+ "time",
+ RetValSpec<TimeTType>,
+ [ArgSpec<TimeTTypePtr>]
+ >,
]
>;
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index d3bb5d4378763..8a8a30bf34d6b 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
add_object_library(
time_utils
SRCS
@@ -103,3 +107,17 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
+
+add_entrypoint_object(
+ time
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.time
+)
+
+add_entrypoint_object(
+ clock
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.clock
+)
diff --git a/libc/src/time/clock.h b/libc/src/time/clock.h
new file mode 100644
index 0000000000000..7a259e6f4b895
--- /dev/null
+++ b/libc/src/time/clock.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of clock --------------------------*- 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_H
+#define LLVM_LIBC_SRC_TIME_CLOCK_H
+
+#include <time.h>
+
+namespace __llvm_libc {
+
+clock_t clock();
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_TIME_CLOCK_H
diff --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..c3f11c317f5d0
--- /dev/null
+++ b/libc/src/time/linux/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_entrypoint_object(
+ time
+ SRCS
+ time.cpp
+ HDRS
+ ../time_func.h
+ DEPENDS
+ libc.include.time
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ clock
+ SRCS
+ clock.cpp
+ HDRS
+ ../clock.h
+ DEPENDS
+ libc.include.time
+ libc.include.sys_syscall
+ libc.src.__support.CPP.limits
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
diff --git a/libc/src/time/linux/clock.cpp b/libc/src/time/linux/clock.cpp
new file mode 100644
index 0000000000000..d448f8ba54ed8
--- /dev/null
+++ b/libc/src/time/linux/clock.cpp
@@ -0,0 +1,49 @@
+//===-- Linux implementation of the clock 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.h"
+
+#include "src/__support/CPP/limits.h"
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/syscall.h> // For syscall numbers.
+#include <time.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(clock_t, clock, ()) {
+ struct timespec ts;
+ long ret_val = __llvm_libc::syscall_impl(
+ SYS_clock_gettime, CLOCK_PROCESS_CPUTIME_ID, reinterpret_cast<long>(&ts));
+ if (ret_val < 0) {
+ errno = -ret_val;
+ return clock_t(-1);
+ }
+
+ // The above syscall gets the CPU time in seconds plus nanoseconds. We should
+ // make sure that corresponding clocks can actually be represented by clock-t.
+ // The standard requires that we return clock_t(-1) if we cannot represent
+ // clocks as a clock_t value.
+ constexpr clock_t CLOCK_SECS_MAX =
+ cpp::numeric_limits<clock_t>::max() / CLOCKS_PER_SEC;
+ if (ts.tv_sec > CLOCK_SECS_MAX)
+ return clock_t(-1);
+ if (ts.tv_nsec / 1000000000 > CLOCK_SECS_MAX - ts.tv_sec)
+ return clock_t(-1);
+
+ // For the integer computation converting tv_nsec to clocks to work
+ // correctly, we want CLOCKS_PER_SEC to be less than 1000000000.
+ static_assert(1000000000 > CLOCKS_PER_SEC,
+ "Expected CLOCKS_PER_SEC to be less than 1000000000.");
+ return clock_t(ts.tv_sec * CLOCKS_PER_SEC +
+ ts.tv_nsec / (1000000000 / CLOCKS_PER_SEC));
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/time/linux/time.cpp b/libc/src/time/linux/time.cpp
new file mode 100644
index 0000000000000..9e39ffa502597
--- /dev/null
+++ b/libc/src/time/linux/time.cpp
@@ -0,0 +1,35 @@
+//===-- Linux implementation of the time 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/time_func.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/syscall.h> // For syscall numbers.
+#include <time.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) {
+ // TODO: Use the Linux VDSO to fetch the time and avoid the syscall.
+ struct timespec ts;
+ long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime, CLOCK_REALTIME,
+ reinterpret_cast<long>(&ts));
+ if (ret_val < 0) {
+ errno = -ret_val;
+ return -1;
+ }
+
+ if (tp != nullptr)
+ *tp = time_t(ts.tv_sec);
+ return time_t(ts.tv_sec);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/time/time_func.h b/libc/src/time/time_func.h
new file mode 100644
index 0000000000000..a24834c50b625
--- /dev/null
+++ b/libc/src/time/time_func.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of time ---------------------------*- 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_TIME_FUNC_H
+#define LLVM_LIBC_SRC_TIME_TIME_FUNC_H
+
+#include <time.h>
+
+// Note this header file is named time_func.h to avoid conflicts with the
+// public header file time.h.
+namespace __llvm_libc {
+
+time_t time(time_t *tp);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_TIME_TIME_FUNC_H
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 10a2f4ee7ec03..5903333c665fb 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -105,3 +105,27 @@ add_libc_unittest(
libc.include.time
libc.src.time.nanosleep
)
+
+add_libc_unittest(
+ time_test
+ SUITE
+ libc_time_unittests
+ SRCS
+ time_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.time
+ libc.src.time.time
+)
+
+add_libc_unittest(
+ clock_test
+ SUITE
+ libc_time_unittests
+ SRCS
+ clock_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.time
+ libc.src.time.clock
+)
diff --git a/libc/test/src/time/clock_test.cpp b/libc/test/src/time/clock_test.cpp
new file mode 100644
index 0000000000000..2aa61babad351
--- /dev/null
+++ b/libc/test/src/time/clock_test.cpp
@@ -0,0 +1,22 @@
+//===-- Unittests for clock -----------------------------------------------===//
+//
+// 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.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+
+TEST(LlvmLibcClockTest, SmokeTest) {
+ clock_t c1 = __llvm_libc::clock();
+ ASSERT_GT(c1, clock_t(0));
+
+ clock_t c2 = __llvm_libc::clock();
+ ASSERT_GE(c2, c1);
+}
diff --git a/libc/test/src/time/time_test.cpp b/libc/test/src/time/time_test.cpp
new file mode 100644
index 0000000000000..2f5214a15a1b6
--- /dev/null
+++ b/libc/test/src/time/time_test.cpp
@@ -0,0 +1,24 @@
+//===-- Unittests for time ------------------------------------------------===//
+//
+// 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/time_func.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+
+TEST(LlvmLibcTimeTest, SmokeTest) {
+ time_t t1;
+ time_t t2 = __llvm_libc::time(&t1);
+ ASSERT_EQ(t1, t2);
+ ASSERT_GT(t1, time_t(0));
+
+ time_t t3 = __llvm_libc::time(nullptr);
+ ASSERT_GE(t3, t1);
+}
More information about the libc-commits
mailing list