[libc-commits] [libc] [llvm] [libc][windows] start time API implementation (PR #117775)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Wed Dec 4 08:06:15 PST 2024


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/117775

>From 60137454d110c4efb65e5cf1bcdc84245b411253 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 26 Nov 2024 11:46:51 -0800
Subject: [PATCH 1/9] [libc][windows] start time API implementation

---
 libc/config/windows/entrypoints.txt           |  3 +
 libc/hdr/types/clockid_t.h                    |  2 +-
 .../llvm-libc-macros/windows/CMakeLists.txt   |  6 ++
 .../windows/time-macros-ext.h                 | 15 ++++
 libc/src/CMakeLists.txt                       |  2 +-
 libc/src/__support/time/CMakeLists.txt        |  7 ++
 .../time/{linux => }/clock_gettime.h          | 10 +--
 libc/src/__support/time/linux/CMakeLists.txt  |  2 +-
 .../__support/time/linux/clock_conversion.h   |  2 +-
 .../__support/time/linux/clock_gettime.cpp    |  2 +-
 .../src/__support/time/windows/CMakeLists.txt | 16 ++++
 .../__support/time/windows/clock_gettime.cpp  | 89 +++++++++++++++++++
 libc/src/time/CMakeLists.txt                  | 10 ++-
 libc/src/time/linux/CMakeLists.txt            | 21 +----
 libc/src/time/linux/clock.cpp                 |  2 +-
 libc/src/time/linux/clock_gettime.cpp         |  2 +-
 libc/src/time/linux/gettimeofday.cpp          |  2 +-
 libc/src/time/{linux => }/time.cpp            |  9 +-
 .../threads/linux/raw_mutex_test.cpp          |  2 +-
 .../llvm-project-overlay/libc/BUILD.bazel     |  2 +-
 20 files changed, 167 insertions(+), 39 deletions(-)
 create mode 100644 libc/include/llvm-libc-macros/windows/CMakeLists.txt
 create mode 100644 libc/include/llvm-libc-macros/windows/time-macros-ext.h
 rename libc/src/__support/time/{linux => }/clock_gettime.h (72%)
 create mode 100644 libc/src/__support/time/windows/CMakeLists.txt
 create mode 100644 libc/src/__support/time/windows/clock_gettime.cpp
 rename libc/src/time/{linux => }/time.cpp (82%)

diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 8f0b50bcc83ea2..d0796b85aec2af 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -95,6 +95,9 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # errno.h entrypoints
     libc.src.errno.errno
+
+    # time.h entrypoints
+    libc.src.time.time
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/hdr/types/clockid_t.h b/libc/hdr/types/clockid_t.h
index 333342072a2ff2..06fafc5b150612 100644
--- a/libc/hdr/types/clockid_t.h
+++ b/libc/hdr/types/clockid_t.h
@@ -9,7 +9,7 @@
 #ifndef LLVM_LIBC_HDR_TYPES_CLOCKID_T_H
 #define LLVM_LIBC_HDR_TYPES_CLOCKID_T_H
 
-#ifdef LIBC_FULL_BUILD
+#if defined(LIBC_FULL_BUILD) || defined(_MSC_VER)
 
 #include "include/llvm-libc-types/clockid_t.h"
 
diff --git a/libc/include/llvm-libc-macros/windows/CMakeLists.txt b/libc/include/llvm-libc-macros/windows/CMakeLists.txt
new file mode 100644
index 00000000000000..48afc795178a0d
--- /dev/null
+++ b/libc/include/llvm-libc-macros/windows/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_header(
+  time_macros_ext
+  HDR
+    time-macros-ext.h
+)
+
diff --git a/libc/include/llvm-libc-macros/windows/time-macros-ext.h b/libc/include/llvm-libc-macros/windows/time-macros-ext.h
new file mode 100644
index 00000000000000..e629a92f371c4a
--- /dev/null
+++ b/libc/include/llvm-libc-macros/windows/time-macros-ext.h
@@ -0,0 +1,15 @@
+//===-- Windows Time Macros Extension -------------------------------------===//
+//
+// 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_MACROS_WINDOWS_TIME_MACROS_EXT_H
+#define LLVM_LIBC_MACROS_WINDOWS_TIME_MACROS_EXT_H
+
+#define CLOCK_MONOTONIC 0
+#define CLOCK_REALTIME 1
+
+#endif // LLVM_LIBC_MACROS_WINDOWS_TIME_MACROS_EXT_H
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 02c193e635362e..dd3b51886edfea 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(stdio)
 add_subdirectory(stdlib)
 add_subdirectory(string)
 add_subdirectory(wchar)
+add_subdirectory(time)
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
   add_subdirectory(dirent)
@@ -40,5 +41,4 @@ add_subdirectory(setjmp)
 add_subdirectory(signal)
 add_subdirectory(spawn)
 add_subdirectory(threads)
-add_subdirectory(time)
 add_subdirectory(locale)
diff --git a/libc/src/__support/time/CMakeLists.txt b/libc/src/__support/time/CMakeLists.txt
index 89ddffb099388b..e73f2744b15a0e 100644
--- a/libc/src/__support/time/CMakeLists.txt
+++ b/libc/src/__support/time/CMakeLists.txt
@@ -2,6 +2,13 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
   add_subdirectory(${LIBC_TARGET_OS})
 endif()
 
+add_object_library(
+  clock_gettime
+  ALIAS
+  DEPENDS
+    libc.src.__support.time.${LIBC_TARGET_OS}.clock_gettime
+)
+
 add_header_library(
   units
   HDRS
diff --git a/libc/src/__support/time/linux/clock_gettime.h b/libc/src/__support/time/clock_gettime.h
similarity index 72%
rename from libc/src/__support/time/linux/clock_gettime.h
rename to libc/src/__support/time/clock_gettime.h
index f7f996ce7c1975..584bf546cd60cd 100644
--- a/libc/src/__support/time/linux/clock_gettime.h
+++ b/libc/src/__support/time/clock_gettime.h
@@ -6,21 +6,17 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H
-#define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H
+#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_CLOCK_GETTIME_H
+#define LLVM_LIBC_SRC___SUPPORT_TIME_CLOCK_GETTIME_H
 
 #include "hdr/types/clockid_t.h"
 #include "hdr/types/struct_timespec.h"
 #include "src/__support/error_or.h"
 
-#if defined(SYS_clock_gettime64)
-#include <linux/time_types.h>
-#endif
-
 namespace LIBC_NAMESPACE_DECL {
 namespace internal {
 ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts);
 } // namespace internal
 } // namespace LIBC_NAMESPACE_DECL
 
-#endif // LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H
+#endif // LLVM_LIBC_SRC___SUPPORT_TIME_CLOCK_GETTIME_H
diff --git a/libc/src/__support/time/linux/CMakeLists.txt b/libc/src/__support/time/linux/CMakeLists.txt
index 94ed09e6521524..6fec7eeba99add 100644
--- a/libc/src/__support/time/linux/CMakeLists.txt
+++ b/libc/src/__support/time/linux/CMakeLists.txt
@@ -1,7 +1,7 @@
 add_object_library(
   clock_gettime
   HDRS
-    clock_gettime.h
+    ../clock_gettime.h
   SRCS
     clock_gettime.cpp
   DEPENDS
diff --git a/libc/src/__support/time/linux/clock_conversion.h b/libc/src/__support/time/linux/clock_conversion.h
index 7a52873263a14c..ac5357d308d7c5 100644
--- a/libc/src/__support/time/linux/clock_conversion.h
+++ b/libc/src/__support/time/linux/clock_conversion.h
@@ -10,7 +10,7 @@
 #define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_CONVERSION_H
 
 #include "src/__support/macros/config.h"
-#include "src/__support/time/linux/clock_gettime.h"
+#include "src/__support/time/clock_gettime.h"
 #include "src/__support/time/units.h"
 
 namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/__support/time/linux/clock_gettime.cpp b/libc/src/__support/time/linux/clock_gettime.cpp
index 3a0eca417724ac..944fc0a2b80fe7 100644
--- a/libc/src/__support/time/linux/clock_gettime.cpp
+++ b/libc/src/__support/time/linux/clock_gettime.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/__support/time/linux/clock_gettime.h"
+#include "src/__support/time/clock_gettime.h"
 #include "hdr/types/clockid_t.h"
 #include "hdr/types/struct_timespec.h"
 #include "src/__support/OSUtil/linux/vdso.h"
diff --git a/libc/src/__support/time/windows/CMakeLists.txt b/libc/src/__support/time/windows/CMakeLists.txt
new file mode 100644
index 00000000000000..24b5fa7e086265
--- /dev/null
+++ b/libc/src/__support/time/windows/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_object_library(
+  clock_gettime
+  HDRS
+    ../clock_gettime.h
+  SRCS
+    clock_gettime.cpp
+  DEPENDS
+    libc.hdr.types.struct_timespec
+    libc.hdr.types.clockid_t
+    libc.hdr.errno_macros
+    libc.include.llvm-libc-macros.windows.time_macros_ext
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.CPP.atomic
+)
diff --git a/libc/src/__support/time/windows/clock_gettime.cpp b/libc/src/__support/time/windows/clock_gettime.cpp
new file mode 100644
index 00000000000000..6e0b7e028c9789
--- /dev/null
+++ b/libc/src/__support/time/windows/clock_gettime.cpp
@@ -0,0 +1,89 @@
+//===--- clock_gettime windows 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_gettime.h"
+#include "include/llvm-libc-macros/windows/time-macros-ext.h"
+#include "src/__support/CPP/atomic.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/time/units.h"
+#include <Windows.h>
+
+#ifdef __clang__
+#define UNINITIALIZED [[clang::uninitialized]]
+#else
+#define UNINITIALIZED
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+static long long get_ticks_per_second() {
+  static cpp::Atomic<long long> frequency = 0;
+  if (!frequency) {
+    UNINITIALIZED LARGE_INTEGER buffer;
+    // On systems that run Windows XP or later, the function will always
+    // succeed and will thus never return zero.
+    ::QueryPerformanceFrequency(&buffer);
+    frequency = buffer.QuadPart;
+    return buffer.QuadPart;
+  }
+  return frequency.load(cpp::MemoryOrder::RELAXED);
+}
+
+ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
+  using namespace time_units;
+  ErrorOr<int> ret = 0;
+  __try {
+    switch (clockid) {
+    default:
+      ret = cpp::unexpected(EINVAL);
+      break;
+
+    case CLOCK_MONOTONIC: {
+      // see
+      // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
+      // Is the performance counter monotonic (non-decreasing)?
+      // Yes. QPC does not go backward.
+      UNINITIALIZED LARGE_INTEGER buffer;
+      // On systems that run Windows XP or later, the function will always
+      // succeed and will thus never return zero.
+      ::QueryPerformanceCounter(&buffer);
+      long long freq = get_ticks_per_second();
+      long long ticks = buffer.QuadPart;
+      long long tv_sec = ticks / freq;
+      long long tv_nsec = (ticks % freq) * 1_s_ns / freq;
+      ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
+      ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
+      break;
+    }
+    case CLOCK_REALTIME: {
+      // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
+      // GetSystemTimePreciseAsFileTime
+      // This function is best suited for high-resolution time-of-day
+      // measurements, or time stamps that are synchronized to UTC
+      UNINITIALIZED FILETIME file_time;
+      UNINITIALIZED ULARGE_INTEGER time;
+      ::GetSystemTimePreciseAsFileTime(&file_time);
+      time.LowPart = file_time.dwLowDateTime;
+      time.HighPart = file_time.dwHighDateTime;
+
+      // adjust to POSIX epoch (from Jan 1, 1601 to Jan 1, 1970)
+      constexpr unsigned long long HNS_PER_SEC = 1_s_ns / 100ULL;
+      time.QuadPart -= (11644473600ULL * HNS_PER_SEC);
+      unsigned long long tv_sec = time.QuadPart / HNS_PER_SEC;
+      unsigned long long tv_nsec = (time.QuadPart % HNS_PER_SEC) * 100ULL;
+      ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
+      ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
+      break;
+    }
+    }
+  } __except (EXCEPTION_EXECUTE_HANDLER) {
+    ret = cpp::unexpected(EFAULT);
+  }
+  return ret;
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index f18e74a15e6fc2..3e8e6882ffc5d4 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -106,9 +106,15 @@ add_entrypoint_object(
 
 add_entrypoint_object(
   time
-  ALIAS
+  SRCS
+    time.cpp
+  HDRS
+    time_func.h
   DEPENDS
-    .${LIBC_TARGET_OS}.time
+    libc.hdr.time_macros
+    libc.hdr.types.time_t
+    libc.src.__support.time.clock_gettime
+    libc.src.errno.errno
 )
 
 add_entrypoint_object(
diff --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt
index 31fd7d1e64c85c..314623f9f425e7 100644
--- a/libc/src/time/linux/CMakeLists.txt
+++ b/libc/src/time/linux/CMakeLists.txt
@@ -1,16 +1,3 @@
-add_entrypoint_object(
-  time
-  SRCS
-    time.cpp
-  HDRS
-    ../time_func.h
-  DEPENDS
-    libc.hdr.time_macros
-    libc.hdr.types.time_t
-    libc.src.__support.time.linux.clock_gettime
-    libc.src.errno.errno
-)
-
 add_entrypoint_object(
   timespec_get
   SRCS
@@ -20,7 +7,7 @@ add_entrypoint_object(
   DEPENDS
     libc.hdr.time_macros
     libc.hdr.types.struct_timespec
-    libc.src.__support.time.linux.clock_gettime
+    libc.src.__support.time.clock_gettime
     libc.src.errno.errno
 )
 
@@ -34,7 +21,7 @@ add_entrypoint_object(
     libc.hdr.time_macros
     libc.hdr.types.clock_t
     libc.src.__support.time.units
-    libc.src.__support.time.linux.clock_gettime
+    libc.src.__support.time.clock_gettime
     libc.src.__support.CPP.limits
     libc.src.errno.errno
 )
@@ -62,7 +49,7 @@ add_entrypoint_object(
   DEPENDS
     libc.hdr.types.clockid_t
     libc.hdr.types.struct_timespec
-    libc.src.__support.time.linux.clock_gettime
+    libc.src.__support.time.clock_gettime
     libc.src.errno.errno
 )
 
@@ -75,7 +62,7 @@ add_entrypoint_object(
   DEPENDS
     libc.hdr.time_macros
     libc.hdr.types.suseconds_t
-    libc.src.__support.time.linux.clock_gettime
+    libc.src.__support.time.clock_gettime
     libc.src.__support.time.units
     libc.src.errno.errno
 )
diff --git a/libc/src/time/linux/clock.cpp b/libc/src/time/linux/clock.cpp
index f43e1bcad6a3a1..ee4fa82b4f8944 100644
--- a/libc/src/time/linux/clock.cpp
+++ b/libc/src/time/linux/clock.cpp
@@ -11,7 +11,7 @@
 #include "src/__support/CPP/limits.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/time/linux/clock_gettime.h"
+#include "src/__support/time/clock_gettime.h"
 #include "src/__support/time/units.h"
 #include "src/errno/libc_errno.h"
 
diff --git a/libc/src/time/linux/clock_gettime.cpp b/libc/src/time/linux/clock_gettime.cpp
index a2b20a6dbc9879..743c644d65d024 100644
--- a/libc/src/time/linux/clock_gettime.cpp
+++ b/libc/src/time/linux/clock_gettime.cpp
@@ -9,7 +9,7 @@
 #include "src/time/clock_gettime.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/time/linux/clock_gettime.h"
+#include "src/__support/time/clock_gettime.h"
 #include "src/errno/libc_errno.h"
 
 namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/time/linux/gettimeofday.cpp b/libc/src/time/linux/gettimeofday.cpp
index 19d9988ae73a6e..e8ddf482fc9840 100644
--- a/libc/src/time/linux/gettimeofday.cpp
+++ b/libc/src/time/linux/gettimeofday.cpp
@@ -11,7 +11,7 @@
 #include "hdr/types/suseconds_t.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/time/linux/clock_gettime.h"
+#include "src/__support/time/clock_gettime.h"
 #include "src/__support/time/units.h"
 #include "src/errno/libc_errno.h"
 
diff --git a/libc/src/time/linux/time.cpp b/libc/src/time/time.cpp
similarity index 82%
rename from libc/src/time/linux/time.cpp
rename to libc/src/time/time.cpp
index 20fb86e8e29dbb..e3615d995116b8 100644
--- a/libc/src/time/linux/time.cpp
+++ b/libc/src/time/time.cpp
@@ -9,14 +9,17 @@
 #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/__support/time/clock_gettime.h"
 #include "src/errno/libc_errno.h"
 #include "src/time/time_func.h"
 
+#ifdef _MSC_VER
+#include "include/llvm-libc-macros/windows/time-macros-ext.h"
+#endif
+
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) {
-  // TODO: Use the Linux VDSO to fetch the time and avoid the syscall.
+LLVM_LIBC_FUNCTION(time_t, time, (time_t *tp)) {
   struct timespec ts;
   auto result = internal::clock_gettime(CLOCK_REALTIME, &ts);
   if (!result.has_value()) {
diff --git a/libc/test/src/__support/threads/linux/raw_mutex_test.cpp b/libc/test/src/__support/threads/linux/raw_mutex_test.cpp
index 918f5d35c94f42..dadc706421d06e 100644
--- a/libc/test/src/__support/threads/linux/raw_mutex_test.cpp
+++ b/libc/test/src/__support/threads/linux/raw_mutex_test.cpp
@@ -12,7 +12,7 @@
 #include "src/__support/OSUtil/syscall.h"
 #include "src/__support/threads/linux/raw_mutex.h"
 #include "src/__support/threads/sleep.h"
-#include "src/__support/time/linux/clock_gettime.h"
+#include "src/__support/time/clock_gettime.h"
 #include "src/stdlib/exit.h"
 #include "src/sys/mman/mmap.h"
 #include "src/sys/mman/munmap.h"
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index c5a0076d2ef308..9aab193663fba8 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -1477,7 +1477,7 @@ libc_support_library(
 
 libc_support_library(
     name = "__support_time_linux_clock_gettime",
-    hdrs = ["src/__support/time/linux/clock_gettime.h"],
+    hdrs = ["src/__support/time/clock_gettime.h"],
     target_compatible_with = select({
         "@platforms//os:linux": [],
         "//conditions:default": ["@platforms//:incompatible"],

>From 60ce1865ee15f572a66b42414f8c9413aeee5ea5 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 26 Nov 2024 12:11:40 -0800
Subject: [PATCH 2/9] [libc][windows] enable test and fix namespace placement

---
 libc/src/__support/time/windows/clock_gettime.cpp | 3 ++-
 libc/test/src/CMakeLists.txt                      | 2 +-
 libc/test/src/time/CMakeLists.txt                 | 2 +-
 libc/test/src/time/time_test.cpp                  | 2 --
 4 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/libc/src/__support/time/windows/clock_gettime.cpp b/libc/src/__support/time/windows/clock_gettime.cpp
index 6e0b7e028c9789..f2be368352835f 100644
--- a/libc/src/__support/time/windows/clock_gettime.cpp
+++ b/libc/src/__support/time/windows/clock_gettime.cpp
@@ -20,7 +20,7 @@
 #endif
 
 namespace LIBC_NAMESPACE_DECL {
-
+namespace internal {
 static long long get_ticks_per_second() {
   static cpp::Atomic<long long> frequency = 0;
   if (!frequency) {
@@ -86,4 +86,5 @@ ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
   }
   return ret;
 }
+} // namespace internal
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 8ac8f91e98d4cc..606f6d837e4fe7 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -59,6 +59,7 @@ add_subdirectory(stdio)
 add_subdirectory(stdlib)
 add_subdirectory(string)
 add_subdirectory(wchar)
+add_subdirectory(time)
 
 # Depends on utilities in stdlib
 add_subdirectory(inttypes)
@@ -82,7 +83,6 @@ add_subdirectory(network)
 add_subdirectory(setjmp)
 add_subdirectory(signal)
 add_subdirectory(spawn)
-add_subdirectory(time)
 add_subdirectory(locale)
 
 if(${LIBC_TARGET_OS} STREQUAL "linux")
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 7151526b72b26d..19f90869852251 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -157,8 +157,8 @@ add_libc_unittest(
   SRCS
     time_test.cpp
   DEPENDS
-    libc.include.time
     libc.src.time.time
+    libc.src.__support.time.windows.clock_gettime
     libc.src.errno.errno
 )
 
diff --git a/libc/test/src/time/time_test.cpp b/libc/test/src/time/time_test.cpp
index d3d4dc9a285158..7cdb4e834633e5 100644
--- a/libc/test/src/time/time_test.cpp
+++ b/libc/test/src/time/time_test.cpp
@@ -9,8 +9,6 @@
 #include "src/time/time_func.h"
 #include "test/UnitTest/Test.h"
 
-#include <time.h>
-
 TEST(LlvmLibcTimeTest, SmokeTest) {
   time_t t1;
   time_t t2 = LIBC_NAMESPACE::time(&t1);

>From 471fb1e83608d02bdd25fc8ae330531a4e0684b5 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 26 Nov 2024 12:15:33 -0800
Subject: [PATCH 3/9] [libc][windows] fix format

---
 libc/src/time/time.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libc/src/time/time.cpp b/libc/src/time/time.cpp
index e3615d995116b8..a233676e702998 100644
--- a/libc/src/time/time.cpp
+++ b/libc/src/time/time.cpp
@@ -18,8 +18,7 @@
 #endif
 
 namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(time_t, time, (time_t *tp)) {
+LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) {
   struct timespec ts;
   auto result = internal::clock_gettime(CLOCK_REALTIME, &ts);
   if (!result.has_value()) {

>From 734a4f33e36211de4d39b41ce322f39b451164b2 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 26 Nov 2024 14:20:28 -0800
Subject: [PATCH 4/9] [libc][windows] remove SEH

---
 .../__support/time/windows/clock_gettime.cpp  | 84 +++++++++----------
 1 file changed, 40 insertions(+), 44 deletions(-)

diff --git a/libc/src/__support/time/windows/clock_gettime.cpp b/libc/src/__support/time/windows/clock_gettime.cpp
index f2be368352835f..379eae21b1d8d2 100644
--- a/libc/src/__support/time/windows/clock_gettime.cpp
+++ b/libc/src/__support/time/windows/clock_gettime.cpp
@@ -37,52 +37,48 @@ static long long get_ticks_per_second() {
 ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
   using namespace time_units;
   ErrorOr<int> ret = 0;
-  __try {
-    switch (clockid) {
-    default:
-      ret = cpp::unexpected(EINVAL);
-      break;
+  switch (clockid) {
+  default:
+    ret = cpp::unexpected(EINVAL);
+    break;
 
-    case CLOCK_MONOTONIC: {
-      // see
-      // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
-      // Is the performance counter monotonic (non-decreasing)?
-      // Yes. QPC does not go backward.
-      UNINITIALIZED LARGE_INTEGER buffer;
-      // On systems that run Windows XP or later, the function will always
-      // succeed and will thus never return zero.
-      ::QueryPerformanceCounter(&buffer);
-      long long freq = get_ticks_per_second();
-      long long ticks = buffer.QuadPart;
-      long long tv_sec = ticks / freq;
-      long long tv_nsec = (ticks % freq) * 1_s_ns / freq;
-      ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
-      ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
-      break;
-    }
-    case CLOCK_REALTIME: {
-      // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
-      // GetSystemTimePreciseAsFileTime
-      // This function is best suited for high-resolution time-of-day
-      // measurements, or time stamps that are synchronized to UTC
-      UNINITIALIZED FILETIME file_time;
-      UNINITIALIZED ULARGE_INTEGER time;
-      ::GetSystemTimePreciseAsFileTime(&file_time);
-      time.LowPart = file_time.dwLowDateTime;
-      time.HighPart = file_time.dwHighDateTime;
+  case CLOCK_MONOTONIC: {
+    // see
+    // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
+    // Is the performance counter monotonic (non-decreasing)?
+    // Yes. QPC does not go backward.
+    UNINITIALIZED LARGE_INTEGER buffer;
+    // On systems that run Windows XP or later, the function will always
+    // succeed and will thus never return zero.
+    ::QueryPerformanceCounter(&buffer);
+    long long freq = get_ticks_per_second();
+    long long ticks = buffer.QuadPart;
+    long long tv_sec = ticks / freq;
+    long long tv_nsec = (ticks % freq) * 1_s_ns / freq;
+    ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
+    ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
+    break;
+  }
+  case CLOCK_REALTIME: {
+    // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
+    // GetSystemTimePreciseAsFileTime
+    // This function is best suited for high-resolution time-of-day
+    // measurements, or time stamps that are synchronized to UTC
+    UNINITIALIZED FILETIME file_time;
+    UNINITIALIZED ULARGE_INTEGER time;
+    ::GetSystemTimePreciseAsFileTime(&file_time);
+    time.LowPart = file_time.dwLowDateTime;
+    time.HighPart = file_time.dwHighDateTime;
 
-      // adjust to POSIX epoch (from Jan 1, 1601 to Jan 1, 1970)
-      constexpr unsigned long long HNS_PER_SEC = 1_s_ns / 100ULL;
-      time.QuadPart -= (11644473600ULL * HNS_PER_SEC);
-      unsigned long long tv_sec = time.QuadPart / HNS_PER_SEC;
-      unsigned long long tv_nsec = (time.QuadPart % HNS_PER_SEC) * 100ULL;
-      ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
-      ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
-      break;
-    }
-    }
-  } __except (EXCEPTION_EXECUTE_HANDLER) {
-    ret = cpp::unexpected(EFAULT);
+    // adjust to POSIX epoch (from Jan 1, 1601 to Jan 1, 1970)
+    constexpr unsigned long long HNS_PER_SEC = 1_s_ns / 100ULL;
+    time.QuadPart -= (11644473600ULL * HNS_PER_SEC);
+    unsigned long long tv_sec = time.QuadPart / HNS_PER_SEC;
+    unsigned long long tv_nsec = (time.QuadPart % HNS_PER_SEC) * 100ULL;
+    ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
+    ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
+    break;
+  }
   }
   return ret;
 }

>From c7e61ba8c4fd6e83a36e5fa0a393891fbb718d3a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 27 Nov 2024 06:36:44 -0800
Subject: [PATCH 5/9] adjust frequency caching

---
 libc/src/__support/time/windows/clock_gettime.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/time/windows/clock_gettime.cpp b/libc/src/__support/time/windows/clock_gettime.cpp
index 379eae21b1d8d2..2bdbf740d34f15 100644
--- a/libc/src/__support/time/windows/clock_gettime.cpp
+++ b/libc/src/__support/time/windows/clock_gettime.cpp
@@ -23,15 +23,16 @@ namespace LIBC_NAMESPACE_DECL {
 namespace internal {
 static long long get_ticks_per_second() {
   static cpp::Atomic<long long> frequency = 0;
-  if (!frequency) {
+  auto freq = frequency.load(cpp::MemoryOrder::RELAXED);
+  if (!freq) {
     UNINITIALIZED LARGE_INTEGER buffer;
     // On systems that run Windows XP or later, the function will always
     // succeed and will thus never return zero.
     ::QueryPerformanceFrequency(&buffer);
-    frequency = buffer.QuadPart;
+    frequency.store(buffer.QuadPart, cpp::MemoryOrder::RELAXED);
     return buffer.QuadPart;
   }
-  return frequency.load(cpp::MemoryOrder::RELAXED);
+  return freq;
 }
 
 ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {

>From 7bf98bedc60742eabe867aa7eeced8fd1c13d99e Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 4 Dec 2024 07:37:47 -0800
Subject: [PATCH 6/9] address CRs

---
 libc/hdr/time_macros.h                        |  6 +++
 libc/hdr/types/clockid_t.h                    |  3 +-
 .../src/__support/time/windows/CMakeLists.txt |  1 +
 .../__support/time/windows/clock_gettime.cpp  | 43 +++++++++++++------
 libc/src/time/time.cpp                        |  6 +--
 5 files changed, 41 insertions(+), 18 deletions(-)

diff --git a/libc/hdr/time_macros.h b/libc/hdr/time_macros.h
index dc36fe66f7a802..4488a24848c359 100644
--- a/libc/hdr/time_macros.h
+++ b/libc/hdr/time_macros.h
@@ -19,4 +19,10 @@
 
 #endif // LLVM_LIBC_FULL_BUILD
 
+// TODO: For now, on windows, let's always include the extension header.
+// We will need to decide how to export this header.
+#ifdef _WIN32
+#include "include/llvm-libc-macros/windows/time-macros-ext.h"
+#endif // _WIN32
+
 #endif // LLVM_LIBC_HDR_TIME_MACROS_H
diff --git a/libc/hdr/types/clockid_t.h b/libc/hdr/types/clockid_t.h
index 06fafc5b150612..729e580aba4384 100644
--- a/libc/hdr/types/clockid_t.h
+++ b/libc/hdr/types/clockid_t.h
@@ -9,7 +9,8 @@
 #ifndef LLVM_LIBC_HDR_TYPES_CLOCKID_T_H
 #define LLVM_LIBC_HDR_TYPES_CLOCKID_T_H
 
-#if defined(LIBC_FULL_BUILD) || defined(_MSC_VER)
+// TODO: we will need to decide how to export extension to windows.
+#if defined(LIBC_FULL_BUILD) || defined(_WIN32)
 
 #include "include/llvm-libc-types/clockid_t.h"
 
diff --git a/libc/src/__support/time/windows/CMakeLists.txt b/libc/src/__support/time/windows/CMakeLists.txt
index 24b5fa7e086265..8406de838f6e45 100644
--- a/libc/src/__support/time/windows/CMakeLists.txt
+++ b/libc/src/__support/time/windows/CMakeLists.txt
@@ -13,4 +13,5 @@ add_object_library(
     libc.src.__support.error_or
     libc.src.__support.OSUtil.osutil
     libc.src.__support.CPP.atomic
+    libc.src.__support.CPP.limits
 )
diff --git a/libc/src/__support/time/windows/clock_gettime.cpp b/libc/src/__support/time/windows/clock_gettime.cpp
index 2bdbf740d34f15..c32a112e1db7a0 100644
--- a/libc/src/__support/time/windows/clock_gettime.cpp
+++ b/libc/src/__support/time/windows/clock_gettime.cpp
@@ -6,26 +6,29 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/__support/time/clock_gettime.h"
-#include "include/llvm-libc-macros/windows/time-macros-ext.h"
+#include "hdr/time_macros.h"
+
 #include "src/__support/CPP/atomic.h"
 #include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/time/clock_gettime.h"
 #include "src/__support/time/units.h"
-#include <Windows.h>
 
-#ifdef __clang__
-#define UNINITIALIZED [[clang::uninitialized]]
-#else
-#define UNINITIALIZED
-#endif
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
 
 namespace LIBC_NAMESPACE_DECL {
 namespace internal {
 static long long get_ticks_per_second() {
   static cpp::Atomic<long long> frequency = 0;
+  // Relaxed ordering is enough. It is okay to record the frequency multiple
+  // times. The store operation itself is atomic and the value must propagate
+  // as required by cache coherence.
   auto freq = frequency.load(cpp::MemoryOrder::RELAXED);
   if (!freq) {
-    UNINITIALIZED LARGE_INTEGER buffer;
+    [[clang::uninitialized]] LARGE_INTEGER buffer;
     // On systems that run Windows XP or later, the function will always
     // succeed and will thus never return zero.
     ::QueryPerformanceFrequency(&buffer);
@@ -37,6 +40,8 @@ static long long get_ticks_per_second() {
 
 ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
   using namespace time_units;
+  constexpr long long SEC_LIMIT =
+      cpp::numeric_limits<decltype(ts->tv_sec)>::max();
   ErrorOr<int> ret = 0;
   switch (clockid) {
   default:
@@ -48,7 +53,7 @@ ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
     // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
     // Is the performance counter monotonic (non-decreasing)?
     // Yes. QPC does not go backward.
-    UNINITIALIZED LARGE_INTEGER buffer;
+    [[clang::uninitialized]] LARGE_INTEGER buffer;
     // On systems that run Windows XP or later, the function will always
     // succeed and will thus never return zero.
     ::QueryPerformanceCounter(&buffer);
@@ -56,6 +61,10 @@ ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
     long long ticks = buffer.QuadPart;
     long long tv_sec = ticks / freq;
     long long tv_nsec = (ticks % freq) * 1_s_ns / freq;
+    if (LIBC_UNLIKELY(tv_sec > SEC_LIMIT)) {
+      ret = cpp::unexpected(EOVERFLOW);
+      break;
+    }
     ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
     ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
     break;
@@ -65,17 +74,27 @@ ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
     // GetSystemTimePreciseAsFileTime
     // This function is best suited for high-resolution time-of-day
     // measurements, or time stamps that are synchronized to UTC
-    UNINITIALIZED FILETIME file_time;
-    UNINITIALIZED ULARGE_INTEGER time;
+    [[clang::uninitialized]] FILETIME file_time;
+    [[clang::uninitialized]] ULARGE_INTEGER time;
     ::GetSystemTimePreciseAsFileTime(&file_time);
     time.LowPart = file_time.dwLowDateTime;
     time.HighPart = file_time.dwHighDateTime;
 
     // adjust to POSIX epoch (from Jan 1, 1601 to Jan 1, 1970)
     constexpr unsigned long long HNS_PER_SEC = 1_s_ns / 100ULL;
+    constexpr unsigned long long POSIX_TIME_SHIFT =
+        (11644473600ULL * HNS_PER_SEC);
+    if (LIBC_UNLIKELY(POSIX_TIME_SHIFT > time.QuadPart)) {
+      ret = cpp::unexpected(EOVERFLOW);
+      break;
+    }
     time.QuadPart -= (11644473600ULL * HNS_PER_SEC);
     unsigned long long tv_sec = time.QuadPart / HNS_PER_SEC;
     unsigned long long tv_nsec = (time.QuadPart % HNS_PER_SEC) * 100ULL;
+    if (LIBC_UNLIKELY(tv_sec > SEC_LIMIT)) {
+      ret = cpp::unexpected(EOVERFLOW);
+      break;
+    }
     ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec);
     ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec);
     break;
diff --git a/libc/src/time/time.cpp b/libc/src/time/time.cpp
index a233676e702998..ceded83b8e2e0e 100644
--- a/libc/src/time/time.cpp
+++ b/libc/src/time/time.cpp
@@ -13,12 +13,8 @@
 #include "src/errno/libc_errno.h"
 #include "src/time/time_func.h"
 
-#ifdef _MSC_VER
-#include "include/llvm-libc-macros/windows/time-macros-ext.h"
-#endif
-
 namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) {
+LLVM_LIBC_FUNCTION(time_t, time, (time_t *tp)) {
   struct timespec ts;
   auto result = internal::clock_gettime(CLOCK_REALTIME, &ts);
   if (!result.has_value()) {

>From de9887c6e7f145d9faf7dc9ad80d8327b0d6a7ae Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 4 Dec 2024 08:01:10 -0800
Subject: [PATCH 7/9] adjust dependency

---
 libc/hdr/CMakeLists.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 93da271f5e040b..5eb311f4bb2298 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -135,10 +135,18 @@ add_proxy_header_library(
     libc.include.llvm-libc-macros.unistd_macros
 )
 
+if (WIN32)
+  set(windows_addtional_time_macros libc.include.llvm-libc-macros.windows.time_macros_ext)
+else()
+  set(windows_addtional_time_macros "")
+endif()
+
 add_proxy_header_library(
   time_macros
   HDRS
     time_macros.h
+  DEPENDS
+    ${windows_addtional_time_macros}
   FULL_BUILD_DEPENDS
     libc.include.time
     libc.include.llvm-libc-macros.time_macros

>From 717e609cbf62f541c0f093d5aff7dbc14956d33f Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 4 Dec 2024 08:02:46 -0800
Subject: [PATCH 8/9] adjust dependency

---
 libc/test/src/time/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 19f90869852251..d2a98677a55435 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -158,7 +158,7 @@ add_libc_unittest(
     time_test.cpp
   DEPENDS
     libc.src.time.time
-    libc.src.__support.time.windows.clock_gettime
+    libc.src.__support.time.clock_gettime
     libc.src.errno.errno
 )
 

>From b0844cc64ef05b3a448ccb111cc2a9740361225f Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 4 Dec 2024 08:05:57 -0800
Subject: [PATCH 9/9] fix timespec_get

---
 libc/src/time/linux/timespec_get.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/time/linux/timespec_get.cpp b/libc/src/time/linux/timespec_get.cpp
index ba9f8eb2e4426b..cf5174523aa4f9 100644
--- a/libc/src/time/linux/timespec_get.cpp
+++ b/libc/src/time/linux/timespec_get.cpp
@@ -10,7 +10,7 @@
 #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/__support/time/clock_gettime.h"
 #include "src/errno/libc_errno.h"
 
 namespace LIBC_NAMESPACE_DECL {



More information about the libc-commits mailing list