[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