1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include <chrono>
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include "pw_chrono/system_clock.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/sleep.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/thread.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker using pw::chrono::SystemClock;
23*61c4878aSAndroid Build Coastguard Worker using namespace std::chrono_literals;
24*61c4878aSAndroid Build Coastguard Worker
25*61c4878aSAndroid Build Coastguard Worker namespace pw::this_thread {
26*61c4878aSAndroid Build Coastguard Worker namespace {
27*61c4878aSAndroid Build Coastguard Worker
28*61c4878aSAndroid Build Coastguard Worker extern "C" {
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard Worker // Functions defined in sleep_facade_test_c.c which call the API from C.
31*61c4878aSAndroid Build Coastguard Worker void pw_this_thread_CallSleepFor(pw_chrono_SystemClock_Duration sleep_duration);
32*61c4878aSAndroid Build Coastguard Worker void pw_this_thread_CallSleepUntil(pw_chrono_SystemClock_TimePoint wakeup_time);
33*61c4878aSAndroid Build Coastguard Worker
34*61c4878aSAndroid Build Coastguard Worker } // extern "C"
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker // We can't control the SystemClock's period configuration, so just in case
37*61c4878aSAndroid Build Coastguard Worker // duration cannot be accurately expressed in integer ticks, round the
38*61c4878aSAndroid Build Coastguard Worker // duration up.
39*61c4878aSAndroid Build Coastguard Worker constexpr SystemClock::duration kRoundedArbitraryShortDuration =
40*61c4878aSAndroid Build Coastguard Worker SystemClock::for_at_least(42ms);
41*61c4878aSAndroid Build Coastguard Worker constexpr SystemClock::duration kRoundedArbitraryLongDuration =
42*61c4878aSAndroid Build Coastguard Worker SystemClock::for_at_least(1s);
43*61c4878aSAndroid Build Coastguard Worker constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryShortDurationInC =
44*61c4878aSAndroid Build Coastguard Worker PW_SYSTEM_CLOCK_MS(42);
45*61c4878aSAndroid Build Coastguard Worker constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryLongDurationInC =
46*61c4878aSAndroid Build Coastguard Worker PW_SYSTEM_CLOCK_S(1);
47*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepForPositiveDuration)48*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepForPositiveDuration) {
49*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
50*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker SystemClock::time_point before = SystemClock::now();
53*61c4878aSAndroid Build Coastguard Worker sleep_for(kRoundedArbitraryShortDuration);
54*61c4878aSAndroid Build Coastguard Worker SystemClock::duration time_elapsed = SystemClock::now() - before;
55*61c4878aSAndroid Build Coastguard Worker EXPECT_GE(time_elapsed, kRoundedArbitraryShortDuration);
56*61c4878aSAndroid Build Coastguard Worker }
57*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepForZeroLengthDuration)58*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepForZeroLengthDuration) {
59*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
60*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
61*61c4878aSAndroid Build Coastguard Worker
62*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when a zero length duration is used.
63*61c4878aSAndroid Build Coastguard Worker SystemClock::time_point before = SystemClock::now();
64*61c4878aSAndroid Build Coastguard Worker sleep_for(SystemClock::duration::zero());
65*61c4878aSAndroid Build Coastguard Worker SystemClock::duration time_elapsed = SystemClock::now() - before;
66*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(time_elapsed, kRoundedArbitraryLongDuration);
67*61c4878aSAndroid Build Coastguard Worker }
68*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepForNegativeDuration)69*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepForNegativeDuration) {
70*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
71*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when a negative duration is used.
74*61c4878aSAndroid Build Coastguard Worker SystemClock::time_point before = SystemClock::now();
75*61c4878aSAndroid Build Coastguard Worker sleep_for(-kRoundedArbitraryLongDuration);
76*61c4878aSAndroid Build Coastguard Worker SystemClock::duration time_elapsed = SystemClock::now() - before;
77*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(time_elapsed, kRoundedArbitraryLongDuration);
78*61c4878aSAndroid Build Coastguard Worker }
79*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepUntilFutureWakeupTime)80*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepUntilFutureWakeupTime) {
81*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
82*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker SystemClock::time_point deadline =
85*61c4878aSAndroid Build Coastguard Worker SystemClock::now() + kRoundedArbitraryShortDuration;
86*61c4878aSAndroid Build Coastguard Worker sleep_until(deadline);
87*61c4878aSAndroid Build Coastguard Worker EXPECT_GE(SystemClock::now(), deadline);
88*61c4878aSAndroid Build Coastguard Worker }
89*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepUntilCurrentWakeupTime)90*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepUntilCurrentWakeupTime) {
91*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
92*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when now is used.
95*61c4878aSAndroid Build Coastguard Worker SystemClock::time_point deadline =
96*61c4878aSAndroid Build Coastguard Worker SystemClock::now() + kRoundedArbitraryLongDuration;
97*61c4878aSAndroid Build Coastguard Worker sleep_until(SystemClock::now());
98*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(SystemClock::now(), deadline);
99*61c4878aSAndroid Build Coastguard Worker }
100*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepUntilPastWakeupTime)101*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepUntilPastWakeupTime) {
102*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
103*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when a timestamp in the past is used.
106*61c4878aSAndroid Build Coastguard Worker SystemClock::time_point deadline =
107*61c4878aSAndroid Build Coastguard Worker SystemClock::now() + kRoundedArbitraryLongDuration;
108*61c4878aSAndroid Build Coastguard Worker sleep_until(SystemClock::now() - kRoundedArbitraryLongDuration);
109*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(SystemClock::now(), deadline);
110*61c4878aSAndroid Build Coastguard Worker }
111*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepForPositiveDurationInC)112*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepForPositiveDurationInC) {
113*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
114*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
117*61c4878aSAndroid Build Coastguard Worker pw_this_thread_SleepFor(kRoundedArbitraryShortDurationInC);
118*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Duration time_elapsed =
119*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
120*61c4878aSAndroid Build Coastguard Worker EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryShortDurationInC.ticks);
121*61c4878aSAndroid Build Coastguard Worker }
122*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepForZeroLengthDurationInC)123*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepForZeroLengthDurationInC) {
124*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
125*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
126*61c4878aSAndroid Build Coastguard Worker
127*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when a zero length duration is used.
128*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
129*61c4878aSAndroid Build Coastguard Worker pw_this_thread_SleepFor(PW_SYSTEM_CLOCK_MS(0));
130*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Duration time_elapsed =
131*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
132*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryLongDurationInC.ticks);
133*61c4878aSAndroid Build Coastguard Worker }
134*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepForNegativeDurationInC)135*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepForNegativeDurationInC) {
136*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
137*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
138*61c4878aSAndroid Build Coastguard Worker
139*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when a negative duration is used.
140*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
141*61c4878aSAndroid Build Coastguard Worker pw_this_thread_SleepFor(
142*61c4878aSAndroid Build Coastguard Worker PW_SYSTEM_CLOCK_MS(-kRoundedArbitraryLongDurationInC.ticks));
143*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Duration time_elapsed =
144*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
145*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryLongDurationInC.ticks);
146*61c4878aSAndroid Build Coastguard Worker }
147*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepUntilFutureWakeupTimeInC)148*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepUntilFutureWakeupTimeInC) {
149*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
150*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint deadline;
153*61c4878aSAndroid Build Coastguard Worker deadline.duration_since_epoch.ticks =
154*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
155*61c4878aSAndroid Build Coastguard Worker kRoundedArbitraryShortDurationInC.ticks;
156*61c4878aSAndroid Build Coastguard Worker pw_this_thread_CallSleepUntil(deadline);
157*61c4878aSAndroid Build Coastguard Worker EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
158*61c4878aSAndroid Build Coastguard Worker deadline.duration_since_epoch.ticks);
159*61c4878aSAndroid Build Coastguard Worker }
160*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepUntilCurrentWakeupTimeInC)161*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepUntilCurrentWakeupTimeInC) {
162*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
163*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
164*61c4878aSAndroid Build Coastguard Worker
165*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when now is used.
166*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint deadline;
167*61c4878aSAndroid Build Coastguard Worker deadline.duration_since_epoch.ticks =
168*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
169*61c4878aSAndroid Build Coastguard Worker kRoundedArbitraryLongDurationInC.ticks;
170*61c4878aSAndroid Build Coastguard Worker pw_this_thread_CallSleepUntil(pw_chrono_SystemClock_Now());
171*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
172*61c4878aSAndroid Build Coastguard Worker deadline.duration_since_epoch.ticks);
173*61c4878aSAndroid Build Coastguard Worker }
174*61c4878aSAndroid Build Coastguard Worker
TEST(Sleep,SleepUntilPastWakeupTimeInC)175*61c4878aSAndroid Build Coastguard Worker TEST(Sleep, SleepUntilPastWakeupTimeInC) {
176*61c4878aSAndroid Build Coastguard Worker // Ensure we are in a thread context, meaning we are permitted to sleep.
177*61c4878aSAndroid Build Coastguard Worker ASSERT_NE(get_id(), Thread::id());
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard Worker // Ensure it doesn't sleep when a timestamp in the past is used.
180*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint deadline;
181*61c4878aSAndroid Build Coastguard Worker deadline.duration_since_epoch.ticks =
182*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
183*61c4878aSAndroid Build Coastguard Worker kRoundedArbitraryLongDurationInC.ticks;
184*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_TimePoint old_timestamp;
185*61c4878aSAndroid Build Coastguard Worker old_timestamp.duration_since_epoch.ticks =
186*61c4878aSAndroid Build Coastguard Worker pw_chrono_SystemClock_Now().duration_since_epoch.ticks -
187*61c4878aSAndroid Build Coastguard Worker kRoundedArbitraryLongDurationInC.ticks;
188*61c4878aSAndroid Build Coastguard Worker pw_this_thread_CallSleepUntil(old_timestamp);
189*61c4878aSAndroid Build Coastguard Worker EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
190*61c4878aSAndroid Build Coastguard Worker deadline.duration_since_epoch.ticks);
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard Worker } // namespace
194*61c4878aSAndroid Build Coastguard Worker } // namespace pw::this_thread
195