From 8f1e362ee9275a687693448bd975194ee9b984f2 Mon Sep 17 00:00:00 2001 From: Raman Tenneti Date: Sat, 24 Sep 2022 00:13:23 +0000 Subject: [PATCH] Implement nanosleep per https://pubs.opengroup.org/onlinepubs/009695399/basedefs/time.h.html Tested: Limited unit test: This makes a call and checks that no error was returned, but we currently don't have the ability to ensure that time has elapsed as expected. Co-authored-by: Jeff Bailey Reviewed By: sivachandra, jeffbailey Differential Revision: https://reviews.llvm.org/D134095 --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/api.td | 2 +- libc/config/linux/x86_64/entrypoints.txt | 1 + libc/include/CMakeLists.txt | 1 + .../include/llvm-libc-types/struct_timespec.h | 5 ++-- libc/spec/posix.td | 21 ++++++++++++++ libc/src/time/CMakeLists.txt | 14 +++++++++ libc/src/time/nanosleep.cpp | 29 +++++++++++++++++++ libc/src/time/nanosleep.h | 23 +++++++++++++++ libc/test/src/time/CMakeLists.txt | 17 +++++++++++ libc/test/src/time/nanosleep_test.cpp | 29 +++++++++++++++++++ 11 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 libc/src/time/nanosleep.cpp create mode 100644 libc/src/time/nanosleep.h create mode 100644 libc/test/src/time/nanosleep_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index b506663a04b6..e05012391bea 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -353,6 +353,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.gmtime libc.src.time.gmtime_r libc.src.time.mktime + libc.src.time.nanosleep ) endif() diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index 508ef3721a64..03559879b353 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -171,7 +171,7 @@ def StdlibAPI : PublicAPI<"stdlib.h"> { } def TimeAPI : PublicAPI<"time.h"> { - let Types = ["time_t", "struct tm"]; + let Types = ["time_t", "struct tm", "struct timespec"]; } def ErrnoAPI : PublicAPI<"errno.h"> { diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index cf8c2c2d7746..2a48c90b967d 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -393,6 +393,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.gmtime libc.src.time.gmtime_r libc.src.time.mktime + libc.src.time.nanosleep ) endif() diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 63eb88247de0..a8aac4cfbd31 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -93,6 +93,7 @@ add_gen_header( .llvm_libc_common_h .llvm-libc-types.time_t .llvm-libc-types.struct_tm + .llvm-libc-types.struct_timespec ) add_gen_header( diff --git a/libc/include/llvm-libc-types/struct_timespec.h b/libc/include/llvm-libc-types/struct_timespec.h index eb6e70bb578a..1fa6272d3df9 100644 --- a/libc/include/llvm-libc-types/struct_timespec.h +++ b/libc/include/llvm-libc-types/struct_timespec.h @@ -12,8 +12,9 @@ #include struct timespec { - time_t tv_sec; - long tv_nsec; + time_t tv_sec; /* Seconds. */ + /* TODO: BIG_ENDIAN may require padding. */ + long tv_nsec; /* Nanoseconds. */ }; #endif // __LLVM_LIBC_TYPES_TIMESPEC_H__ diff --git a/libc/spec/posix.td b/libc/spec/posix.td index 8f8cad426ef5..d93ba16de9fa 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -37,6 +37,9 @@ def StructDirentPtr : PtrType; def StructDirentPtrPtr : PtrType; def ConstStructDirentPtrPtr : ConstType; +def StructTimeSpec : NamedType<"struct timespec">; +def StructTimeSpecPtr : PtrType; + def POSIX : StandardSpec<"POSIX"> { PtrType CharPtr = PtrType; RestrictedPtrType RestrictedCharPtr = RestrictedPtrType; @@ -919,6 +922,23 @@ def POSIX : StandardSpec<"POSIX"> { ] >; + HeaderSpec Time = HeaderSpec< + "time.h", + [], // Macros + [StructTimeSpec], // Types + [], // Enumerations + [ + FunctionSpec< + "nanosleep", + RetValSpec, + [ + ArgSpec, + ArgSpec, + ] + >, + ] + >; + let Headers = [ CType, Dirent, @@ -932,6 +952,7 @@ def POSIX : StandardSpec<"POSIX"> { SysResource, SysStat, SysUtsName, + Time, UniStd, String ]; diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt index 514b36cd852a..880e7ed956ac 100644 --- a/libc/src/time/CMakeLists.txt +++ b/libc/src/time/CMakeLists.txt @@ -66,3 +66,17 @@ add_entrypoint_object( libc.include.time libc.src.errno.errno ) + +add_entrypoint_object( + nanosleep + SRCS + nanosleep.cpp + HDRS + nanosleep.h + DEPENDS + libc.include.errno + libc.include.time + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) diff --git a/libc/src/time/nanosleep.cpp b/libc/src/time/nanosleep.cpp new file mode 100644 index 000000000000..2eb5e97aff09 --- /dev/null +++ b/libc/src/time/nanosleep.cpp @@ -0,0 +1,29 @@ +//===-- Implementation of nanosleep 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/nanosleep.h" +#include "include/sys/syscall.h" // For syscall numbers. +#include "src/__support/OSUtil/syscall.h" // For syscall functions. +#include "src/__support/common.h" + +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, nanosleep, + (const struct timespec *req, struct timespec *rem)) { + int ret = __llvm_libc::syscall(SYS_nanosleep, req, rem); + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; +} + +} // namespace __llvm_libc diff --git a/libc/src/time/nanosleep.h b/libc/src/time/nanosleep.h new file mode 100644 index 000000000000..5177ef0f63ac --- /dev/null +++ b/libc/src/time/nanosleep.h @@ -0,0 +1,23 @@ +//===-- Implementation header of nanosleep -------------------------*- 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_NANOSLEEP_H +#define LLVM_LIBC_SRC_TIME_NANOSLEEP_H + +#include + +namespace __llvm_libc { + +int nanosleep(const struct timespec *req, struct timespec *rem); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_TIME_NANOSLEEP_H + +#include "include/time.h" diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt index 9fe06e3a2297..0fe964ca4333 100644 --- a/libc/test/src/time/CMakeLists.txt +++ b/libc/test/src/time/CMakeLists.txt @@ -68,3 +68,20 @@ add_libc_unittest( DEPENDS libc.src.time.mktime ) + +add_libc_unittest( + nanosleep + SUITE + libc_time_unittests + SRCS + nanosleep_test.cpp + HDRS + TmHelper.h + TmMatcher.h + CXX_STANDARD + 20 + DEPENDS + libc.include.errno + libc.include.time + libc.src.time.nanosleep +) diff --git a/libc/test/src/time/nanosleep_test.cpp b/libc/test/src/time/nanosleep_test.cpp new file mode 100644 index 000000000000..2b2c90710e1a --- /dev/null +++ b/libc/test/src/time/nanosleep_test.cpp @@ -0,0 +1,29 @@ +//===-- Unittests for nanosleep +//---------------------------------------------===// +// +// 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/nanosleep.h" +#include "test/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" + +namespace cpp = __llvm_libc::cpp; + +TEST(LlvmLibcNanosleep, SmokeTest) { + // TODO: When we have the code to read clocks, test that time has passed. + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + errno = 0; + + struct timespec tim = {1, 500}; + struct timespec tim2 = {0, 0}; + int ret = __llvm_libc::nanosleep(&tim, &tim2); + ASSERT_EQ(errno, 0); + ASSERT_EQ(ret, 0); +}