diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index ff346b783739b..be5f5a66016b5 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -363,6 +363,10 @@ set(TARGET_LIBC_ENTRYPOINTS # sys/uio.h entrypoints libc.src.sys.uio.writev libc.src.sys.uio.readv + + # sys/time.h entrypoints + libc.src.sys.time.setitimer + libc.src.sys.time.getitimer ) if(LLVM_LIBC_INCLUDE_SCUDO) diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 05e8e9e308168..870a194418f43 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -185,6 +185,9 @@ set(TARGET_LIBC_ENTRYPOINTS # libc.src.sys.epoll.epoll_pwait # libc.src.sys.epoll.epoll_pwait2 + # sys/time.h entrypoints + libc.src.sys.time.setitimer + libc.src.sys.time.getitimer ) if(LLVM_LIBC_FULL_BUILD) diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 1ac3a781d5279..73dfeae1a2c94 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -368,6 +368,10 @@ set(TARGET_LIBC_ENTRYPOINTS # sys/uio.h entrypoints libc.src.sys.uio.writev libc.src.sys.uio.readv + + # sys/time.h entrypoints + libc.src.sys.time.setitimer + libc.src.sys.time.getitimer ) if(LLVM_LIBC_INCLUDE_SCUDO) diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt index e43c6f4552644..ac9fe40abf516 100644 --- a/libc/hdr/types/CMakeLists.txt +++ b/libc/hdr/types/CMakeLists.txt @@ -190,6 +190,15 @@ add_proxy_header_library( libc.include.sys_time ) +add_proxy_header_library( + struct_itimerval + HDRS + struct_itimerval.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.struct_itimerval + libc.include.sys_time +) + add_proxy_header_library( pid_t HDRS diff --git a/libc/hdr/types/struct_itimerval.h b/libc/hdr/types/struct_itimerval.h new file mode 100644 index 0000000000000..b2281675b8023 --- /dev/null +++ b/libc/hdr/types/struct_itimerval.h @@ -0,0 +1,21 @@ +//===-- Proxy for struct itimerval ----------------------------------------===// +// +// 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_HDR_TYPES_STRUCT_ITIMERVAL_H +#define LLVM_LIBC_HDR_TYPES_STRUCT_ITIMERVAL_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/struct_itimerval.h" + +#else + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_STRUCT_ITIMERVAL_H diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 9ed39bcd05190..861b983b34219 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -77,6 +77,7 @@ add_header(struct_pollfd HDR struct_pollfd.h) add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t) add_header(struct_sched_param HDR struct_sched_param.h) add_header(struct_timeval HDR struct_timeval.h DEPENDS .suseconds_t .time_t) +add_header(struct_itimerval HDR struct_itimerval.h DEPENDS .struct_timeval) add_header(struct_rusage HDR struct_rusage.h DEPENDS .struct_timeval) add_header(union_sigval HDR union_sigval.h) add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t .clock_t) diff --git a/libc/include/llvm-libc-types/struct_itimerval.h b/libc/include/llvm-libc-types/struct_itimerval.h new file mode 100644 index 0000000000000..e23f1e6076dfe --- /dev/null +++ b/libc/include/llvm-libc-types/struct_itimerval.h @@ -0,0 +1,19 @@ +//===-- Definition of struct itimerval ------------------------------------===// +// +// 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_STRUCT_ITIMERVAL_H +#define LLVM_LIBC_TYPES_STRUCT_ITIMERVAL_H + +#include "struct_timeval.h" + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#endif // LLVM_LIBC_TYPES_STRUCT_ITIMERVAL_H diff --git a/libc/include/sys/time.yaml b/libc/include/sys/time.yaml index 92ab9a467f33a..ed6b94228df75 100644 --- a/libc/include/sys/time.yaml +++ b/libc/include/sys/time.yaml @@ -4,6 +4,7 @@ standards: Linux macros: [] types: - type_name: struct_timeval + - type_name: struct_itimerval enums: [] objects: [] functions: @@ -12,3 +13,20 @@ functions: arguments: - type: const char* - type: const struct timeval* + + - name: setitimer + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const struct itimerval *__restrict + - type: struct itimerval *__restrict + + - name: getitimer + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: struct itimerval * diff --git a/libc/src/sys/time/CMakeLists.txt b/libc/src/sys/time/CMakeLists.txt index f599cddaaeeb3..8ea6752ba87c0 100644 --- a/libc/src/sys/time/CMakeLists.txt +++ b/libc/src/sys/time/CMakeLists.txt @@ -8,3 +8,17 @@ add_entrypoint_object( DEPENDS .${LIBC_TARGET_OS}.utimes ) + +add_entrypoint_object( + setitimer + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.setitimer +) + +add_entrypoint_object( + getitimer + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.getitimer +) diff --git a/libc/src/sys/time/getitimer.h b/libc/src/sys/time/getitimer.h new file mode 100644 index 0000000000000..e19dfd13522ca --- /dev/null +++ b/libc/src/sys/time/getitimer.h @@ -0,0 +1,19 @@ +//===-- Implementation header for getitimer -------------------------------===// +// +// 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_SYS_TIME_GETITIMER_H +#define LLVM_LIBC_SRC_SYS_TIME_GETITIMER_H + +#include "hdr/types/struct_itimerval.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +int getitimer(int which, struct itimerval *curr_value); +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_TIME_GETITIMER_H diff --git a/libc/src/sys/time/linux/CMakeLists.txt b/libc/src/sys/time/linux/CMakeLists.txt index 506001e5c9fd2..7a4dd68eeac2c 100644 --- a/libc/src/sys/time/linux/CMakeLists.txt +++ b/libc/src/sys/time/linux/CMakeLists.txt @@ -14,3 +14,31 @@ add_entrypoint_object( libc.src.__support.OSUtil.osutil libc.src.errno.errno ) + +add_entrypoint_object( + setitimer + SRCS + setitimer.cpp + HDRS + ../setitimer.h + DEPENDS + libc.hdr.types.struct_itimerval + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.errno.errno +) + +add_entrypoint_object( + getitimer + SRCS + getitimer.cpp + HDRS + ../getitimer.h + DEPENDS + libc.hdr.types.struct_itimerval + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.errno.errno +) diff --git a/libc/src/sys/time/linux/getitimer.cpp b/libc/src/sys/time/linux/getitimer.cpp new file mode 100644 index 0000000000000..bbdbaa57dfd30 --- /dev/null +++ b/libc/src/sys/time/linux/getitimer.cpp @@ -0,0 +1,29 @@ +//===-- Implementation file for getitimer ---------------------------------===// +// +// 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/sys/time/getitimer.h" +#include "hdr/types/struct_itimerval.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" +#include + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, getitimer, (int which, struct itimerval *curr_value)) { + long ret = + LIBC_NAMESPACE::syscall_impl(SYS_getitimer, which, curr_value); + // On failure, return -1 and set errno. + if (ret < 0) { + libc_errno = static_cast(-ret); + return -1; + } + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/time/linux/setitimer.cpp b/libc/src/sys/time/linux/setitimer.cpp new file mode 100644 index 0000000000000..b50356004701d --- /dev/null +++ b/libc/src/sys/time/linux/setitimer.cpp @@ -0,0 +1,30 @@ +//===-- Implementation file for setitimer ---------------------------------===// +// +// 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/sys/time/setitimer.h" +#include "hdr/types/struct_itimerval.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" +#include + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, setitimer, + (int which, const struct itimerval *new_value, + struct itimerval *old_value)) { + long ret = LIBC_NAMESPACE::syscall_impl(SYS_setitimer, which, new_value, + old_value); + // On failure, return -1 and set errno. + if (ret < 0) { + libc_errno = static_cast(-ret); + return -1; + } + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/time/setitimer.h b/libc/src/sys/time/setitimer.h new file mode 100644 index 0000000000000..9daf8a71e8615 --- /dev/null +++ b/libc/src/sys/time/setitimer.h @@ -0,0 +1,20 @@ +//===-- Implementation header for setitimer -------------------------------===// +// +// 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_SYS_TIME_SETITIMER_H +#define LLVM_LIBC_SRC_SYS_TIME_SETITIMER_H + +#include "hdr/types/struct_itimerval.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +int setitimer(int which, const struct itimerval *new_value, + struct itimerval *old_value); +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_TIME_SETITIMER_H diff --git a/libc/test/src/sys/time/CMakeLists.txt b/libc/test/src/sys/time/CMakeLists.txt index 72a65eec00937..2468b4ae2cc34 100644 --- a/libc/test/src/sys/time/CMakeLists.txt +++ b/libc/test/src/sys/time/CMakeLists.txt @@ -19,3 +19,34 @@ add_libc_unittest( libc.src.sys.stat.stat libc.test.UnitTest.ErrnoCheckingTest ) + +add_libc_unittest( + setitimer_test + SUITE + libc_sys_time_unittests + SRCS + setitimer_test.cpp + DEPENDS + libc.include.signal + libc.src.sys.time.setitimer + libc.src.signal.sigaction + libc.src.signal.sigemptyset + libc.src.__support.common + libc.src.errno.errno + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher +) + +add_libc_unittest( + getitimer_test + SUITE + libc_sys_time_unittests + SRCS + getitimer_test.cpp + DEPENDS + libc.src.sys.time.getitimer + libc.src.__support.common + libc.src.errno.errno + libc.test.UnitTest.ErrnoCheckingTest + libc.test.UnitTest.ErrnoSetterMatcher +) diff --git a/libc/test/src/sys/time/getitimer_test.cpp b/libc/test/src/sys/time/getitimer_test.cpp new file mode 100644 index 0000000000000..c1d6f72701627 --- /dev/null +++ b/libc/test/src/sys/time/getitimer_test.cpp @@ -0,0 +1,41 @@ +//===-- Unittests for getitimer -------------------------------------------===// +// +// 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 "hdr/types/struct_itimerval.h" +#include "src/sys/time/getitimer.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" + +using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; +using LlvmLibcSysTimeGetitimerTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcSysTimeGetitimerTest, SmokeTest) { + struct itimerval timer; + timer.it_value.tv_sec = -1; + timer.it_value.tv_usec = -1; + timer.it_interval.tv_sec = -1; + timer.it_interval.tv_usec = -1; + + ASSERT_THAT(LIBC_NAMESPACE::getitimer(0, &timer), + returns(EQ(0)).with_errno(EQ(0))); + + ASSERT_TRUE(timer.it_value.tv_sec == 0); + ASSERT_TRUE(timer.it_value.tv_usec == 0); + ASSERT_TRUE(timer.it_interval.tv_sec == 0); + ASSERT_TRUE(timer.it_interval.tv_usec == 0); +} + +TEST_F(LlvmLibcSysTimeGetitimerTest, InvalidRetTest) { + struct itimerval timer; + + // out of range timer type (which) + ASSERT_THAT(LIBC_NAMESPACE::getitimer(99, &timer), + returns(NE(0)).with_errno(NE(0))); +} diff --git a/libc/test/src/sys/time/setitimer_test.cpp b/libc/test/src/sys/time/setitimer_test.cpp new file mode 100644 index 0000000000000..16d33fdf1e4f9 --- /dev/null +++ b/libc/test/src/sys/time/setitimer_test.cpp @@ -0,0 +1,57 @@ +//===-- Unittests for setitimer -------------------------------------------===// +// +// 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 "hdr/types/struct_itimerval.h" +#include "hdr/types/struct_sigaction.h" +#include "src/signal/sigaction.h" +#include "src/signal/sigemptyset.h" +#include "src/sys/time/setitimer.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" + +using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; +using LlvmLibcSysTimeSetitimerTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +static bool timer_fired(false); + +extern "C" void handle_sigalrm(int) { timer_fired = true; } + +TEST_F(LlvmLibcSysTimeSetitimerTest, SmokeTest) { + LIBC_NAMESPACE::libc_errno = 0; + struct sigaction sa; + sa.sa_handler = handle_sigalrm; + LIBC_NAMESPACE::sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + LIBC_NAMESPACE::sigaction(SIGALRM, &sa, nullptr); + + struct itimerval timer; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 200000; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 0; // One-shot timer + + ASSERT_THAT(LIBC_NAMESPACE::setitimer(0, &timer, nullptr), + returns(EQ(0)).with_errno(EQ(0))); + + while (true) { + if (timer_fired) + break; + } + + ASSERT_TRUE(timer_fired); +} + +TEST_F(LlvmLibcSysTimeSetitimerTest, InvalidRetTest) { + struct itimerval timer; + + // out of range timer type (which) + ASSERT_THAT(LIBC_NAMESPACE::setitimer(99, &timer, nullptr), + returns(NE(0)).with_errno(NE(0))); +}