[libc-commits] [libc] 8b35159 - [libc] Introduces gmtime_r to LLVM libc, based on C99/C2X/Single Unix Sp.

Raman Tenneti via libc-commits libc-commits at lists.llvm.org
Mon Mar 22 14:04:26 PDT 2021


Author: Raman Tenneti
Date: 2021-03-22T14:04:05-07:00
New Revision: 8b35159ac720fcb9914e4931b416e17b0fbda771

URL: https://github.com/llvm/llvm-project/commit/8b35159ac720fcb9914e4931b416e17b0fbda771
DIFF: https://github.com/llvm/llvm-project/commit/8b35159ac720fcb9914e4931b416e17b0fbda771.diff

LOG: [libc] Introduces gmtime_r to LLVM libc, based on C99/C2X/Single Unix Sp.

gmtime and gmtime_r share the same common code. They call gmtime_internal
a static inline function. Thus added only validation tests for gmtime_r.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D99046

Added: 
    libc/src/time/gmtime_r.cpp
    libc/src/time/gmtime_r.h
    libc/test/src/time/gmtime_r_test.cpp

Modified: 
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/stdc.td
    libc/src/time/CMakeLists.txt
    libc/src/time/gmtime.cpp
    libc/src/time/time_utils.h
    libc/test/src/time/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index c8dfd3b687c9..36067fbbf22f 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -250,6 +250,7 @@ def TimeAPI : PublicAPI<"time.h"> {
 
   let Functions = [
     "gmtime",
+    "gmtime_r",
     "mktime",
   ];
 }

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 8dca7124ae49..28ce217dc513 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -177,6 +177,7 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # time.h entrypoints
     libc.src.time.gmtime
+    libc.src.time.gmtime_r
     libc.src.time.mktime
 
     # unistd.h entrypoints

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 8afb37f86760..2b3602b2e67c 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -603,6 +603,14 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<StructTmPtr>,
               [ArgSpec<TimeTTypePtr>]
           >,
+          FunctionSpec<
+              "gmtime_r",
+              RetValSpec<StructTmPtr>,
+              [
+                  ArgSpec<TimeTTypePtr>,
+                  ArgSpec<StructTmPtr>,
+              ]
+          >,
           FunctionSpec<
               "mktime",
               RetValSpec<TimeTType>,

diff  --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index c11a658a8ccd..03343cf036c5 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -4,6 +4,10 @@ add_object_library(
     time_utils.cpp
   HDRS
     time_utils.h
+  DEPENDS
+    libc.include.errno
+    libc.include.time
+    libc.src.errno.__errno_location
 )
 
 add_entrypoint_object(
@@ -14,9 +18,18 @@ add_entrypoint_object(
     gmtime.h
   DEPENDS
     .time_utils
-    libc.include.errno
     libc.include.time
-    libc.src.errno.__errno_location
+)
+
+add_entrypoint_object(
+  gmtime_r
+  SRCS
+    gmtime_r.cpp
+  HDRS
+    gmtime_r.h
+  DEPENDS
+    .time_utils
+    libc.include.time
 )
 
 add_entrypoint_object(

diff  --git a/libc/src/time/gmtime.cpp b/libc/src/time/gmtime.cpp
index 04991a539d07..75ce85941b18 100644
--- a/libc/src/time/gmtime.cpp
+++ b/libc/src/time/gmtime.cpp
@@ -10,20 +10,11 @@
 #include "src/__support/common.h"
 #include "src/time/time_utils.h"
 
-#include <limits.h>
-
 namespace __llvm_libc {
 
 LLVM_LIBC_FUNCTION(struct tm *, gmtime, (const time_t *timer)) {
   static struct tm tm_out;
-  time_t seconds = *timer;
-  // Update the tm structure's year, month, day, etc. from seconds.
-  if (time_utils::UpdateFromSeconds(seconds, &tm_out) < 0) {
-    time_utils::OutOfRange();
-    return nullptr;
-  }
-
-  return &tm_out;
+  return time_utils::gmtime_internal(timer, &tm_out);
 }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/time/gmtime_r.cpp b/libc/src/time/gmtime_r.cpp
new file mode 100644
index 000000000000..67bf12696e2e
--- /dev/null
+++ b/libc/src/time/gmtime_r.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of gmtime_r 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/gmtime_r.h"
+#include "src/__support/common.h"
+#include "src/time/time_utils.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(struct tm *, gmtime_r,
+                   (const time_t *timer, struct tm *result)) {
+  return time_utils::gmtime_internal(timer, result);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/time/gmtime_r.h b/libc/src/time/gmtime_r.h
new file mode 100644
index 000000000000..8e9fc94b5cee
--- /dev/null
+++ b/libc/src/time/gmtime_r.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of gmtime_r -----------------------*- 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_GMTIME_R_H
+#define LLVM_LIBC_SRC_TIME_GMTIME_R_H
+
+#include <time.h>
+
+namespace __llvm_libc {
+
+struct tm *gmtime_r(const time_t *timer, struct tm *result);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_TIME_GMTIME_R_H
+
+#include "include/time.h"

diff  --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index c87124e6e753..cca03007084c 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -53,15 +53,27 @@ struct TimeConstants {
   static constexpr time_t OutOfRangeReturnValue = -1;
 };
 
+// Update the "tm" structure's year, month, etc. members from seconds.
+// "total_seconds" is the number of seconds since January 1st, 1970.
+extern int64_t UpdateFromSeconds(int64_t total_seconds, struct tm *tm);
+
 // POSIX.1-2017 requires this.
 static inline time_t OutOfRange() {
   llvmlibc_errno = EOVERFLOW;
   return static_cast<time_t>(-1);
 }
 
-// Update the "tm" structure's year, month, etc. members from seconds.
-// "total_seconds" is the number of seconds since January 1st, 1970.
-extern int64_t UpdateFromSeconds(int64_t total_seconds, struct tm *tm);
+static inline struct tm *gmtime_internal(const time_t *timer,
+                                         struct tm *result) {
+  int64_t seconds = *timer;
+  // Update the tm structure's year, month, day, etc. from seconds.
+  if (UpdateFromSeconds(seconds, result) < 0) {
+    OutOfRange();
+    return nullptr;
+  }
+
+  return result;
+}
 
 } // namespace time_utils
 } // namespace __llvm_libc

diff  --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 690cdce67115..e3bf5e228c65 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -1,15 +1,37 @@
 add_libc_testsuite(libc_time_unittests)
 
 add_libc_unittest(
-  mktime
+  gmtime
   SUITE
     libc_time_unittests
   SRCS
     gmtime_test.cpp
-    mktime_test.cpp
   HDRS
     TmMatcher.h
   DEPENDS
     libc.src.time.gmtime
+)
+
+add_libc_unittest(
+  gmtime_r
+  SUITE
+    libc_time_unittests
+  SRCS
+    gmtime_r_test.cpp
+  HDRS
+    TmMatcher.h
+  DEPENDS
+    libc.src.time.gmtime_r
+)
+
+add_libc_unittest(
+  mktime
+  SUITE
+    libc_time_unittests
+  SRCS
+    mktime_test.cpp
+  HDRS
+    TmMatcher.h
+  DEPENDS
     libc.src.time.mktime
 )

diff  --git a/libc/test/src/time/gmtime_r_test.cpp b/libc/test/src/time/gmtime_r_test.cpp
new file mode 100644
index 000000000000..037460c050c7
--- /dev/null
+++ b/libc/test/src/time/gmtime_r_test.cpp
@@ -0,0 +1,57 @@
+//===-- Unittests for gmtime_r --------------------------------------------===//
+//
+// 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/gmtime_r.h"
+#include "src/time/time_utils.h"
+#include "test/src/time/TmMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::time_utils::TimeConstants;
+
+// gmtime and gmtime_r share the same code and thus didn't repeat all the tests
+// from gmtime. Added couple of validation tests.
+TEST(LlvmLibcGmTimeR, EndOf32BitEpochYear) {
+  // Test for maximum value of a signed 32-bit integer.
+  // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
+  time_t seconds = 0x7FFFFFFF;
+  struct tm tm_data;
+  struct tm *tm_data_ptr;
+  tm_data_ptr = __llvm_libc::gmtime_r(&seconds, &tm_data);
+  EXPECT_TM_EQ((tm{7,  // sec
+                   14, // min
+                   3,  // hr
+                   19, // day
+                   0,  // tm_mon starts with 0 for Jan
+                   2038 - TimeConstants::TimeYearBase, // year
+                   2,                                  // wday
+                   7,                                  // yday
+                   0}),
+               *tm_data_ptr);
+  EXPECT_TM_EQ(*tm_data_ptr, tm_data);
+}
+
+TEST(LlvmLibcGmTimeR, Max64BitYear) {
+  if (sizeof(time_t) == 4)
+    return;
+  // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
+  time_t seconds = 67767976202043050;
+  struct tm tm_data;
+  struct tm *tm_data_ptr;
+  tm_data_ptr = __llvm_libc::gmtime_r(&seconds, &tm_data);
+  EXPECT_TM_EQ((tm{50, // sec
+                   50, // min
+                   12, // hr
+                   1,  // day
+                   0,  // tm_mon starts with 0 for Jan
+                   2147483647 - TimeConstants::TimeYearBase, // year
+                   2,                                        // wday
+                   50,                                       // yday
+                   0}),
+               *tm_data_ptr);
+  EXPECT_TM_EQ(*tm_data_ptr, tm_data);
+}


        


More information about the libc-commits mailing list