1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h>
6#include <stdio.h>
7#include <threads.h>
8
9#include <lib/zx/timer.h>
10
11#include <fbl/type_support.h>
12
13#include <unistd.h>
14#include <unittest/unittest.h>
15
16static bool deadline_after() {
17    BEGIN_TEST;
18    auto then = zx_clock_get_monotonic();
19    // The day we manage to boot and run this test in less than 1uS we need to fix this.
20    ASSERT_GT(then, 1000u);
21
22    auto one_hour_later = zx_deadline_after(ZX_HOUR(1));
23    EXPECT_LT(then, one_hour_later);
24
25    zx_duration_t too_big = INT64_MAX - 100;
26    auto clamped = zx_deadline_after(too_big);
27    EXPECT_EQ(clamped, ZX_TIME_INFINITE);
28
29    EXPECT_LT(0, zx_deadline_after(10 * 365 * ZX_HOUR(24)));
30    EXPECT_LT(zx_deadline_after(ZX_TIME_INFINITE_PAST), 0);
31    END_TEST;
32}
33
34static bool timer_set_negative_deadline() {
35    BEGIN_TEST;
36    zx::timer timer;
37    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
38    zx::duration slack;
39    ASSERT_EQ(timer.set(zx::time(-1), slack), ZX_OK);
40    zx_signals_t pending;
41    ASSERT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time::infinite(), &pending), ZX_OK);
42    ASSERT_EQ(pending, ZX_TIMER_SIGNALED);
43    END_TEST;
44}
45
46static bool timer_set_negative_deadline_max() {
47    BEGIN_TEST;
48    zx::timer timer;
49    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
50    zx::duration slack;
51    ASSERT_EQ(timer.set(zx::time(ZX_TIME_INFINITE_PAST), slack), ZX_OK);
52    zx_signals_t pending;
53    ASSERT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time::infinite(), &pending), ZX_OK);
54    ASSERT_EQ(pending, ZX_TIMER_SIGNALED);
55    END_TEST;
56}
57
58static bool timer_set_negative_slack() {
59    BEGIN_TEST;
60    zx::timer timer;
61    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
62    ASSERT_EQ(timer.set(zx::time(), zx::duration(-1)), ZX_ERR_OUT_OF_RANGE);
63    END_TEST;
64}
65
66static bool basic_test() {
67    BEGIN_TEST;
68    zx::timer timer;
69    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
70
71    zx_signals_t pending;
72    EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time(), &pending), ZX_ERR_TIMED_OUT);
73    EXPECT_EQ(pending, 0u);
74
75    for (int ix = 0; ix != 10; ++ix) {
76        const auto deadline_timer = zx::deadline_after(zx::msec(50));
77        const auto deadline_wait = zx::deadline_after(zx::sec(1));
78        // Timer should fire faster than the wait timeout.
79        ASSERT_EQ(timer.set(deadline_timer, zx::nsec(0)), ZX_OK);
80
81        EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, deadline_wait, &pending), ZX_OK);
82        EXPECT_EQ(pending, ZX_TIMER_SIGNALED);
83    }
84    END_TEST;
85}
86
87static bool restart_test() {
88    BEGIN_TEST;
89    zx::timer timer;
90    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
91
92    zx_signals_t pending;
93    for (int ix = 0; ix != 10; ++ix) {
94        const auto deadline_timer = zx::deadline_after(zx::msec(500));
95        const auto deadline_wait = zx::deadline_after(zx::msec(1));
96        // Setting a timer already running is equivalent to a cancel + set.
97        ASSERT_EQ(timer.set(deadline_timer, zx::nsec(0)), ZX_OK);
98
99        EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, deadline_wait, &pending), ZX_ERR_TIMED_OUT);
100        EXPECT_EQ(pending, 0u);
101    }
102    END_TEST;
103}
104
105static bool invalid_calls() {
106    BEGIN_TEST;
107
108    zx::timer timer;
109    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_UTC, &timer), ZX_ERR_INVALID_ARGS);
110    ASSERT_EQ(zx::timer::create(ZX_TIMER_SLACK_LATE + 1, ZX_CLOCK_UTC, &timer), ZX_ERR_INVALID_ARGS);
111
112    END_TEST;
113}
114
115static bool edge_cases() {
116    BEGIN_TEST;
117
118    zx::timer timer;
119    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
120    ASSERT_EQ(timer.set(zx::time(), zx::nsec(0)), ZX_OK);
121
122    END_TEST;
123}
124
125// furiously spin resetting the timer, trying to race with it going off to look for
126// race conditions.
127static bool restart_race() {
128    BEGIN_TEST;
129
130    const zx_time_t kTestDuration = ZX_SEC(5);
131    auto start = zx_clock_get_monotonic();
132
133    zx::timer timer;
134    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
135    while (zx_clock_get_monotonic() - start < kTestDuration) {
136        ASSERT_EQ(timer.set(zx::deadline_after(zx::usec(100)), zx::nsec(0)), ZX_OK);
137    }
138
139    EXPECT_EQ(timer.cancel(), ZX_OK);
140
141    END_TEST;
142}
143
144// If the timer is already due at the moment it is started then the signal should be
145// asserted immediately.  Likewise canceling the timer should immediately deassert
146// the signal.
147static bool signals_asserted_immediately() {
148    BEGIN_TEST;
149    zx::timer timer;
150    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer), ZX_OK);
151
152    for (int i = 0; i < 100; i++) {
153        zx::time now = zx::clock::get_monotonic();
154
155        EXPECT_EQ(timer.set(now, zx::nsec(0)), ZX_OK);
156
157        zx_signals_t pending;
158        EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time(), &pending), ZX_OK);
159        EXPECT_EQ(pending, ZX_TIMER_SIGNALED);
160
161        EXPECT_EQ(timer.cancel(), ZX_OK);
162
163        EXPECT_EQ(timer.wait_one(ZX_TIMER_SIGNALED, zx::time(), &pending), ZX_ERR_TIMED_OUT);
164        EXPECT_EQ(pending, 0u);
165    }
166
167    END_TEST;
168}
169
170// This test is disabled because is flaky. The system might have a timer
171// nearby |deadline_1| or |deadline_2| and as such the test will fire
172// either earlier or later than expected. The precise behavior is still
173// tested by the "k timer tests" command.
174//
175// See ZX-1087 for the current owner.
176
177static bool coalesce_test(uint32_t mode) {
178    BEGIN_TEST;
179    // The second timer will coalesce to the first one for ZX_TIMER_SLACK_LATE
180    // but not for  ZX_TIMER_SLACK_EARLY. This test is not precise because the
181    // system might have other timers that interfere with it. Precise tests are
182    // avaliable as kernel tests.
183
184    zx::timer timer_1;
185    ASSERT_EQ(zx::timer::create(0, ZX_CLOCK_MONOTONIC, &timer_1), ZX_OK);
186    zx::timer timer_2;
187    ASSERT_EQ(zx::timer::create(mode, ZX_CLOCK_MONOTONIC, &timer_2), ZX_OK);
188
189    zx_time_t start = zx_clock_get_monotonic();
190
191    const auto deadline_1 = zx::time(start + ZX_MSEC(350));
192    const auto deadline_2 = zx::time(start + ZX_MSEC(250));
193
194    ASSERT_EQ(timer_1.set(deadline_1, zx::nsec(0)), ZX_OK);
195    ASSERT_EQ(timer_2.set(deadline_2, zx::msec(110)), ZX_OK);
196
197    zx_signals_t pending;
198    EXPECT_EQ(timer_2.wait_one(ZX_TIMER_SIGNALED, zx::time::infinite(), &pending), ZX_OK);
199    EXPECT_EQ(pending, ZX_TIMER_SIGNALED);
200
201    auto duration = zx_clock_get_monotonic() - start;
202
203    if (mode == ZX_TIMER_SLACK_LATE) {
204        EXPECT_GE(duration, ZX_MSEC(350));
205    } else if (mode == ZX_TIMER_SLACK_EARLY) {
206        EXPECT_LE(duration, ZX_MSEC(345));
207    } else {
208        assert(false);
209    }
210    END_TEST;
211}
212
213// Test is disabled, see coalesce_test().
214static bool coalesce_test_early() {
215    return coalesce_test(ZX_TIMER_SLACK_EARLY);
216}
217
218// Test is disabled, see coalesce_test().
219static bool coalesce_test_late() {
220    return coalesce_test(ZX_TIMER_SLACK_LATE);
221}
222
223BEGIN_TEST_CASE(timers_test)
224RUN_TEST(deadline_after)
225RUN_TEST(timer_set_negative_deadline)
226RUN_TEST(timer_set_negative_deadline_max)
227RUN_TEST(timer_set_negative_slack)
228RUN_TEST(invalid_calls)
229RUN_TEST(basic_test)
230// Disabled: RUN_TEST(coalesce_test_late)
231// Disabled: RUN_TEST(coalesce_test_early)
232RUN_TEST(restart_test)
233RUN_TEST(edge_cases)
234RUN_TEST(restart_race)
235RUN_TEST(signals_asserted_immediately)
236END_TEST_CASE(timers_test)
237
238int main(int argc, char** argv) {
239    bool success = unittest_run_all_tests(argc, argv);
240    return success ? 0 : -1;
241}
242