| //===----------------------------------------------------------------------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// Unittests for posix timers (timer_create, timer_delete). | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "hdr/errno_macros.h" | |
| #include "hdr/signal_macros.h" | |
| #include "hdr/time_macros.h" | |
| #include "hdr/types/clockid_t.h" | |
| #include "hdr/types/struct_itimerspec.h" | |
| #include "hdr/types/struct_sigevent.h" | |
| #include "hdr/types/timer_t.h" | |
| #include "src/time/clock_gettime.h" | |
| #include "src/time/timer_create.h" | |
| #include "src/time/timer_delete.h" | |
| #include "src/time/timer_gettime.h" | |
| #include "src/time/timer_settime.h" | |
| #include "src/unistd/gettid.h" | |
| #include "test/UnitTest/ErrnoCheckingTest.h" | |
| #include "test/UnitTest/ErrnoSetterMatcher.h" | |
| #include "test/UnitTest/Test.h" | |
| using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::any_of; | |
| using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; | |
| using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; | |
| using LlvmLibcTimerTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; | |
| TEST_F(LlvmLibcTimerTest, NullSigevent) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, ValidSigeventSigevNone) { | |
| sigevent se; | |
| se.sigev_notify = SIGEV_NONE; | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_MONOTONIC, &se, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, ValidSigeventSigevSignal) { | |
| sigevent se; | |
| se.sigev_notify = SIGEV_SIGNAL; | |
| se.sigev_signo = SIGALRM; | |
| se.sigev_value.sival_int = 42; | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, &se, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| #ifdef SIGEV_THREAD_ID | |
| TEST_F(LlvmLibcTimerTest, ValidSigeventSigevThreadId) { | |
| sigevent se; | |
| se.sigev_notify = SIGEV_THREAD_ID; | |
| se.sigev_signo = SIGALRM; | |
| se.sigev_value.sival_int = 42; | |
| se.sigev_notify_thread_id = LIBC_NAMESPACE::gettid(); | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, &se, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| #endif | |
| TEST_F(LlvmLibcTimerTest, InvalidClockId) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(static_cast<clockid_t>(-1), nullptr, | |
| &timerid), | |
| Fails(EINVAL)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, NullTimerId) { | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, nullptr), | |
| Fails(any_of(EINVAL, EFAULT))); | |
| } | |
| TEST_F(LlvmLibcTimerTest, DeleteInvalidTimerId) { | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(reinterpret_cast<timer_t>(-1)), | |
| Fails(EINVAL)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, CreateAndDelete) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Fails(EINVAL)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, SetTimeRelativeAndDisarm) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| itimerspec new_val{}; | |
| new_val.it_value.tv_sec = 10; | |
| new_val.it_value.tv_nsec = 0; | |
| new_val.it_interval.tv_sec = 1; | |
| new_val.it_interval.tv_nsec = 0; | |
| itimerspec old_val{}; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(timerid, 0, &new_val, &old_val), | |
| Succeeds(0)); | |
| // Initially, old_val should be 0 because it was disarmed. | |
| ASSERT_EQ(old_val.it_value.tv_sec, static_cast<time_t>(0)); | |
| ASSERT_EQ(old_val.it_value.tv_nsec, | |
| static_cast<decltype(old_val.it_value.tv_nsec)>(0)); | |
| // Disarm the timer by setting it_value to 0 | |
| itimerspec disarm_val{}; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(timerid, 0, &disarm_val, &old_val), | |
| Succeeds(0)); | |
| // old_val should have been armed previously | |
| ASSERT_GT(old_val.it_value.tv_sec, static_cast<time_t>(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, SetTimeAbsolute) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| timespec now{}; | |
| ASSERT_THAT(LIBC_NAMESPACE::clock_gettime(CLOCK_REALTIME, &now), Succeeds(0)); | |
| itimerspec new_val{}; | |
| new_val.it_value.tv_sec = now.tv_sec + 100; | |
| new_val.it_value.tv_nsec = 0; | |
| ASSERT_THAT( | |
| LIBC_NAMESPACE::timer_settime(timerid, TIMER_ABSTIME, &new_val, nullptr), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, SetTimeInvalidTimerId) { | |
| itimerspec new_val{}; | |
| new_val.it_value.tv_sec = 1; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(reinterpret_cast<timer_t>(-1), 0, | |
| &new_val, nullptr), | |
| Fails(EINVAL)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, SetTimeNullNewValue) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(timerid, 0, nullptr, nullptr), | |
| Fails(any_of(EINVAL, EFAULT))); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, SetTimeInvalidNanoseconds) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| itimerspec new_val{}; | |
| new_val.it_value.tv_sec = 1; | |
| new_val.it_value.tv_nsec = 1000000000; // invalid >= 10^9 | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(timerid, 0, &new_val, nullptr), | |
| Fails(EINVAL)); | |
| new_val.it_value.tv_nsec = -1; // invalid < 0 | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(timerid, 0, &new_val, nullptr), | |
| Fails(EINVAL)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, GetTimeDisarmedAndArmed) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| itimerspec curr_val{}; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_gettime(timerid, &curr_val), Succeeds(0)); | |
| ASSERT_EQ(curr_val.it_value.tv_sec, static_cast<time_t>(0)); | |
| ASSERT_EQ(curr_val.it_value.tv_nsec, | |
| static_cast<decltype(curr_val.it_value.tv_nsec)>(0)); | |
| itimerspec new_val{}; | |
| new_val.it_value.tv_sec = 20; | |
| new_val.it_value.tv_nsec = 0; | |
| new_val.it_interval.tv_sec = 2; | |
| new_val.it_interval.tv_nsec = 0; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_settime(timerid, 0, &new_val, nullptr), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_gettime(timerid, &curr_val), Succeeds(0)); | |
| ASSERT_GT(curr_val.it_value.tv_sec, static_cast<time_t>(0)); | |
| ASSERT_EQ(curr_val.it_interval.tv_sec, static_cast<time_t>(2)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, GetTimeInvalidTimerId) { | |
| itimerspec curr_val{}; | |
| ASSERT_THAT( | |
| LIBC_NAMESPACE::timer_gettime(reinterpret_cast<timer_t>(-1), &curr_val), | |
| Fails(EINVAL)); | |
| } | |
| TEST_F(LlvmLibcTimerTest, GetTimeNullPointer) { | |
| timer_t timerid; | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_create(CLOCK_REALTIME, nullptr, &timerid), | |
| Succeeds(0)); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_gettime(timerid, nullptr), | |
| Fails(any_of(EINVAL, EFAULT))); | |
| ASSERT_THAT(LIBC_NAMESPACE::timer_delete(timerid), Succeeds(0)); | |
| } |