Skip to content

Commit a129bfa

Browse files
rtenneti-googlememfrob
authored andcommitted
[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
1 parent 5d20243 commit a129bfa

File tree

10 files changed

+164
-17
lines changed

10 files changed

+164
-17
lines changed

libc/config/linux/api.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ def TimeAPI : PublicAPI<"time.h"> {
250250

251251
let Functions = [
252252
"gmtime",
253+
"gmtime_r",
253254
"mktime",
254255
];
255256
}

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ if(LLVM_LIBC_FULL_BUILD)
177177

178178
# time.h entrypoints
179179
libc.src.time.gmtime
180+
libc.src.time.gmtime_r
180181
libc.src.time.mktime
181182

182183
# unistd.h entrypoints

libc/spec/stdc.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,14 @@ def StdC : StandardSpec<"stdc"> {
603603
RetValSpec<StructTmPtr>,
604604
[ArgSpec<TimeTTypePtr>]
605605
>,
606+
FunctionSpec<
607+
"gmtime_r",
608+
RetValSpec<StructTmPtr>,
609+
[
610+
ArgSpec<TimeTTypePtr>,
611+
ArgSpec<StructTmPtr>,
612+
]
613+
>,
606614
FunctionSpec<
607615
"mktime",
608616
RetValSpec<TimeTType>,

libc/src/time/CMakeLists.txt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ add_object_library(
44
time_utils.cpp
55
HDRS
66
time_utils.h
7+
DEPENDS
8+
libc.include.errno
9+
libc.include.time
10+
libc.src.errno.__errno_location
711
)
812

913
add_entrypoint_object(
@@ -14,9 +18,18 @@ add_entrypoint_object(
1418
gmtime.h
1519
DEPENDS
1620
.time_utils
17-
libc.include.errno
1821
libc.include.time
19-
libc.src.errno.__errno_location
22+
)
23+
24+
add_entrypoint_object(
25+
gmtime_r
26+
SRCS
27+
gmtime_r.cpp
28+
HDRS
29+
gmtime_r.h
30+
DEPENDS
31+
.time_utils
32+
libc.include.time
2033
)
2134

2235
add_entrypoint_object(

libc/src/time/gmtime.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,11 @@
1010
#include "src/__support/common.h"
1111
#include "src/time/time_utils.h"
1212

13-
#include <limits.h>
14-
1513
namespace __llvm_libc {
1614

1715
LLVM_LIBC_FUNCTION(struct tm *, gmtime, (const time_t *timer)) {
1816
static struct tm tm_out;
19-
time_t seconds = *timer;
20-
// Update the tm structure's year, month, day, etc. from seconds.
21-
if (time_utils::UpdateFromSeconds(seconds, &tm_out) < 0) {
22-
time_utils::OutOfRange();
23-
return nullptr;
24-
}
25-
26-
return &tm_out;
17+
return time_utils::gmtime_internal(timer, &tm_out);
2718
}
2819

2920
} // namespace __llvm_libc

libc/src/time/gmtime_r.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation of gmtime_r function -------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/time/gmtime_r.h"
10+
#include "src/__support/common.h"
11+
#include "src/time/time_utils.h"
12+
13+
namespace __llvm_libc {
14+
15+
LLVM_LIBC_FUNCTION(struct tm *, gmtime_r,
16+
(const time_t *timer, struct tm *result)) {
17+
return time_utils::gmtime_internal(timer, result);
18+
}
19+
20+
} // namespace __llvm_libc

libc/src/time/gmtime_r.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- Implementation header of gmtime_r -----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_TIME_GMTIME_R_H
10+
#define LLVM_LIBC_SRC_TIME_GMTIME_R_H
11+
12+
#include <time.h>
13+
14+
namespace __llvm_libc {
15+
16+
struct tm *gmtime_r(const time_t *timer, struct tm *result);
17+
18+
} // namespace __llvm_libc
19+
20+
#endif // LLVM_LIBC_SRC_TIME_GMTIME_R_H
21+
22+
#include "include/time.h"

libc/src/time/time_utils.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,27 @@ struct TimeConstants {
5353
static constexpr time_t OutOfRangeReturnValue = -1;
5454
};
5555

56+
// Update the "tm" structure's year, month, etc. members from seconds.
57+
// "total_seconds" is the number of seconds since January 1st, 1970.
58+
extern int64_t UpdateFromSeconds(int64_t total_seconds, struct tm *tm);
59+
5660
// POSIX.1-2017 requires this.
5761
static inline time_t OutOfRange() {
5862
llvmlibc_errno = EOVERFLOW;
5963
return static_cast<time_t>(-1);
6064
}
6165

62-
// Update the "tm" structure's year, month, etc. members from seconds.
63-
// "total_seconds" is the number of seconds since January 1st, 1970.
64-
extern int64_t UpdateFromSeconds(int64_t total_seconds, struct tm *tm);
66+
static inline struct tm *gmtime_internal(const time_t *timer,
67+
struct tm *result) {
68+
int64_t seconds = *timer;
69+
// Update the tm structure's year, month, day, etc. from seconds.
70+
if (UpdateFromSeconds(seconds, result) < 0) {
71+
OutOfRange();
72+
return nullptr;
73+
}
74+
75+
return result;
76+
}
6577

6678
} // namespace time_utils
6779
} // namespace __llvm_libc

libc/test/src/time/CMakeLists.txt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,37 @@
11
add_libc_testsuite(libc_time_unittests)
22

33
add_libc_unittest(
4-
mktime
4+
gmtime
55
SUITE
66
libc_time_unittests
77
SRCS
88
gmtime_test.cpp
9-
mktime_test.cpp
109
HDRS
1110
TmMatcher.h
1211
DEPENDS
1312
libc.src.time.gmtime
13+
)
14+
15+
add_libc_unittest(
16+
gmtime_r
17+
SUITE
18+
libc_time_unittests
19+
SRCS
20+
gmtime_r_test.cpp
21+
HDRS
22+
TmMatcher.h
23+
DEPENDS
24+
libc.src.time.gmtime_r
25+
)
26+
27+
add_libc_unittest(
28+
mktime
29+
SUITE
30+
libc_time_unittests
31+
SRCS
32+
mktime_test.cpp
33+
HDRS
34+
TmMatcher.h
35+
DEPENDS
1436
libc.src.time.mktime
1537
)

libc/test/src/time/gmtime_r_test.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===-- Unittests for gmtime_r --------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/time/gmtime_r.h"
10+
#include "src/time/time_utils.h"
11+
#include "test/src/time/TmMatcher.h"
12+
#include "utils/UnitTest/Test.h"
13+
14+
using __llvm_libc::time_utils::TimeConstants;
15+
16+
// gmtime and gmtime_r share the same code and thus didn't repeat all the tests
17+
// from gmtime. Added couple of validation tests.
18+
TEST(LlvmLibcGmTimeR, EndOf32BitEpochYear) {
19+
// Test for maximum value of a signed 32-bit integer.
20+
// Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
21+
time_t seconds = 0x7FFFFFFF;
22+
struct tm tm_data;
23+
struct tm *tm_data_ptr;
24+
tm_data_ptr = __llvm_libc::gmtime_r(&seconds, &tm_data);
25+
EXPECT_TM_EQ((tm{7, // sec
26+
14, // min
27+
3, // hr
28+
19, // day
29+
0, // tm_mon starts with 0 for Jan
30+
2038 - TimeConstants::TimeYearBase, // year
31+
2, // wday
32+
7, // yday
33+
0}),
34+
*tm_data_ptr);
35+
EXPECT_TM_EQ(*tm_data_ptr, tm_data);
36+
}
37+
38+
TEST(LlvmLibcGmTimeR, Max64BitYear) {
39+
if (sizeof(time_t) == 4)
40+
return;
41+
// Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
42+
time_t seconds = 67767976202043050;
43+
struct tm tm_data;
44+
struct tm *tm_data_ptr;
45+
tm_data_ptr = __llvm_libc::gmtime_r(&seconds, &tm_data);
46+
EXPECT_TM_EQ((tm{50, // sec
47+
50, // min
48+
12, // hr
49+
1, // day
50+
0, // tm_mon starts with 0 for Jan
51+
2147483647 - TimeConstants::TimeYearBase, // year
52+
2, // wday
53+
50, // yday
54+
0}),
55+
*tm_data_ptr);
56+
EXPECT_TM_EQ(*tm_data_ptr, tm_data);
57+
}

0 commit comments

Comments
 (0)