blob: 7b9145dc0419726f0fbc332a45697b4683fe68f8 [file] [log] [blame]
Brian Silverman797e71e2013-09-06 17:29:39 -07001#include "aos/common/condition.h"
2
3#include <unistd.h>
4#include <sys/types.h>
5#include <sys/wait.h>
6
Brian Silvermanf1194642014-09-04 13:01:17 -04007#include <atomic>
8
Brian Silverman797e71e2013-09-06 17:29:39 -07009#include "gtest/gtest.h"
10
Brian Silverman797e71e2013-09-06 17:29:39 -070011#include "aos/common/time.h"
12#include "aos/common/mutex.h"
13#include "aos/common/queue_testutils.h"
14#include "aos/common/type_traits.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -080015#include "aos/linux_code/ipc_lib/core_lib.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070016#include "aos/common/logging/logging.h"
Brian Silverman2586a5d2013-09-13 13:45:52 -070017#include "aos/common/macros.h"
Brian Silverman8d2e56e2013-09-23 17:55:03 -070018#include "aos/common/die.h"
Brian Silvermanf1194642014-09-04 13:01:17 -040019#include "aos/common/util/thread.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070020
21using ::aos::time::Time;
22using ::aos::common::testing::GlobalCoreInstance;
23
24namespace aos {
25namespace testing {
26
Brian Silvermanf1194642014-09-04 13:01:17 -040027class ConditionTestCommon : public ::testing::Test {
28 public:
29 ConditionTestCommon() {}
30
31 void Settle() {
32 time::SleepFor(::Time::InSeconds(0.008));
33 }
34
35 private:
36 DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
37};
38
39// Some simple tests that don't rely on a GlobalCoreInstance to help with
40// debugging problems that cause tests using that to just completely lock up.
41class SimpleConditionTest : public ConditionTestCommon {
42 public:
43 SimpleConditionTest() : condition_(&mutex_) {}
44
45 Mutex mutex_;
46 Condition condition_;
47
48 private:
49 DISALLOW_COPY_AND_ASSIGN(SimpleConditionTest);
50};
51
52// Makes sure that nothing crashes or anything with a basic Wait() and then
53// Signal().
54// This test is written to hopefully fail instead of deadlocking on failure, but
55// it's tricky because there's no way to kill the child in the middle.
56TEST_F(SimpleConditionTest, Basic) {
57 ::std::atomic_bool child_finished(false);
58 Condition child_ready(&mutex_);
59 ASSERT_FALSE(mutex_.Lock());
60 util::FunctionThread child([this, &child_finished, &child_ready](
61 util::FunctionThread *) {
62 ASSERT_FALSE(mutex_.Lock());
63 child_ready.Broadcast();
64 ASSERT_FALSE(condition_.Wait());
65 child_finished.store(true);
66 mutex_.Unlock();
67 });
68 child.Start();
69 ASSERT_FALSE(child_ready.Wait());
70 EXPECT_FALSE(child_finished.load());
71 condition_.Signal();
72 mutex_.Unlock();
73 child.Join();
74 EXPECT_TRUE(child_finished.load());
75}
76
77class ConditionTest : public ConditionTestCommon {
Brian Silverman797e71e2013-09-06 17:29:39 -070078 public:
79 struct Shared {
80 Shared() : condition(&mutex) {}
81
82 Mutex mutex;
83 Condition condition;
84 };
85 static_assert(shm_ok<Shared>::value,
86 "it's going to get shared between forked processes");
87
88 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
89 new (shared_) Shared();
90 }
91
92 GlobalCoreInstance my_core;
93
94 Shared *const shared_;
95
Brian Silverman8d2e56e2013-09-23 17:55:03 -070096 protected:
97 void SetUp() override {
98 SetDieTestMode(true);
99 }
100
Brian Silverman2586a5d2013-09-13 13:45:52 -0700101 private:
102 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700103};
104
105class ConditionTestProcess {
106 public:
107 enum class Action {
108 kWaitLockStart, // lock, delay, wait, unlock
109 kWait, // delay, lock, wait, unlock
110 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700111 };
112
113 // This amount gets added to any passed in delay to make the test repeatable.
114 static constexpr ::Time kMinimumDelay = ::Time::InSeconds(0.015);
Brian Silverman4c04efd2013-09-07 14:51:33 -0700115 static constexpr ::Time kDefaultTimeout = ::Time::InSeconds(0.09);
Brian Silverman797e71e2013-09-06 17:29:39 -0700116
117 // delay is how long to wait before doing action to condition.
118 // timeout is how long to wait after delay before deciding that it's hung.
119 ConditionTestProcess(const ::Time &delay, Action action, Condition *condition,
120 const ::Time &timeout = kDefaultTimeout)
121 : delay_(kMinimumDelay + delay), action_(action), condition_(condition),
122 timeout_(delay_ + timeout), child_(-1),
123 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
124 new (shared_) Shared();
125 }
126 ~ConditionTestProcess() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700127 CHECK_EQ(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700128 }
129
130 void Start() {
131 ASSERT_FALSE(shared_->started);
132
133 child_ = fork();
134 if (child_ == 0) { // in child
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700135 ::aos::common::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700136 Run();
137 exit(EXIT_SUCCESS);
138 } else { // in parent
Brian Silvermanfe457de2014-05-26 22:04:08 -0700139 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700140
141 shared_->ready.Lock();
142
143 shared_->started = true;
144 }
145 }
146
147 bool IsFinished() {
148 return shared_->finished;
149 }
150
151 ::testing::AssertionResult Hung() {
152 if (!shared_->started) {
153 ADD_FAILURE();
154 return ::testing::AssertionFailure() << "not started yet";
155 }
156 if (shared_->finished) {
157 Join();
158 return ::testing::AssertionFailure() << "already returned";
159 }
160 if (shared_->delayed) {
161 if (shared_->start_time > ::Time::Now() + timeout_) {
162 Kill();
163 return ::testing::AssertionSuccess() << "already been too long";
164 }
165 } else {
166 shared_->done_delaying.Lock();
167 }
168 time::SleepFor(::Time::InSeconds(0.01));
169 if (!shared_->finished) time::SleepUntil(shared_->start_time + timeout_);
170 if (shared_->finished) {
171 Join();
172 return ::testing::AssertionFailure() << "completed within timeout";
173 } else {
174 Kill();
175 return ::testing::AssertionSuccess() << "took too long";
176 }
177 }
178 ::testing::AssertionResult Test() {
179 Start();
180 return Hung();
181 }
182
183 private:
184 struct Shared {
185 Shared()
186 : started(false), delayed(false), start_time(0, 0), finished(false) {
187 done_delaying.Lock();
188 ready.Lock();
189 }
190
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700191 volatile bool started;
192 volatile bool delayed;
Brian Silverman797e71e2013-09-06 17:29:39 -0700193 Mutex done_delaying;
194 ::Time start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700195 volatile bool finished;
Brian Silverman797e71e2013-09-06 17:29:39 -0700196 Mutex ready;
197 };
198 static_assert(shm_ok<Shared>::value,
199 "it's going to get shared between forked processes");
200
201 void Run() {
202 if (action_ == Action::kWaitLockStart) {
203 shared_->ready.Unlock();
204 condition_->m()->Lock();
205 }
206 time::SleepFor(delay_);
207 shared_->start_time = ::Time::Now();
208 shared_->delayed = true;
209 shared_->done_delaying.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700210 if (action_ != Action::kWaitLockStart) {
211 shared_->ready.Unlock();
212 condition_->m()->Lock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700213 }
Brian Silverman2586a5d2013-09-13 13:45:52 -0700214 condition_->Wait();
Brian Silverman797e71e2013-09-06 17:29:39 -0700215 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700216 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700217 condition_->m()->Unlock();
218 }
219 }
220
221 void Join() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700222 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700223 int status;
224 do {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700225 CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700226 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
227 child_ = -1;
228 }
229 void Kill() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700230 CHECK_NE(child_, -1);
231 PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700232 Join();
233 }
234
235 const ::Time delay_;
236 const Action action_;
237 Condition *const condition_;
238 const ::Time timeout_;
239
240 pid_t child_;
241
242 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700243
244 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700245};
246constexpr ::Time ConditionTestProcess::kMinimumDelay;
247constexpr ::Time ConditionTestProcess::kDefaultTimeout;
248
249// Makes sure that the testing framework and everything work for a really simple
250// Wait() and then Signal().
251TEST_F(ConditionTest, Basic) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700252 ConditionTestProcess child(::Time(0, 0),
253 ConditionTestProcess::Action::kWait,
254 &shared_->condition);
255 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700256 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700257 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700258 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700259 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700260}
261
Brian Silverman2586a5d2013-09-13 13:45:52 -0700262// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700263TEST_F(ConditionTest, Locking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700264 ConditionTestProcess child(::Time(0, 0),
265 ConditionTestProcess::Action::kWait,
266 &shared_->condition);
Brian Silverman797e71e2013-09-06 17:29:39 -0700267 shared_->mutex.Lock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700268 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700269 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700270 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700271 // waiting to lock the mutex.
272 shared_->condition.Signal();
273 Settle();
274 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700275 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700276}
277
Brian Silverman2586a5d2013-09-13 13:45:52 -0700278// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700279// unlocked.
280TEST_F(ConditionTest, LockFirst) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700281 ConditionTestProcess child(::Time(0, 0),
282 ConditionTestProcess::Action::kWait,
283 &shared_->condition);
Brian Silverman797e71e2013-09-06 17:29:39 -0700284 shared_->mutex.Lock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700285 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700286 Settle();
287 shared_->condition.Signal();
288 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700289 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700290 shared_->mutex.Unlock();
291 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700292 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700293 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700294 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700295}
296
297// Tests that the mutex gets relocked after Wait() returns.
298TEST_F(ConditionTest, Relocking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700299 ConditionTestProcess child(::Time(0, 0),
300 ConditionTestProcess::Action::kWaitNoUnlock,
301 &shared_->condition);
302 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700303 Settle();
304 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700305 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700306 EXPECT_FALSE(shared_->mutex.TryLock());
307}
308
Brian Silverman2586a5d2013-09-13 13:45:52 -0700309// Tests that Signal() stops exactly 1 Wait()er.
310TEST_F(ConditionTest, SignalOne) {
311 ConditionTestProcess child1(::Time(0, 0),
312 ConditionTestProcess::Action::kWait,
313 &shared_->condition);
314 ConditionTestProcess child2(::Time(0, 0),
315 ConditionTestProcess::Action::kWait,
316 &shared_->condition);
317 ConditionTestProcess child3(::Time(0, 0),
318 ConditionTestProcess::Action::kWait,
319 &shared_->condition);
320 auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
321 (child2.IsFinished() ? 1 : 0) + (child3.IsFinished() ? 1 : 0); };
322 child1.Start();
323 child2.Start();
324 child3.Start();
325 Settle();
326 EXPECT_EQ(0, number_finished());
327 shared_->condition.Signal();
328 Settle();
329 EXPECT_EQ(1, number_finished());
330 shared_->condition.Signal();
331 Settle();
332 EXPECT_EQ(2, number_finished());
333 shared_->condition.Signal();
334 Settle();
335 EXPECT_EQ(3, number_finished());
336 EXPECT_FALSE(child1.Hung());
337 EXPECT_FALSE(child2.Hung());
338 EXPECT_FALSE(child3.Hung());
339}
340
341// Tests that Brodcast() wakes multiple Wait()ers.
342TEST_F(ConditionTest, Broadcast) {
343 ConditionTestProcess child1(::Time(0, 0),
344 ConditionTestProcess::Action::kWait,
345 &shared_->condition);
346 ConditionTestProcess child2(::Time(0, 0),
347 ConditionTestProcess::Action::kWait,
348 &shared_->condition);
349 ConditionTestProcess child3(::Time(0, 0),
350 ConditionTestProcess::Action::kWait,
351 &shared_->condition);
352 child1.Start();
353 child2.Start();
354 child3.Start();
355 Settle();
356 shared_->condition.Broadcast();
357 EXPECT_FALSE(child1.Hung());
358 EXPECT_FALSE(child2.Hung());
359 EXPECT_FALSE(child3.Hung());
360}
361
Brian Silverman797e71e2013-09-06 17:29:39 -0700362} // namespace testing
363} // namespace aos