| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <threads.h> |
| |
| #include <lib/zx/timer.h> |
| |
| #include <fbl/type_support.h> |
| |
| #include <unistd.h> |
| #include <unittest/unittest.h> |
| |
| static bool deadline_test() { |
| BEGIN_TEST; |
| auto then = zx_clock_get(ZX_CLOCK_MONOTONIC); |
| // The day we manage to boot and run this test in less than 1uS we need to fix this. |
| ASSERT_GT(then, 1000u); |
| |
| auto one_hour_later = zx_deadline_after(ZX_HOUR(1)); |
| EXPECT_LT(then, one_hour_later); |
| |
| uint64_t too_big = UINT64_MAX - 100u; |
| auto clamped = zx_deadline_after(too_big); |
| EXPECT_EQ(clamped, ZX_TIME_INFINITE); |
| END_TEST; |
| } |
| |
| static bool basic_test() { |
| BEGIN_TEST; |
| zx::timer timer; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK); |
| |
| zx_signals_t pending; |
| EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time(), &pending), ZX_ERR_TIMED_OUT); |
| EXPECT_EQ(pending, 0u); |
| |
| for (int ix = 0; ix != 10; ++ix) { |
| const auto deadline_timer = zx::deadline_after(zx::msec(50)); |
| const auto deadline_wait = zx::deadline_after(zx::sec(1)); |
| // Timer should fire faster than the wait timeout. |
| ASSERT_EQ(timer.set(deadline_timer, zx::nsec(0)), ZX_OK); |
| |
| EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, deadline_wait, &pending), ZX_OK); |
| EXPECT_EQ(pending, ZX_TIMER_SIGNALED); |
| } |
| END_TEST; |
| } |
| |
| static bool restart_test() { |
| BEGIN_TEST; |
| zx::timer timer; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK); |
| |
| zx_signals_t pending; |
| for (int ix = 0; ix != 10; ++ix) { |
| const auto deadline_timer = zx::deadline_after(zx::msec(500)); |
| const auto deadline_wait = zx::deadline_after(zx::msec(1)); |
| // Setting a timer already running is equivalent to a cancel + set. |
| ASSERT_EQ(timer.set(deadline_timer, zx::nsec(0)), ZX_OK); |
| |
| EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, deadline_wait, &pending), ZX_ERR_TIMED_OUT); |
| EXPECT_EQ(pending, 0u); |
| } |
| END_TEST; |
| } |
| |
| static bool invalid_calls() { |
| BEGIN_TEST; |
| |
| zx::timer timer; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_UTC, &timer), ZX_ERR_INVALID_ARGS); |
| ASSERT_EQ(zx::timer::create(ZX_TIMER_SLACK_LATE + 1, ZX_CLOCK_UTC, &timer), ZX_ERR_INVALID_ARGS); |
| |
| END_TEST; |
| } |
| |
| static bool edge_cases() { |
| BEGIN_TEST; |
| |
| zx::timer timer; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK); |
| ASSERT_EQ(timer.set(zx::time(), zx::nsec(0)), ZX_OK); |
| |
| END_TEST; |
| } |
| |
| // furiously spin resetting the timer, trying to race with it going off to look for |
| // race conditions. |
| static bool restart_race() { |
| BEGIN_TEST; |
| |
| const zx_time_t kTestDuration = ZX_SEC(5); |
| auto start = zx_clock_get(ZX_CLOCK_MONOTONIC); |
| |
| zx::timer timer; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK); |
| while (zx_clock_get(ZX_CLOCK_MONOTONIC) - start < kTestDuration) { |
| ASSERT_EQ(timer.set(zx::deadline_after(zx::usec(100)), zx::nsec(0)), ZX_OK); |
| } |
| |
| EXPECT_EQ(timer.cancel(), ZX_OK); |
| |
| END_TEST; |
| } |
| |
| // If the timer is already due at the moment it is started then the signal should be |
| // asserted immediately. Likewise canceling the timer should immediately deassert |
| // the signal. |
| static bool signals_asserted_immediately() { |
| BEGIN_TEST; |
| zx::timer timer; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK); |
| |
| for (int i = 0; i < 100; i++) { |
| zx::time now = zx::clock::get(ZX_CLOCK_MONOTONIC); |
| |
| EXPECT_EQ(timer.set(now, zx::nsec(0)), ZX_OK); |
| |
| zx_signals_t pending; |
| EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time(), &pending), ZX_OK); |
| EXPECT_EQ(pending, ZX_TIMER_SIGNALED); |
| |
| EXPECT_EQ(timer.cancel(), ZX_OK); |
| |
| EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time(), &pending), ZX_ERR_TIMED_OUT); |
| EXPECT_EQ(pending, 0u); |
| } |
| |
| END_TEST; |
| } |
| |
| // This test is disabled because is flaky. The system might have a timer |
| // nearby |deadline_1| or |deadline_2| and as such the test will fire |
| // either earlier or later than expected. The precise behavior is still |
| // tested by the "k timer tests" command. |
| // |
| // See ZX-1087 for the current owner. |
| |
| static bool coalesce_test(uint32_t mode) { |
| BEGIN_TEST; |
| // The second timer will coalesce to the first one for ZX_TIMER_SLACK_LATE |
| // but not for ZX_TIMER_SLACK_EARLY. This test is not precise because the |
| // system might have other timers that interfere with it. Precise tests are |
| // avaliable as kernel tests. |
| |
| zx::timer timer_1; |
| ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer_1), ZX_OK); |
| zx::timer timer_2; |
| ASSERT_EQ(zx::timer::create(mode, ZX_CLOCK_MONOTONIC, &timer_2), ZX_OK); |
| |
| zx_time_t start = zx_clock_get(ZX_CLOCK_MONOTONIC); |
| |
| const auto deadline_1 = zx::time(start + ZX_MSEC(350)); |
| const auto deadline_2 = zx::time(start + ZX_MSEC(250)); |
| |
| ASSERT_EQ(timer_1.set(deadline_1, zx::nsec(0)), ZX_OK); |
| ASSERT_EQ(timer_2.set(deadline_2, zx::msec(110)), ZX_OK); |
| |
| zx_signals_t pending; |
| EXPECT_EQ(timer_2.wait_one(ZX_TIMER_SIGNALED, zx::time::infinite(), &pending), ZX_OK); |
| EXPECT_EQ(pending, ZX_TIMER_SIGNALED); |
| |
| auto duration = zx_clock_get(ZX_CLOCK_MONOTONIC) - start; |
| |
| if (mode == ZX_TIMER_SLACK_LATE) { |
| EXPECT_GE(duration, ZX_MSEC(350)); |
| } else if (mode == ZX_TIMER_SLACK_EARLY) { |
| EXPECT_LE(duration, ZX_MSEC(345)); |
| } else { |
| assert(false); |
| } |
| END_TEST; |
| } |
| |
| // Test is disabled, see coalesce_test(). |
| static bool coalesce_test_early() { |
| return coalesce_test(ZX_TIMER_SLACK_EARLY); |
| } |
| |
| // Test is disabled, see coalesce_test(). |
| static bool coalesce_test_late() { |
| return coalesce_test(ZX_TIMER_SLACK_LATE); |
| } |
| |
| BEGIN_TEST_CASE(timers_test) |
| RUN_TEST(deadline_test) |
| RUN_TEST(invalid_calls) |
| RUN_TEST(basic_test) |
| // Disabled: RUN_TEST(coalesce_test_late) |
| // Disabled: RUN_TEST(coalesce_test_early) |
| RUN_TEST(restart_test) |
| RUN_TEST(edge_cases) |
| RUN_TEST(restart_race) |
| RUN_TEST(signals_asserted_immediately) |
| END_TEST_CASE(timers_test) |
| |
| int main(int argc, char** argv) { |
| bool success = unittest_run_all_tests(argc, argv); |
| return success ? 0 : -1; |
| } |