Skip to content

Commit b8daa45

Browse files
authored
[libc] Implement timespec_get (#116102)
`timespec_get` is C standard counterpart to POSIX `clock_gettime`. On Linux we simply use `clock_gettime`. On baremetal we introduce a new external API `__llvm_libc_timespec_get_utc` that should be implemented by the vendor.
1 parent 0c98776 commit b8daa45

File tree

18 files changed

+245
-0
lines changed

18 files changed

+245
-0
lines changed

libc/config/baremetal/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
209209
libc.src.time.gmtime
210210
libc.src.time.gmtime_r
211211
libc.src.time.mktime
212+
libc.src.time.timespec_get
212213

213214
# internal entrypoints
214215
libc.startup.baremetal.init

libc/config/baremetal/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ set(TARGET_LIBC_ENTRYPOINTS
205205
libc.src.time.gmtime
206206
libc.src.time.gmtime_r
207207
libc.src.time.mktime
208+
libc.src.time.timespec_get
208209

209210
# internal entrypoints
210211
libc.startup.baremetal.init

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ if(LLVM_LIBC_FULL_BUILD)
10001000
libc.src.time.mktime
10011001
libc.src.time.nanosleep
10021002
libc.src.time.time
1003+
libc.src.time.timespec_get
10031004

10041005
# unistd.h entrypoints
10051006
libc.src.unistd.__llvm_libc_syscall

libc/config/linux/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,7 @@ if(LLVM_LIBC_FULL_BUILD)
939939
libc.src.time.mktime
940940
libc.src.time.nanosleep
941941
libc.src.time.time
942+
libc.src.time.timespec_get
942943

943944
# unistd.h entrypoints
944945
libc.src.unistd.__llvm_libc_syscall

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,7 @@ if(LLVM_LIBC_FULL_BUILD)
10831083
libc.src.time.mktime
10841084
libc.src.time.nanosleep
10851085
libc.src.time.time
1086+
libc.src.time.timespec_get
10861087

10871088
# locale.h entrypoints
10881089
libc.src.locale.localeconv

libc/include/llvm-libc-macros/time-macros.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@
77
#include "linux/time-macros.h"
88
#endif
99

10+
#define TIME_UTC 1
11+
#define TIME_MONOTONIC 2
12+
#define TIME_ACTIVE 3
13+
#define TIME_THREAD_ACTIVE 4
14+
1015
#endif // LLVM_LIBC_MACROS_TIME_MACROS_H

libc/newhdrgen/yaml/time.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,10 @@ functions:
9696
return_type: time_t
9797
arguments:
9898
- type: time_t *
99+
- name: timespec_get
100+
standard:
101+
- stdc
102+
return_type: int
103+
arguments:
104+
- type: struct timespec *
105+
- type: int

libc/spec/stdc.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,14 @@ def StdC : StandardSpec<"stdc"> {
16761676
RetValSpec<TimeTType>,
16771677
[ArgSpec<TimeTTypePtr>]
16781678
>,
1679+
FunctionSpec<
1680+
"timespec_get",
1681+
RetValSpec<IntType>,
1682+
[
1683+
ArgSpec<StructTimeSpecPtr>,
1684+
ArgSpec<IntType>,
1685+
]
1686+
>,
16791687
]
16801688
>;
16811689

libc/src/time/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ add_entrypoint_object(
111111
.${LIBC_TARGET_OS}.time
112112
)
113113

114+
add_entrypoint_object(
115+
timespec_get
116+
ALIAS
117+
DEPENDS
118+
.${LIBC_TARGET_OS}.timespec_get
119+
)
120+
114121
add_entrypoint_object(
115122
clock
116123
ALIAS
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_entrypoint_object(
2+
timespec_get
3+
SRCS
4+
timespec_get.cpp
5+
HDRS
6+
../timespec_get.h
7+
DEPENDS
8+
libc.hdr.time_macros
9+
libc.hdr.types.struct_timespec
10+
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===-- Implementation of timespec_get for baremetal ----------------------===//
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/timespec_get.h"
10+
#include "hdr/time_macros.h"
11+
#include "src/__support/common.h"
12+
#include "src/__support/macros/config.h"
13+
14+
namespace LIBC_NAMESPACE_DECL {
15+
16+
extern "C" bool __llvm_libc_timespec_get_utc(struct timespec *ts);
17+
18+
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
19+
if (base != TIME_UTC)
20+
return 0;
21+
22+
if (!__llvm_libc_timespec_get_utc(ts))
23+
return 0;
24+
return base;
25+
}
26+
27+
} // namespace LIBC_NAMESPACE_DECL

libc/src/time/gpu/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,15 @@ add_entrypoint_object(
4444
libc.hdr.types.struct_timespec
4545
.time_utils
4646
)
47+
48+
add_entrypoint_object(
49+
timespec_get
50+
SRCS
51+
timespec_get.cpp
52+
HDRS
53+
../timespec_get.h
54+
DEPENDS
55+
libc.hdr.time_macros
56+
libc.hdr.types.struct_timespec
57+
.time_utils
58+
)

libc/src/time/gpu/timespec_get.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===-- Implementation of timespec_get for gpu ----------------------------===//
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/timespec_get.h"
10+
#include "hdr/time_macros.h"
11+
#include "src/__support/common.h"
12+
#include "src/__support/macros/config.h"
13+
14+
namespace LIBC_NAMESPACE_DECL {
15+
16+
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
17+
if (base != TIME_MONOTONIC || !ts)
18+
return 0;
19+
20+
uint64_t ns_per_tick = TICKS_PER_SEC / GPU_CLOCKS_PER_SEC;
21+
uint64_t ticks = gpu::fixed_frequency_clock();
22+
23+
ts->tv_nsec = (ticks * ns_per_tick) % TICKS_PER_SEC;
24+
ts->tv_sec = (ticks * ns_per_tick) / TICKS_PER_SEC;
25+
26+
return base;
27+
}
28+
29+
} // namespace LIBC_NAMESPACE_DECL

libc/src/time/linux/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ add_entrypoint_object(
1111
libc.src.errno.errno
1212
)
1313

14+
add_entrypoint_object(
15+
timespec_get
16+
SRCS
17+
timespec_get.cpp
18+
HDRS
19+
../timespec_get.h
20+
DEPENDS
21+
libc.hdr.time_macros
22+
libc.hdr.types.struct_timespec
23+
libc.src.__support.time.linux.clock_gettime
24+
libc.src.errno.errno
25+
)
26+
1427
add_entrypoint_object(
1528
clock
1629
SRCS

libc/src/time/linux/timespec_get.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===-- Implementation of timespec_get for Linux --------------------------===//
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/timespec_get.h"
10+
#include "hdr/time_macros.h"
11+
#include "src/__support/common.h"
12+
#include "src/__support/macros/config.h"
13+
#include "src/__support/time/linux/clock_gettime.h"
14+
#include "src/errno/libc_errno.h"
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
18+
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
19+
clockid_t clockid;
20+
switch (base) {
21+
case TIME_UTC:
22+
clockid = CLOCK_REALTIME;
23+
break;
24+
case TIME_MONOTONIC:
25+
clockid = CLOCK_MONOTONIC;
26+
break;
27+
case TIME_ACTIVE:
28+
clockid = CLOCK_PROCESS_CPUTIME_ID;
29+
break;
30+
case TIME_THREAD_ACTIVE:
31+
clockid = CLOCK_THREAD_CPUTIME_ID;
32+
break;
33+
default:
34+
return 0;
35+
}
36+
37+
auto result = internal::clock_gettime(clockid, ts);
38+
if (!result.has_value()) {
39+
libc_errno = result.error();
40+
return 0;
41+
}
42+
return base;
43+
}
44+
45+
} // namespace LIBC_NAMESPACE_DECL

libc/src/time/timespec_get.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header of timespec_get -------------------*- 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_TIMESPEC_GET_H
10+
#define LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
11+
12+
#include "hdr/types/struct_timespec.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
int timespec_get(struct timespec *ts, int base);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H

libc/test/src/time/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ add_libc_unittest(
162162
libc.src.errno.errno
163163
)
164164

165+
add_libc_test(
166+
timespec_get_test
167+
SUITE
168+
libc_time_unittests
169+
SRCS
170+
timespec_get_test.cpp
171+
DEPENDS
172+
libc.src.time.timespec_get
173+
)
174+
165175
add_libc_test(
166176
clock_test
167177
SUITE
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===-- Unittests for timespec_get ----------------------------------------===//
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 "hdr/time_macros.h"
10+
#include "hdr/types/struct_timespec.h"
11+
#include "src/__support/macros/properties/architectures.h"
12+
#include "src/time/timespec_get.h"
13+
#include "test/UnitTest/Test.h"
14+
15+
TEST(LlvmLibcTimespecGet, Utc) {
16+
timespec ts;
17+
int result;
18+
result = LIBC_NAMESPACE::timespec_get(&ts, TIME_UTC);
19+
#ifdef LIBC_TARGET_ARCH_IS_GPU
20+
ASSERT_EQ(result, 0);
21+
#else
22+
ASSERT_EQ(result, TIME_UTC);
23+
ASSERT_GT(ts.tv_sec, time_t(0));
24+
#endif
25+
}
26+
27+
TEST(LlvmLibcTimespecGet, Monotonic) {
28+
timespec ts1, ts2;
29+
int result;
30+
result = LIBC_NAMESPACE::timespec_get(&ts1, TIME_MONOTONIC);
31+
ASSERT_EQ(result, TIME_MONOTONIC);
32+
ASSERT_GT(ts1.tv_sec, time_t(0));
33+
result = LIBC_NAMESPACE::timespec_get(&ts2, TIME_MONOTONIC);
34+
ASSERT_EQ(result, TIME_MONOTONIC);
35+
ASSERT_GE(ts2.tv_sec, ts1.tv_sec); // The monotonic time should increase.
36+
if (ts2.tv_sec == ts1.tv_sec) {
37+
ASSERT_GE(ts2.tv_nsec, ts1.tv_nsec);
38+
}
39+
}
40+
41+
TEST(LlvmLibcTimespecGet, Unknown) {
42+
timespec ts;
43+
int result;
44+
result = LIBC_NAMESPACE::timespec_get(&ts, 0);
45+
ASSERT_EQ(result, 0);
46+
}

0 commit comments

Comments
 (0)