diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -425,6 +425,7 @@ libc.src.time.clock_gettime libc.src.time.clock libc.src.time.difftime + libc.src.time.gettimeofday libc.src.time.gmtime libc.src.time.gmtime_r libc.src.time.mktime diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -173,7 +173,14 @@ } def TimeAPI : PublicAPI<"time.h"> { - let Types = ["clock_t", "time_t", "struct tm", "struct timespec", "clockid_t",]; + let Types = [ + "clock_t", + "time_t", + "struct tm", + "struct timespec", + "struct timeval", + "clockid_t", + ]; } def ErrnoAPI : PublicAPI<"errno.h"> { @@ -287,7 +294,8 @@ def SysStatAPI : PublicAPI<"sys/stat.h"> { let Types = ["mode_t", "dev_t", "ino_t", "nlink_t", "uid_t", "gid_t", "off_t", - "struct timespec", "blksize_t", "blkcnt_t", "struct stat"]; + "struct timespec", "struct timeval", "blksize_t", "blkcnt_t", + "struct stat"]; } def SysWaitAPI : PublicAPI<"sys/wait.h"> { 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 @@ -459,6 +459,7 @@ libc.src.time.clock_gettime libc.src.time.clock libc.src.time.difftime + libc.src.time.gettimeofday libc.src.time.gmtime libc.src.time.gmtime_r libc.src.time.mktime diff --git a/libc/docs/date_and_time.rst b/libc/docs/date_and_time.rst --- a/libc/docs/date_and_time.rst +++ b/libc/docs/date_and_time.rst @@ -42,6 +42,7 @@ ctime_r difftime |check| getdate +gettimeofday |check| gmtime |check| gmtime_r |check| localtime diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -106,6 +106,7 @@ .llvm-libc-types.clockid_t .llvm-libc-types.struct_tm .llvm-libc-types.struct_timespec + .llvm-libc-types.struct_timeval ) add_gen_header( diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -45,6 +45,9 @@ def StructTimeSpec : NamedType<"struct timespec">; def StructTimeSpecPtr : PtrType; +def StructTimeVal : NamedType<"struct timeval">; +def StructTimeValPtr : PtrType; + def ExecArgvT : NamedType<"__exec_argv_t">; def ExecEnvpT : NamedType<"__exec_envp_t">; @@ -723,7 +726,20 @@ HeaderSpec SysStat = HeaderSpec< "sys/stat.h", [], // Macros - [ModeTType, DevT, InoT, UidT, GidT, StructTimeSpec, BlkSizeT, BlkCntT, OffTType, NLinkT, StatType], // Types + [ + ModeTType, + DevT, + InoT, + UidT, + GidT, + StructTimeSpec, + StructTimeVal, + BlkSizeT, + BlkCntT, + OffTType, + NLinkT, + StatType, + ], // Types [], // Enumerations [ FunctionSpec< @@ -1061,21 +1077,26 @@ HeaderSpec Time = HeaderSpec< "time.h", [], // Macros - [ClockIdT, StructTimeSpec], // Types + [ClockIdT, StructTimeSpec, StructTimeVal], // Types [], // Enumerations [ FunctionSpec< - "nanosleep", + "clock_gettime", RetValSpec, - [ - ArgSpec, - ArgSpec, - ] + [ArgSpec, ArgSpec] >, FunctionSpec< - "clock_gettime", + "gettimeofday", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< + "nanosleep", RetValSpec, - [ArgSpec,ArgSpec] + [ + 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 @@ -59,6 +59,21 @@ libc.include.time ) +add_entrypoint_object( + gettimeofday + SRCS + gettimeofday.cpp + HDRS + gettimeofday.h + DEPENDS + .clock_gettime + libc.include.errno + 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/gettimeofday.h b/libc/src/time/gettimeofday.h new file mode 100644 --- /dev/null +++ b/libc/src/time/gettimeofday.h @@ -0,0 +1,22 @@ +//===-- Implementation header of gettimeofday -------------------*- 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_GETTIMEOFDAY_H +#define LLVM_LIBC_SRC_TIME_GETTIMEOFDAY_H + +#include + +namespace __llvm_libc { + +int gettimeofday(struct timeval *tv, void *tz); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_TIME_GETTIMEOFDAY_H + +#include "include/time.h" diff --git a/libc/src/time/gettimeofday.cpp b/libc/src/time/gettimeofday.cpp new file mode 100644 --- /dev/null +++ b/libc/src/time/gettimeofday.cpp @@ -0,0 +1,34 @@ +//===-- Implementation of gettimeofday 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/gettimeofday.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/time/clock_gettime.h" + +#include +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, gettimeofday, + (struct timeval * tv, [[maybe_unused]] void *unused)) { + if (tv == nullptr) + return 0; + clockid_t clockid = CLOCK_REALTIME; + struct timespec tp; + long ret_val = __llvm_libc::clock_gettime(clockid, &tp); + if (ret_val < 0) + return -1; + tv->tv_sec = tp.tv_sec; + tv->tv_usec = tp.tv_nsec / 1000; + 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 @@ -50,6 +50,24 @@ libc.src.time.difftime ) +add_libc_unittest( + gettimeofday + SUITE + libc_time_unittests + SRCS + gettimeofday_test.cpp + HDRS + TmHelper.h + TmMatcher.h + CXX_STANDARD + 20 + DEPENDS + libc.include.errno + libc.include.time + libc.src.time.gettimeofday + libc.src.time.nanosleep +) + add_libc_unittest( gmtime SUITE diff --git a/libc/test/src/time/gettimeofday_test.cpp b/libc/test/src/time/gettimeofday_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/time/gettimeofday_test.cpp @@ -0,0 +1,38 @@ +//===-- Unittests for gettimeofday ----------------------------------------===// +// +// 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 +#include + +#include "src/time/gettimeofday.h" +#include "src/time/nanosleep.h" +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" + +namespace cpp = __llvm_libc::cpp; + +TEST(LlvmLibcGettimeofday, SmokeTest) { + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + void *tz = nullptr; + struct timeval tv; + int ret = __llvm_libc::gettimeofday(&tv, tz); + ASSERT_EQ(ret, 0); + + // Sleep for 200 microsceconds. + struct timespec tim = {0, 200 * 1000}; + struct timespec tim2 = {0, 0}; + ret = __llvm_libc::nanosleep(&tim, &tim2); + + // Call gettimeofday again and verify that it is more 100 microscecods and + // less than 300 microseconds, + struct timeval tv1; + ret = __llvm_libc::gettimeofday(&tv1, tz); + ASSERT_EQ(ret, 0); + ASSERT_GT(tv1.tv_usec - tv.tv_usec, 100); + ASSERT_LT(tv1.tv_usec - tv.tv_usec, 300); +}