[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