[libc] Add Linux implementations of time and clock functions.

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D136666
This commit is contained in:
Siva Chandra Reddy
2022-10-25 06:45:45 +00:00
parent 20204db503
commit 22ea0e5d9b
16 changed files with 276 additions and 4 deletions

View File

@@ -172,7 +172,7 @@ def StdlibAPI : PublicAPI<"stdlib.h"> {
}
def TimeAPI : PublicAPI<"time.h"> {
let Types = ["time_t", "struct tm", "struct timespec", "clockid_t",];
let Types = ["clock_t", "time_t", "struct tm", "struct timespec", "clockid_t",];
}
def ErrnoAPI : PublicAPI<"errno.h"> {

View File

@@ -443,12 +443,14 @@ if(LLVM_LIBC_FULL_BUILD)
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
libc.src.time.clock_gettime
libc.src.time.clock
libc.src.time.difftime
libc.src.time.gmtime
libc.src.time.gmtime_r
libc.src.time.mktime
libc.src.time.nanosleep
libc.src.time.clock_gettime
libc.src.time.time
# unistd.h entrypoints
libc.src.unistd.environ

View File

@@ -93,6 +93,7 @@ add_gen_header(
.llvm_libc_common_h
.llvm-libc-macros.time_macros
.llvm-libc-types.time_t
.llvm-libc-types.clock_t
.llvm-libc-types.clockid_t
.llvm-libc-types.struct_tm
.llvm-libc-types.struct_timespec

View File

@@ -21,4 +21,6 @@
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9
#define CLOCKS_PER_SEC 1000000
#endif //__LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H

View File

@@ -16,6 +16,7 @@ add_header(__thread_type HDR __thread_type.h)
add_header(blkcnt_t HDR blkcnt_t.h)
add_header(blksize_t HDR blksize_t.h)
add_header(cc_t HDR cc_t.h)
add_header(clock_t HDR clock_t.h)
add_header(clockid_t HDR clockid_t.h)
add_header(cnd_t HDR cnd_t.h)
add_header(cookie_io_functions_t HDR cookie_io_functions_t.h DEPENDS .off64_t)

View File

@@ -0,0 +1,14 @@
//===-- Definition of clock_t type ----------------------------------------===//
//
// 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_TYPES_CLOCK_T_H__
#define __LLVM_LIBC_TYPES_CLOCK_T_H__
typedef long clock_t;
#endif // __LLVM_LIBC_TYPES_CLOCK_T_H__

View File

@@ -3,6 +3,7 @@ def StdC : StandardSpec<"stdc"> {
NamedType StructTmType = NamedType<"struct tm">;
PtrType StructTmPtr = PtrType<StructTmType>;
PtrType TimeTTypePtr = PtrType<TimeTType>;
NamedType ClockT = NamedType<"clock_t">;
NamedType DivTType = NamedType<"div_t">;
NamedType LDivTType = NamedType<"ldiv_t">;
@@ -917,8 +918,9 @@ def StdC : StandardSpec<"stdc"> {
"time.h",
[], // Macros
[ // Types
StructTmType,
TimeTType,
ClockT,
StructTmType,
TimeTType,
],
[], // Enumerations
[
@@ -935,6 +937,11 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<CharPtr>,
]
>,
FunctionSpec<
"clock",
RetValSpec<ClockT>,
[ArgSpec<VoidType>]
>,
FunctionSpec<
"difftime",
RetValSpec<DoubleType>,
@@ -961,6 +968,11 @@ def StdC : StandardSpec<"stdc"> {
RetValSpec<TimeTType>,
[ArgSpec<StructTmPtr>]
>,
FunctionSpec<
"time",
RetValSpec<TimeTType>,
[ArgSpec<TimeTTypePtr>]
>,
]
>;

View File

@@ -1,3 +1,7 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
add_object_library(
time_utils
SRCS
@@ -103,3 +107,17 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
add_entrypoint_object(
time
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.time
)
add_entrypoint_object(
clock
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.clock
)

20
libc/src/time/clock.h Normal file
View File

@@ -0,0 +1,20 @@
//===-- Implementation header of clock --------------------------*- 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_CLOCK_H
#define LLVM_LIBC_SRC_TIME_CLOCK_H
#include <time.h>
namespace __llvm_libc {
clock_t clock();
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_TIME_CLOCK_H

View File

@@ -0,0 +1,26 @@
add_entrypoint_object(
time
SRCS
time.cpp
HDRS
../time_func.h
DEPENDS
libc.include.time
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
add_entrypoint_object(
clock
SRCS
clock.cpp
HDRS
../clock.h
DEPENDS
libc.include.time
libc.include.sys_syscall
libc.src.__support.CPP.limits
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)

View File

@@ -0,0 +1,49 @@
//===-- Linux implementation of the clock 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/clock.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
#include <time.h>
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(clock_t, clock, ()) {
struct timespec ts;
long ret_val = __llvm_libc::syscall_impl(
SYS_clock_gettime, CLOCK_PROCESS_CPUTIME_ID, reinterpret_cast<long>(&ts));
if (ret_val < 0) {
errno = -ret_val;
return clock_t(-1);
}
// The above syscall gets the CPU time in seconds plus nanoseconds. We should
// make sure that corresponding clocks can actually be represented by clock-t.
// The standard requires that we return clock_t(-1) if we cannot represent
// clocks as a clock_t value.
constexpr clock_t CLOCK_SECS_MAX =
cpp::numeric_limits<clock_t>::max() / CLOCKS_PER_SEC;
if (ts.tv_sec > CLOCK_SECS_MAX)
return clock_t(-1);
if (ts.tv_nsec / 1000000000 > CLOCK_SECS_MAX - ts.tv_sec)
return clock_t(-1);
// For the integer computation converting tv_nsec to clocks to work
// correctly, we want CLOCKS_PER_SEC to be less than 1000000000.
static_assert(1000000000 > CLOCKS_PER_SEC,
"Expected CLOCKS_PER_SEC to be less than 1000000000.");
return clock_t(ts.tv_sec * CLOCKS_PER_SEC +
ts.tv_nsec / (1000000000 / CLOCKS_PER_SEC));
}
} // namespace __llvm_libc

View File

@@ -0,0 +1,35 @@
//===-- Linux implementation of the time 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/time_func.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
#include <time.h>
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) {
// TODO: Use the Linux VDSO to fetch the time and avoid the syscall.
struct timespec ts;
long ret_val = __llvm_libc::syscall_impl(SYS_clock_gettime, CLOCK_REALTIME,
reinterpret_cast<long>(&ts));
if (ret_val < 0) {
errno = -ret_val;
return -1;
}
if (tp != nullptr)
*tp = time_t(ts.tv_sec);
return time_t(ts.tv_sec);
}
} // namespace __llvm_libc

22
libc/src/time/time_func.h Normal file
View File

@@ -0,0 +1,22 @@
//===-- Implementation header of time ---------------------------*- 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_TIME_FUNC_H
#define LLVM_LIBC_SRC_TIME_TIME_FUNC_H
#include <time.h>
// Note this header file is named time_func.h to avoid conflicts with the
// public header file time.h.
namespace __llvm_libc {
time_t time(time_t *tp);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_TIME_TIME_FUNC_H

View File

@@ -105,3 +105,27 @@ add_libc_unittest(
libc.include.time
libc.src.time.nanosleep
)
add_libc_unittest(
time_test
SUITE
libc_time_unittests
SRCS
time_test.cpp
DEPENDS
libc.include.errno
libc.include.time
libc.src.time.time
)
add_libc_unittest(
clock_test
SUITE
libc_time_unittests
SRCS
clock_test.cpp
DEPENDS
libc.include.errno
libc.include.time
libc.src.time.clock
)

View File

@@ -0,0 +1,22 @@
//===-- Unittests for clock -----------------------------------------------===//
//
// 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/clock.h"
#include "utils/UnitTest/Test.h"
#include <errno.h>
#include <limits.h>
#include <time.h>
TEST(LlvmLibcClockTest, SmokeTest) {
clock_t c1 = __llvm_libc::clock();
ASSERT_GT(c1, clock_t(0));
clock_t c2 = __llvm_libc::clock();
ASSERT_GE(c2, c1);
}

View File

@@ -0,0 +1,24 @@
//===-- Unittests for time ------------------------------------------------===//
//
// 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/time_func.h"
#include "utils/UnitTest/Test.h"
#include <errno.h>
#include <limits.h>
#include <time.h>
TEST(LlvmLibcTimeTest, SmokeTest) {
time_t t1;
time_t t2 = __llvm_libc::time(&t1);
ASSERT_EQ(t1, t2);
ASSERT_GT(t1, time_t(0));
time_t t3 = __llvm_libc::time(nullptr);
ASSERT_GE(t3, t1);
}