[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.
This commit is contained in:
parent
0c98776159
commit
b8daa45a56
@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
libc.src.time.gmtime
|
||||
libc.src.time.gmtime_r
|
||||
libc.src.time.mktime
|
||||
libc.src.time.timespec_get
|
||||
|
||||
# internal entrypoints
|
||||
libc.startup.baremetal.init
|
||||
|
@ -205,6 +205,7 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
libc.src.time.gmtime
|
||||
libc.src.time.gmtime_r
|
||||
libc.src.time.mktime
|
||||
libc.src.time.timespec_get
|
||||
|
||||
# internal entrypoints
|
||||
libc.startup.baremetal.init
|
||||
|
@ -1000,6 +1000,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||
libc.src.time.mktime
|
||||
libc.src.time.nanosleep
|
||||
libc.src.time.time
|
||||
libc.src.time.timespec_get
|
||||
|
||||
# unistd.h entrypoints
|
||||
libc.src.unistd.__llvm_libc_syscall
|
||||
|
@ -939,6 +939,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||
libc.src.time.mktime
|
||||
libc.src.time.nanosleep
|
||||
libc.src.time.time
|
||||
libc.src.time.timespec_get
|
||||
|
||||
# unistd.h entrypoints
|
||||
libc.src.unistd.__llvm_libc_syscall
|
||||
|
@ -1083,6 +1083,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||
libc.src.time.mktime
|
||||
libc.src.time.nanosleep
|
||||
libc.src.time.time
|
||||
libc.src.time.timespec_get
|
||||
|
||||
# locale.h entrypoints
|
||||
libc.src.locale.localeconv
|
||||
|
@ -7,4 +7,9 @@
|
||||
#include "linux/time-macros.h"
|
||||
#endif
|
||||
|
||||
#define TIME_UTC 1
|
||||
#define TIME_MONOTONIC 2
|
||||
#define TIME_ACTIVE 3
|
||||
#define TIME_THREAD_ACTIVE 4
|
||||
|
||||
#endif // LLVM_LIBC_MACROS_TIME_MACROS_H
|
||||
|
@ -96,3 +96,10 @@ functions:
|
||||
return_type: time_t
|
||||
arguments:
|
||||
- type: time_t *
|
||||
- name: timespec_get
|
||||
standard:
|
||||
- stdc
|
||||
return_type: int
|
||||
arguments:
|
||||
- type: struct timespec *
|
||||
- type: int
|
||||
|
@ -1676,6 +1676,14 @@ def StdC : StandardSpec<"stdc"> {
|
||||
RetValSpec<TimeTType>,
|
||||
[ArgSpec<TimeTTypePtr>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"timespec_get",
|
||||
RetValSpec<IntType>,
|
||||
[
|
||||
ArgSpec<StructTimeSpecPtr>,
|
||||
ArgSpec<IntType>,
|
||||
]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
|
@ -111,6 +111,13 @@ add_entrypoint_object(
|
||||
.${LIBC_TARGET_OS}.time
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
timespec_get
|
||||
ALIAS
|
||||
DEPENDS
|
||||
.${LIBC_TARGET_OS}.timespec_get
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
clock
|
||||
ALIAS
|
||||
|
10
libc/src/time/baremetal/CMakeLists.txt
Normal file
10
libc/src/time/baremetal/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
add_entrypoint_object(
|
||||
timespec_get
|
||||
SRCS
|
||||
timespec_get.cpp
|
||||
HDRS
|
||||
../timespec_get.h
|
||||
DEPENDS
|
||||
libc.hdr.time_macros
|
||||
libc.hdr.types.struct_timespec
|
||||
)
|
27
libc/src/time/baremetal/timespec_get.cpp
Normal file
27
libc/src/time/baremetal/timespec_get.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
//===-- Implementation of timespec_get for baremetal ----------------------===//
|
||||
//
|
||||
// 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/timespec_get.h"
|
||||
#include "hdr/time_macros.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
extern "C" bool __llvm_libc_timespec_get_utc(struct timespec *ts);
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
|
||||
if (base != TIME_UTC)
|
||||
return 0;
|
||||
|
||||
if (!__llvm_libc_timespec_get_utc(ts))
|
||||
return 0;
|
||||
return base;
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
@ -44,3 +44,15 @@ add_entrypoint_object(
|
||||
libc.hdr.types.struct_timespec
|
||||
.time_utils
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
timespec_get
|
||||
SRCS
|
||||
timespec_get.cpp
|
||||
HDRS
|
||||
../timespec_get.h
|
||||
DEPENDS
|
||||
libc.hdr.time_macros
|
||||
libc.hdr.types.struct_timespec
|
||||
.time_utils
|
||||
)
|
||||
|
29
libc/src/time/gpu/timespec_get.cpp
Normal file
29
libc/src/time/gpu/timespec_get.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
//===-- Implementation of timespec_get for gpu ----------------------------===//
|
||||
//
|
||||
// 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/timespec_get.h"
|
||||
#include "hdr/time_macros.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
|
||||
if (base != TIME_MONOTONIC || !ts)
|
||||
return 0;
|
||||
|
||||
uint64_t ns_per_tick = TICKS_PER_SEC / GPU_CLOCKS_PER_SEC;
|
||||
uint64_t ticks = gpu::fixed_frequency_clock();
|
||||
|
||||
ts->tv_nsec = (ticks * ns_per_tick) % TICKS_PER_SEC;
|
||||
ts->tv_sec = (ticks * ns_per_tick) / TICKS_PER_SEC;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
@ -11,6 +11,19 @@ add_entrypoint_object(
|
||||
libc.src.errno.errno
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
timespec_get
|
||||
SRCS
|
||||
timespec_get.cpp
|
||||
HDRS
|
||||
../timespec_get.h
|
||||
DEPENDS
|
||||
libc.hdr.time_macros
|
||||
libc.hdr.types.struct_timespec
|
||||
libc.src.__support.time.linux.clock_gettime
|
||||
libc.src.errno.errno
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
clock
|
||||
SRCS
|
||||
|
45
libc/src/time/linux/timespec_get.cpp
Normal file
45
libc/src/time/linux/timespec_get.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
//===-- Implementation of timespec_get for Linux --------------------------===//
|
||||
//
|
||||
// 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/timespec_get.h"
|
||||
#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/errno/libc_errno.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
|
||||
clockid_t clockid;
|
||||
switch (base) {
|
||||
case TIME_UTC:
|
||||
clockid = CLOCK_REALTIME;
|
||||
break;
|
||||
case TIME_MONOTONIC:
|
||||
clockid = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case TIME_ACTIVE:
|
||||
clockid = CLOCK_PROCESS_CPUTIME_ID;
|
||||
break;
|
||||
case TIME_THREAD_ACTIVE:
|
||||
clockid = CLOCK_THREAD_CPUTIME_ID;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto result = internal::clock_gettime(clockid, ts);
|
||||
if (!result.has_value()) {
|
||||
libc_errno = result.error();
|
||||
return 0;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
21
libc/src/time/timespec_get.h
Normal file
21
libc/src/time/timespec_get.h
Normal file
@ -0,0 +1,21 @@
|
||||
//===-- Implementation header of timespec_get -------------------*- 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_TIMESPEC_GET_H
|
||||
#define LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
|
||||
|
||||
#include "hdr/types/struct_timespec.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
int timespec_get(struct timespec *ts, int base);
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
|
@ -162,6 +162,16 @@ add_libc_unittest(
|
||||
libc.src.errno.errno
|
||||
)
|
||||
|
||||
add_libc_test(
|
||||
timespec_get_test
|
||||
SUITE
|
||||
libc_time_unittests
|
||||
SRCS
|
||||
timespec_get_test.cpp
|
||||
DEPENDS
|
||||
libc.src.time.timespec_get
|
||||
)
|
||||
|
||||
add_libc_test(
|
||||
clock_test
|
||||
SUITE
|
||||
|
46
libc/test/src/time/timespec_get_test.cpp
Normal file
46
libc/test/src/time/timespec_get_test.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
//===-- Unittests for timespec_get ----------------------------------------===//
|
||||
//
|
||||
// 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 "hdr/time_macros.h"
|
||||
#include "hdr/types/struct_timespec.h"
|
||||
#include "src/__support/macros/properties/architectures.h"
|
||||
#include "src/time/timespec_get.h"
|
||||
#include "test/UnitTest/Test.h"
|
||||
|
||||
TEST(LlvmLibcTimespecGet, Utc) {
|
||||
timespec ts;
|
||||
int result;
|
||||
result = LIBC_NAMESPACE::timespec_get(&ts, TIME_UTC);
|
||||
#ifdef LIBC_TARGET_ARCH_IS_GPU
|
||||
ASSERT_EQ(result, 0);
|
||||
#else
|
||||
ASSERT_EQ(result, TIME_UTC);
|
||||
ASSERT_GT(ts.tv_sec, time_t(0));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(LlvmLibcTimespecGet, Monotonic) {
|
||||
timespec ts1, ts2;
|
||||
int result;
|
||||
result = LIBC_NAMESPACE::timespec_get(&ts1, TIME_MONOTONIC);
|
||||
ASSERT_EQ(result, TIME_MONOTONIC);
|
||||
ASSERT_GT(ts1.tv_sec, time_t(0));
|
||||
result = LIBC_NAMESPACE::timespec_get(&ts2, TIME_MONOTONIC);
|
||||
ASSERT_EQ(result, TIME_MONOTONIC);
|
||||
ASSERT_GE(ts2.tv_sec, ts1.tv_sec); // The monotonic time should increase.
|
||||
if (ts2.tv_sec == ts1.tv_sec) {
|
||||
ASSERT_GE(ts2.tv_nsec, ts1.tv_nsec);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LlvmLibcTimespecGet, Unknown) {
|
||||
timespec ts;
|
||||
int result;
|
||||
result = LIBC_NAMESPACE::timespec_get(&ts, 0);
|
||||
ASSERT_EQ(result, 0);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user