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