diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -394,6 +394,7 @@ libc.src.time.gmtime_r libc.src.time.mktime libc.src.time.nanosleep + libc.src.time.clock_gettime ) endif() diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -91,6 +91,7 @@ GEN_HDR time.h DEPENDS .llvm_libc_common_h + .llvm-libc-macros.time_macros .llvm-libc-types.time_t .llvm-libc-types.struct_tm .llvm-libc-types.struct_timespec diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -38,6 +38,14 @@ .linux.sys_resource_macros ) +add_header( + time_macros + HDR + time-macros.h + DEPENDS + .linux.time_macros +) + add_header( unistd_macros HDR diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt --- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt @@ -16,6 +16,12 @@ sys-stat-macros.h ) +add_header( + time_macros + HDR + time-macros.h +) + add_header( sys_resource_macros HDR diff --git a/libc/include/llvm-libc-macros/linux/time-macros.h b/libc/include/llvm-libc-macros/linux/time-macros.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-macros/linux/time-macros.h @@ -0,0 +1,24 @@ +//===-- Definition of macros from time.h ---------------------------------===// +// +// 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_MACROS_LINUX_TIME_MACROS_H +#define __LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H + +// clock type macros +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 +#define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 + +#endif //__LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H diff --git a/libc/include/llvm-libc-macros/time-macros.h b/libc/include/llvm-libc-macros/time-macros.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-macros/time-macros.h @@ -0,0 +1,8 @@ +#ifndef __LLVM_LIBC_MACROS_TIME_MACROS_H +#define __LLVM_LIBC_MACROS_TIME_MACROS_H + +#ifdef __unix__ +#include "linux/time-macros.h" +#endif + +#endif // __LLVM_LIBC_MACROS_TIME_MACROS_H diff --git a/libc/include/llvm-libc-types/time_t.h b/libc/include/llvm-libc-types/time_t.h --- a/libc/include/llvm-libc-types/time_t.h +++ b/libc/include/llvm-libc-types/time_t.h @@ -11,4 +11,6 @@ typedef __INTPTR_TYPE__ time_t; +typedef int clockid_t; + #endif // __LLVM_LIBC_TYPES_TIME_T_H__ diff --git a/libc/include/time.h.def b/libc/include/time.h.def --- a/libc/include/time.h.def +++ b/libc/include/time.h.def @@ -10,6 +10,7 @@ #define LLVM_LIBC_TIME_H #include <__llvm-libc-common.h> +#include %%public_api() diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -19,10 +19,10 @@ def UidT : NamedType<"uid_t">; def GidT : NamedType<"gid_t">; def DevT : NamedType<"dev_t">; +def ClockIdT : NamedType<"clockid_t">; def BlkSizeT : NamedType<"blksize_t">; def BlkCntT : NamedType<"blkcnt_t">; def NLinkT : NamedType<"nlink_t">; -def TimeSpec : NamedType<"struct timespec">; def PidT : NamedType<"pid_t">; def StatType : NamedType<"struct stat">; @@ -605,7 +605,7 @@ HeaderSpec SysStat = HeaderSpec< "sys/stat.h", [], // Macros - [ModeTType, DevT, InoT, UidT, GidT, TimeSpec, BlkSizeT, BlkCntT, OffTType, NLinkT, StatType], // Types + [ModeTType, DevT, InoT, UidT, GidT, StructTimeSpec, BlkSizeT, BlkCntT, OffTType, NLinkT, StatType], // Types [], // Enumerations [ FunctionSpec< @@ -925,7 +925,7 @@ HeaderSpec Time = HeaderSpec< "time.h", [], // Macros - [StructTimeSpec], // Types + [ClockIdT, StructTimeSpec], // Types [], // Enumerations [ FunctionSpec< @@ -936,6 +936,11 @@ ArgSpec, ] >, + FunctionSpec< + "clock_gettime", + RetValSpec, + [ArgSpec,ArgSpec] + >, ] >; diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt --- a/libc/src/time/CMakeLists.txt +++ b/libc/src/time/CMakeLists.txt @@ -32,6 +32,19 @@ libc.include.time ) +add_entrypoint_object( + clock_gettime + SRCS + clock_gettime.cpp + HDRS + clock_gettime.h + DEPENDS + libc.include.time + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + add_entrypoint_object( gmtime SRCS diff --git a/libc/src/time/clock_gettime.h b/libc/src/time/clock_gettime.h new file mode 100644 --- /dev/null +++ b/libc/src/time/clock_gettime.h @@ -0,0 +1,20 @@ +//===-- Implementation header for clock_gettime function --------*- 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_GETTIME_H +#define LLVM_LIBC_SRC_TIME_CLOCK_GETTIME_H + +#include + +namespace __llvm_libc { + +int clock_gettime(clockid_t clockid, struct timespec *tp); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_TIME_CLOCK_GETTIME_H diff --git a/libc/src/time/clock_gettime.cpp b/libc/src/time/clock_gettime.cpp new file mode 100644 --- /dev/null +++ b/libc/src/time/clock_gettime.cpp @@ -0,0 +1,37 @@ +//===---------- Linux implementation of the POSIX clock_gettime 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_gettime.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include +#include // For syscall numbers. +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, clock_gettime, + (clockid_t clockid, struct timespec *tp)) { + long ret_val = + __llvm_libc::syscall(SYS_clock_gettime, static_cast(clockid), + reinterpret_cast(tp)); + long a = CLOCK_REALTIME; + // A negative return value indicates an error with the magnitude of the + // value being the error code. + if (ret_val < 0) { + errno = -ret_val; + return -1; + } + + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt --- a/libc/test/src/time/CMakeLists.txt +++ b/libc/test/src/time/CMakeLists.txt @@ -30,6 +30,16 @@ libc.src.time.asctime_r ) +add_libc_unittest( + clock_gettime + SUITE + libc_time_unittests + SRCS + clock_gettime_test.cpp + DEPENDS + libc.src.time.clock_gettime +) + add_libc_unittest( gmtime SUITE diff --git a/libc/test/src/time/clock_gettime_test.cpp b/libc/test/src/time/clock_gettime_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/time/clock_gettime_test.cpp @@ -0,0 +1,36 @@ +//===-- Unittests for clock_gettime ---------------------------------------===// +// +// 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_gettime.h" +#include "utils/UnitTest/Test.h" + +#include + +TEST(LlvmLibcClockGetTime, RealTime) { + struct timespec tp; + int result; + result = clock_gettime(CLOCK_REALTIME, &tp); + ASSERT_EQ(result, 0); + ASSERT_GT(tp.tv_sec, time_t(0)); +} + +#ifdef CLOCK_MONOTONIC +TEST(LlvmLibcClockGetTime, MonotonicTime) { + struct timespec tp1, tp2; + int result; + result = clock_gettime(CLOCK_MONOTONIC, &tp1); + ASSERT_EQ(result, 0); + ASSERT_GT(tp1.tv_sec, time_t(0)); + result = clock_gettime(CLOCK_MONOTONIC, &tp2); + ASSERT_EQ(result, 0); + ASSERT_GE(tp2.tv_sec, tp1.tv_sec); // The monotonic clock should increase. + if (tp2.tv_sec == tp1.tv_sec) { + ASSERT_GE(tp2.tv_nsec, tp1.tv_nsec); + } +} +#endif // CLOCK_MONOTONIC