blob: 2310273b210fbce1ea645306b28fed2b4711f5c2 [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 Silvermandc1eb272014-08-19 14:25:59 -040018#include "aos/linux_code/ipc_lib/aos_sync.h"
Brian Silverman8d2e56e2013-09-23 17:55:03 -070019#include "aos/common/die.h"
Brian Silvermanf1194642014-09-04 13:01:17 -040020#include "aos/common/util/thread.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070021
22using ::aos::time::Time;
23using ::aos::common::testing::GlobalCoreInstance;
24
25namespace aos {
26namespace testing {
27
Brian Silvermanf1194642014-09-04 13:01:17 -040028class ConditionTestCommon : public ::testing::Test {
29 public:
30 ConditionTestCommon() {}
31
32 void Settle() {
33 time::SleepFor(::Time::InSeconds(0.008));
34 }
35
36 private:
37 DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
38};
39
40// Some simple tests that don't rely on a GlobalCoreInstance to help with
41// debugging problems that cause tests using that to just completely lock up.
42class SimpleConditionTest : public ConditionTestCommon {
43 public:
44 SimpleConditionTest() : condition_(&mutex_) {}
45
46 Mutex mutex_;
47 Condition condition_;
48
49 private:
50 DISALLOW_COPY_AND_ASSIGN(SimpleConditionTest);
51};
52
53// Makes sure that nothing crashes or anything with a basic Wait() and then
54// Signal().
55// This test is written to hopefully fail instead of deadlocking on failure, but
56// it's tricky because there's no way to kill the child in the middle.
57TEST_F(SimpleConditionTest, Basic) {
58 ::std::atomic_bool child_finished(false);
59 Condition child_ready(&mutex_);
60 ASSERT_FALSE(mutex_.Lock());
61 util::FunctionThread child([this, &child_finished, &child_ready](
62 util::FunctionThread *) {
63 ASSERT_FALSE(mutex_.Lock());
64 child_ready.Broadcast();
65 ASSERT_FALSE(condition_.Wait());
66 child_finished.store(true);
67 mutex_.Unlock();
68 });
69 child.Start();
70 ASSERT_FALSE(child_ready.Wait());
71 EXPECT_FALSE(child_finished.load());
72 condition_.Signal();
73 mutex_.Unlock();
74 child.Join();
75 EXPECT_TRUE(child_finished.load());
76}
77
78class ConditionTest : public ConditionTestCommon {
Brian Silverman797e71e2013-09-06 17:29:39 -070079 public:
80 struct Shared {
81 Shared() : condition(&mutex) {}
82
83 Mutex mutex;
84 Condition condition;
85 };
86 static_assert(shm_ok<Shared>::value,
87 "it's going to get shared between forked processes");
88
89 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
90 new (shared_) Shared();
91 }
Brian Silvermandc1eb272014-08-19 14:25:59 -040092 ~ConditionTest() {
93 shared_->~Shared();
94 }
Brian Silverman797e71e2013-09-06 17:29:39 -070095
96 GlobalCoreInstance my_core;
97
98 Shared *const shared_;
99
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700100 protected:
101 void SetUp() override {
102 SetDieTestMode(true);
103 }
104
Brian Silverman2586a5d2013-09-13 13:45:52 -0700105 private:
106 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700107};
108
109class ConditionTestProcess {
110 public:
111 enum class Action {
112 kWaitLockStart, // lock, delay, wait, unlock
113 kWait, // delay, lock, wait, unlock
114 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700115 };
116
117 // This amount gets added to any passed in delay to make the test repeatable.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400118 static constexpr ::Time kMinimumDelay = ::Time::InSeconds(0.15);
119 static constexpr ::Time kDefaultTimeout = ::Time::InSeconds(0.15);
Brian Silverman797e71e2013-09-06 17:29:39 -0700120
121 // delay is how long to wait before doing action to condition.
122 // timeout is how long to wait after delay before deciding that it's hung.
123 ConditionTestProcess(const ::Time &delay, Action action, Condition *condition,
124 const ::Time &timeout = kDefaultTimeout)
125 : delay_(kMinimumDelay + delay), action_(action), condition_(condition),
126 timeout_(delay_ + timeout), child_(-1),
127 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
128 new (shared_) Shared();
129 }
130 ~ConditionTestProcess() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700131 CHECK_EQ(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700132 }
133
134 void Start() {
135 ASSERT_FALSE(shared_->started);
136
137 child_ = fork();
138 if (child_ == 0) { // in child
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700139 ::aos::common::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700140 Run();
141 exit(EXIT_SUCCESS);
142 } else { // in parent
Brian Silvermanfe457de2014-05-26 22:04:08 -0700143 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700144
Brian Silvermandc1eb272014-08-19 14:25:59 -0400145 ASSERT_EQ(0, futex_wait(&shared_->ready));
Brian Silverman797e71e2013-09-06 17:29:39 -0700146
147 shared_->started = true;
148 }
149 }
150
151 bool IsFinished() {
152 return shared_->finished;
153 }
154
155 ::testing::AssertionResult Hung() {
156 if (!shared_->started) {
157 ADD_FAILURE();
158 return ::testing::AssertionFailure() << "not started yet";
159 }
160 if (shared_->finished) {
161 Join();
162 return ::testing::AssertionFailure() << "already returned";
163 }
164 if (shared_->delayed) {
165 if (shared_->start_time > ::Time::Now() + timeout_) {
166 Kill();
167 return ::testing::AssertionSuccess() << "already been too long";
168 }
169 } else {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400170 CHECK_EQ(0, futex_wait(&shared_->done_delaying));
Brian Silverman797e71e2013-09-06 17:29:39 -0700171 }
172 time::SleepFor(::Time::InSeconds(0.01));
173 if (!shared_->finished) time::SleepUntil(shared_->start_time + timeout_);
174 if (shared_->finished) {
175 Join();
176 return ::testing::AssertionFailure() << "completed within timeout";
177 } else {
178 Kill();
179 return ::testing::AssertionSuccess() << "took too long";
180 }
181 }
182 ::testing::AssertionResult Test() {
183 Start();
184 return Hung();
185 }
186
187 private:
188 struct Shared {
189 Shared()
Brian Silvermandc1eb272014-08-19 14:25:59 -0400190 : started(false), delayed(false), done_delaying(0), start_time(0, 0),
191 finished(false), ready(0) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700192 }
193
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700194 volatile bool started;
195 volatile bool delayed;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400196 aos_futex done_delaying;
Brian Silverman797e71e2013-09-06 17:29:39 -0700197 ::Time start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700198 volatile bool finished;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400199 aos_futex ready;
Brian Silverman797e71e2013-09-06 17:29:39 -0700200 };
201 static_assert(shm_ok<Shared>::value,
202 "it's going to get shared between forked processes");
203
204 void Run() {
205 if (action_ == Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400206 ASSERT_EQ(1, futex_set(&shared_->ready));
207 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700208 }
209 time::SleepFor(delay_);
210 shared_->start_time = ::Time::Now();
211 shared_->delayed = true;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400212 ASSERT_NE(-1, futex_set(&shared_->done_delaying));
Brian Silverman2586a5d2013-09-13 13:45:52 -0700213 if (action_ != Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400214 ASSERT_EQ(1, futex_set(&shared_->ready));
215 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700216 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400217 // TODO(brians): Test this returning true (aka the owner dying).
218 ASSERT_FALSE(condition_->Wait());
Brian Silverman797e71e2013-09-06 17:29:39 -0700219 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700220 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700221 condition_->m()->Unlock();
222 }
223 }
224
225 void Join() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700226 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700227 int status;
228 do {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700229 CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700230 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
231 child_ = -1;
232 }
233 void Kill() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700234 CHECK_NE(child_, -1);
235 PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700236 Join();
237 }
238
239 const ::Time delay_;
240 const Action action_;
241 Condition *const condition_;
242 const ::Time timeout_;
243
244 pid_t child_;
245
246 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700247
248 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700249};
250constexpr ::Time ConditionTestProcess::kMinimumDelay;
251constexpr ::Time ConditionTestProcess::kDefaultTimeout;
252
253// Makes sure that the testing framework and everything work for a really simple
254// Wait() and then Signal().
255TEST_F(ConditionTest, Basic) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700256 ConditionTestProcess child(::Time(0, 0),
257 ConditionTestProcess::Action::kWait,
258 &shared_->condition);
259 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700260 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700261 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700262 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700263 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700264}
265
Brian Silverman2586a5d2013-09-13 13:45:52 -0700266// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700267TEST_F(ConditionTest, Locking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700268 ConditionTestProcess child(::Time(0, 0),
269 ConditionTestProcess::Action::kWait,
270 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400271 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700272 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700273 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700274 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700275 // waiting to lock the mutex.
276 shared_->condition.Signal();
277 Settle();
278 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700279 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700280}
281
Brian Silverman2586a5d2013-09-13 13:45:52 -0700282// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700283// unlocked.
284TEST_F(ConditionTest, LockFirst) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700285 ConditionTestProcess child(::Time(0, 0),
286 ConditionTestProcess::Action::kWait,
287 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400288 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700289 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700290 Settle();
291 shared_->condition.Signal();
292 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700293 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700294 shared_->mutex.Unlock();
295 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700296 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700297 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700298 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700299}
300
301// Tests that the mutex gets relocked after Wait() returns.
302TEST_F(ConditionTest, Relocking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700303 ConditionTestProcess child(::Time(0, 0),
304 ConditionTestProcess::Action::kWaitNoUnlock,
305 &shared_->condition);
306 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700307 Settle();
308 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700309 EXPECT_FALSE(child.Hung());
Daniel Petti88a15662015-04-12 17:42:22 -0400310 EXPECT_EQ(Mutex::State::kLockFailed, shared_->mutex.TryLock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700311}
312
Brian Silverman2586a5d2013-09-13 13:45:52 -0700313// Tests that Signal() stops exactly 1 Wait()er.
314TEST_F(ConditionTest, SignalOne) {
315 ConditionTestProcess child1(::Time(0, 0),
316 ConditionTestProcess::Action::kWait,
317 &shared_->condition);
318 ConditionTestProcess child2(::Time(0, 0),
319 ConditionTestProcess::Action::kWait,
320 &shared_->condition);
321 ConditionTestProcess child3(::Time(0, 0),
322 ConditionTestProcess::Action::kWait,
323 &shared_->condition);
324 auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
325 (child2.IsFinished() ? 1 : 0) + (child3.IsFinished() ? 1 : 0); };
326 child1.Start();
327 child2.Start();
328 child3.Start();
329 Settle();
330 EXPECT_EQ(0, number_finished());
331 shared_->condition.Signal();
332 Settle();
333 EXPECT_EQ(1, number_finished());
334 shared_->condition.Signal();
335 Settle();
336 EXPECT_EQ(2, number_finished());
337 shared_->condition.Signal();
338 Settle();
339 EXPECT_EQ(3, number_finished());
340 EXPECT_FALSE(child1.Hung());
341 EXPECT_FALSE(child2.Hung());
342 EXPECT_FALSE(child3.Hung());
343}
344
345// Tests that Brodcast() wakes multiple Wait()ers.
346TEST_F(ConditionTest, Broadcast) {
347 ConditionTestProcess child1(::Time(0, 0),
348 ConditionTestProcess::Action::kWait,
349 &shared_->condition);
350 ConditionTestProcess child2(::Time(0, 0),
351 ConditionTestProcess::Action::kWait,
352 &shared_->condition);
353 ConditionTestProcess child3(::Time(0, 0),
354 ConditionTestProcess::Action::kWait,
355 &shared_->condition);
356 child1.Start();
357 child2.Start();
358 child3.Start();
359 Settle();
360 shared_->condition.Broadcast();
361 EXPECT_FALSE(child1.Hung());
362 EXPECT_FALSE(child2.Hung());
363 EXPECT_FALSE(child3.Hung());
364}
365
Brian Silverman797e71e2013-09-06 17:29:39 -0700366} // namespace testing
367} // namespace aos