• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
18 #include "pw_chrono/system_clock.h"
19 #include "pw_thread/id.h"
20 #include "pw_thread/sleep.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 kRoundedArbitraryDuration =
40     SystemClock::for_at_least(42ms);
41 constexpr pw_chrono_SystemClock_Duration kRoundedArbitraryDurationInC =
42     PW_SYSTEM_CLOCK_MS(42);
43 
TEST(Sleep,SleepForPositiveDuration)44 TEST(Sleep, SleepForPositiveDuration) {
45   // Ensure we are in a thread context, meaning we are permitted to sleep.
46   ASSERT_NE(get_id(), thread::Id());
47 
48   SystemClock::time_point before = SystemClock::now();
49   sleep_for(kRoundedArbitraryDuration);
50   SystemClock::duration time_elapsed = SystemClock::now() - before;
51   EXPECT_GE(time_elapsed, kRoundedArbitraryDuration);
52 }
53 
TEST(Sleep,SleepForZeroLengthDuration)54 TEST(Sleep, SleepForZeroLengthDuration) {
55   // Ensure we are in a thread context, meaning we are permitted to sleep.
56   ASSERT_NE(get_id(), thread::Id());
57 
58   // Ensure it doesn't sleep when a zero length duration is used.
59   SystemClock::time_point before = SystemClock::now();
60   sleep_for(SystemClock::duration::zero());
61   SystemClock::duration time_elapsed = SystemClock::now() - before;
62   EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
63 }
64 
TEST(Sleep,SleepForNegativeDuration)65 TEST(Sleep, SleepForNegativeDuration) {
66   // Ensure we are in a thread context, meaning we are permitted to sleep.
67   ASSERT_NE(get_id(), thread::Id());
68 
69   // Ensure it doesn't sleep when a negative duration is used.
70   SystemClock::time_point before = SystemClock::now();
71   sleep_for(-kRoundedArbitraryDuration);
72   SystemClock::duration time_elapsed = SystemClock::now() - before;
73   EXPECT_LT(time_elapsed, kRoundedArbitraryDuration);
74 }
75 
TEST(Sleep,SleepUntilFutureWakeupTime)76 TEST(Sleep, SleepUntilFutureWakeupTime) {
77   // Ensure we are in a thread context, meaning we are permitted to sleep.
78   ASSERT_NE(get_id(), thread::Id());
79 
80   SystemClock::time_point deadline =
81       SystemClock::now() + kRoundedArbitraryDuration;
82   sleep_until(deadline);
83   EXPECT_GE(SystemClock::now(), deadline);
84 }
85 
TEST(Sleep,SleepUntilCurrentWakeupTime)86 TEST(Sleep, SleepUntilCurrentWakeupTime) {
87   // Ensure we are in a thread context, meaning we are permitted to sleep.
88   ASSERT_NE(get_id(), thread::Id());
89 
90   // Ensure it doesn't sleep when now is used.
91   SystemClock::time_point deadline =
92       SystemClock::now() + kRoundedArbitraryDuration;
93   sleep_until(SystemClock::now());
94   EXPECT_LT(SystemClock::now(), deadline);
95 }
96 
TEST(Sleep,SleepUntilPastWakeupTime)97 TEST(Sleep, SleepUntilPastWakeupTime) {
98   // Ensure we are in a thread context, meaning we are permitted to sleep.
99   ASSERT_NE(get_id(), thread::Id());
100 
101   // Ensure it doesn't sleep when a timestamp in the past is used.
102   SystemClock::time_point deadline =
103       SystemClock::now() + kRoundedArbitraryDuration;
104   sleep_until(SystemClock::now() - kRoundedArbitraryDuration);
105   EXPECT_LT(SystemClock::now(), deadline);
106 }
107 
TEST(Sleep,SleepForPositiveDurationInC)108 TEST(Sleep, SleepForPositiveDurationInC) {
109   // Ensure we are in a thread context, meaning we are permitted to sleep.
110   ASSERT_NE(get_id(), thread::Id());
111 
112   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
113   pw_this_thread_SleepFor(kRoundedArbitraryDurationInC);
114   pw_chrono_SystemClock_Duration time_elapsed =
115       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
116   EXPECT_GE(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
117 }
118 
TEST(Sleep,SleepForZeroLengthDurationInC)119 TEST(Sleep, SleepForZeroLengthDurationInC) {
120   // Ensure we are in a thread context, meaning we are permitted to sleep.
121   ASSERT_NE(get_id(), thread::Id());
122 
123   // Ensure it doesn't sleep when a zero length duration is used.
124   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
125   pw_this_thread_SleepFor(PW_SYSTEM_CLOCK_MS(0));
126   pw_chrono_SystemClock_Duration time_elapsed =
127       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
128   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
129 }
130 
TEST(Sleep,SleepForNegativeDurationInC)131 TEST(Sleep, SleepForNegativeDurationInC) {
132   // Ensure we are in a thread context, meaning we are permitted to sleep.
133   ASSERT_NE(get_id(), thread::Id());
134 
135   // Ensure it doesn't sleep when a negative duration is used.
136   pw_chrono_SystemClock_TimePoint before = pw_chrono_SystemClock_Now();
137   pw_this_thread_SleepFor(
138       PW_SYSTEM_CLOCK_MS(-kRoundedArbitraryDurationInC.ticks));
139   pw_chrono_SystemClock_Duration time_elapsed =
140       pw_chrono_SystemClock_TimeElapsed(before, pw_chrono_SystemClock_Now());
141   EXPECT_LT(time_elapsed.ticks, kRoundedArbitraryDurationInC.ticks);
142 }
143 
TEST(Sleep,SleepUntilFutureWakeupTimeInC)144 TEST(Sleep, SleepUntilFutureWakeupTimeInC) {
145   // Ensure we are in a thread context, meaning we are permitted to sleep.
146   ASSERT_NE(get_id(), thread::Id());
147 
148   pw_chrono_SystemClock_TimePoint deadline;
149   deadline.duration_since_epoch.ticks =
150       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
151       kRoundedArbitraryDurationInC.ticks;
152   pw_this_thread_CallSleepUntil(deadline);
153   EXPECT_GE(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
154             deadline.duration_since_epoch.ticks);
155 }
156 
TEST(Sleep,SleepUntilCurrentWakeupTimeInC)157 TEST(Sleep, SleepUntilCurrentWakeupTimeInC) {
158   // Ensure we are in a thread context, meaning we are permitted to sleep.
159   ASSERT_NE(get_id(), thread::Id());
160 
161   // Ensure it doesn't sleep when now is used.
162   pw_chrono_SystemClock_TimePoint deadline;
163   deadline.duration_since_epoch.ticks =
164       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
165       kRoundedArbitraryDurationInC.ticks;
166   pw_this_thread_CallSleepUntil(pw_chrono_SystemClock_Now());
167   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
168             deadline.duration_since_epoch.ticks);
169 }
170 
TEST(Sleep,SleepUntilPastWakeupTimeInC)171 TEST(Sleep, SleepUntilPastWakeupTimeInC) {
172   // Ensure we are in a thread context, meaning we are permitted to sleep.
173   ASSERT_NE(get_id(), thread::Id());
174 
175   // Ensure it doesn't sleep when a timestamp in the past is used.
176   pw_chrono_SystemClock_TimePoint deadline;
177   deadline.duration_since_epoch.ticks =
178       pw_chrono_SystemClock_Now().duration_since_epoch.ticks +
179       kRoundedArbitraryDurationInC.ticks;
180   pw_chrono_SystemClock_TimePoint old_timestamp;
181   old_timestamp.duration_since_epoch.ticks =
182       pw_chrono_SystemClock_Now().duration_since_epoch.ticks -
183       kRoundedArbitraryDurationInC.ticks;
184   pw_this_thread_CallSleepUntil(old_timestamp);
185   EXPECT_LT(pw_chrono_SystemClock_Now().duration_since_epoch.ticks,
186             deadline.duration_since_epoch.ticks);
187 }
188 
189 }  // namespace
190 }  // namespace pw::this_thread
191