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 @@ -353,6 +353,7 @@ 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 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -171,7 +171,7 @@ } 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 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -393,6 +393,7 @@ 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 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -93,6 +93,7 @@ .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 --- 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 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -37,6 +37,9 @@ 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 @@ ] >; + HeaderSpec Time = HeaderSpec< + "time.h", + [], // Macros + [StructTimeSpec], // Types + [], // Enumerations + [ + FunctionSpec< + "nanosleep", + RetValSpec, + [ + ArgSpec, + ArgSpec, + ] + >, + ] + >; + let Headers = [ CType, Dirent, @@ -932,6 +952,7 @@ SysResource, SysStat, SysUtsName, + Time, UniStd, String ]; 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 @@ -66,3 +66,17 @@ 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.h b/libc/src/time/nanosleep.h new file mode 100644 --- /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/src/time/nanosleep.cpp b/libc/src/time/nanosleep.cpp new file mode 100644 --- /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/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 @@ -68,3 +68,20 @@ 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 --- /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); +}