blob: 15b948e7e89f04638f626794ba9c4bcee4df8a5d [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/condition.h"
Brian Silverman797e71e2013-09-06 17:29:39 -07002
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>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08008#include <chrono>
Brian Silverman71c55c52014-08-19 14:31:59 -04009#include <thread>
Brian Silvermanf1194642014-09-04 13:01:17 -040010
Brian Silverman797e71e2013-09-06 17:29:39 -070011#include "gtest/gtest.h"
12
John Park33858a32018-09-28 23:05:48 -070013#include "aos/time/time.h"
14#include "aos/mutex/mutex.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050015#include "aos/testing/test_shm.h"
John Park33858a32018-09-28 23:05:48 -070016#include "aos/type_traits/type_traits.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -080017#include "aos/linux_code/ipc_lib/core_lib.h"
John Park33858a32018-09-28 23:05:48 -070018#include "aos/logging/logging.h"
19#include "aos/macros.h"
Brian Silvermandc1eb272014-08-19 14:25:59 -040020#include "aos/linux_code/ipc_lib/aos_sync.h"
John Park33858a32018-09-28 23:05:48 -070021#include "aos/die.h"
22#include "aos/util/thread.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050023#include "aos/testing/prevent_exit.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070024
Brian Silverman797e71e2013-09-06 17:29:39 -070025namespace aos {
26namespace testing {
27
Austin Schuhf2a50ba2016-12-24 16:16:26 -080028namespace chrono = ::std::chrono;
29
Brian Silvermanf1194642014-09-04 13:01:17 -040030class ConditionTestCommon : public ::testing::Test {
31 public:
32 ConditionTestCommon() {}
33
Austin Schuhf2a50ba2016-12-24 16:16:26 -080034 void Settle() { ::std::this_thread::sleep_for(chrono::milliseconds(8)); }
Brian Silvermanf1194642014-09-04 13:01:17 -040035
36 private:
37 DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
38};
39
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050040// Some simple tests that don't rely on a TestSharedMemory to help with
Brian Silvermanf1194642014-09-04 13:01:17 -040041// 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
Brian Silverman71c55c52014-08-19 14:31:59 -040078// Tests that contention on the associated mutex doesn't break anything.
79// This seems likely to cause issues with AddressSanitizer in particular.
80TEST_F(SimpleConditionTest, MutexContention) {
81 for (int i = 0; i < 1000; ++i) {
82 ASSERT_FALSE(mutex_.Lock());
83 ::std::thread thread([this]() {
84 ASSERT_FALSE(mutex_.Lock());
85 condition_.Signal();
86 mutex_.Unlock();
87 });
88 ASSERT_FALSE(condition_.Wait());
89 mutex_.Unlock();
90 thread.join();
91 }
92}
93
Brian Silvermanf1194642014-09-04 13:01:17 -040094class ConditionTest : public ConditionTestCommon {
Brian Silverman797e71e2013-09-06 17:29:39 -070095 public:
96 struct Shared {
97 Shared() : condition(&mutex) {}
98
99 Mutex mutex;
100 Condition condition;
101 };
102 static_assert(shm_ok<Shared>::value,
103 "it's going to get shared between forked processes");
104
105 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
106 new (shared_) Shared();
107 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400108 ~ConditionTest() {
109 shared_->~Shared();
110 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700111
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500112 ::aos::testing::TestSharedMemory my_shm_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700113
114 Shared *const shared_;
115
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700116 protected:
117 void SetUp() override {
118 SetDieTestMode(true);
119 }
120
Brian Silverman2586a5d2013-09-13 13:45:52 -0700121 private:
122 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700123};
124
125class ConditionTestProcess {
126 public:
127 enum class Action {
128 kWaitLockStart, // lock, delay, wait, unlock
129 kWait, // delay, lock, wait, unlock
130 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700131 };
132
133 // This amount gets added to any passed in delay to make the test repeatable.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800134 static constexpr chrono::milliseconds kMinimumDelay =
135 chrono::milliseconds(150);
136 static constexpr chrono::milliseconds kDefaultTimeout =
137 chrono::milliseconds(150);
Brian Silverman797e71e2013-09-06 17:29:39 -0700138
139 // delay is how long to wait before doing action to condition.
140 // timeout is how long to wait after delay before deciding that it's hung.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800141 ConditionTestProcess(chrono::milliseconds delay, Action action,
142 Condition *condition,
143 chrono::milliseconds timeout = kDefaultTimeout)
144 : delay_(kMinimumDelay + delay),
145 action_(action),
146 condition_(condition),
147 timeout_(delay_ + timeout),
148 child_(-1),
149 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700150 new (shared_) Shared();
151 }
152 ~ConditionTestProcess() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700153 CHECK_EQ(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700154 }
155
156 void Start() {
157 ASSERT_FALSE(shared_->started);
158
159 child_ = fork();
160 if (child_ == 0) { // in child
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500161 ::aos::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700162 Run();
163 exit(EXIT_SUCCESS);
164 } else { // in parent
Brian Silvermanfe457de2014-05-26 22:04:08 -0700165 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700166
Brian Silvermandc1eb272014-08-19 14:25:59 -0400167 ASSERT_EQ(0, futex_wait(&shared_->ready));
Brian Silverman797e71e2013-09-06 17:29:39 -0700168
169 shared_->started = true;
170 }
171 }
172
173 bool IsFinished() {
174 return shared_->finished;
175 }
176
177 ::testing::AssertionResult Hung() {
178 if (!shared_->started) {
179 ADD_FAILURE();
180 return ::testing::AssertionFailure() << "not started yet";
181 }
182 if (shared_->finished) {
183 Join();
184 return ::testing::AssertionFailure() << "already returned";
185 }
186 if (shared_->delayed) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800187 if (shared_->start_time > monotonic_clock::now() + timeout_) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700188 Kill();
189 return ::testing::AssertionSuccess() << "already been too long";
190 }
191 } else {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400192 CHECK_EQ(0, futex_wait(&shared_->done_delaying));
Brian Silverman797e71e2013-09-06 17:29:39 -0700193 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800194 ::std::this_thread::sleep_for(chrono::milliseconds(10));
195 if (!shared_->finished) {
196 ::std::this_thread::sleep_until(shared_->start_time + timeout_);
197 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700198 if (shared_->finished) {
199 Join();
200 return ::testing::AssertionFailure() << "completed within timeout";
201 } else {
202 Kill();
203 return ::testing::AssertionSuccess() << "took too long";
204 }
205 }
206 ::testing::AssertionResult Test() {
207 Start();
208 return Hung();
209 }
210
211 private:
212 struct Shared {
213 Shared()
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800214 : started(false),
215 delayed(false),
216 done_delaying(0),
217 start_time(monotonic_clock::epoch()),
218 finished(false),
219 ready(0) {}
Brian Silverman797e71e2013-09-06 17:29:39 -0700220
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700221 volatile bool started;
222 volatile bool delayed;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400223 aos_futex done_delaying;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800224 monotonic_clock::time_point start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700225 volatile bool finished;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400226 aos_futex ready;
Brian Silverman797e71e2013-09-06 17:29:39 -0700227 };
228 static_assert(shm_ok<Shared>::value,
229 "it's going to get shared between forked processes");
230
231 void Run() {
232 if (action_ == Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400233 ASSERT_EQ(1, futex_set(&shared_->ready));
234 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700235 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800236 ::std::this_thread::sleep_for(delay_);
237 shared_->start_time = monotonic_clock::now();
Brian Silverman797e71e2013-09-06 17:29:39 -0700238 shared_->delayed = true;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400239 ASSERT_NE(-1, futex_set(&shared_->done_delaying));
Brian Silverman2586a5d2013-09-13 13:45:52 -0700240 if (action_ != Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400241 ASSERT_EQ(1, futex_set(&shared_->ready));
242 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700243 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400244 // TODO(brians): Test this returning true (aka the owner dying).
245 ASSERT_FALSE(condition_->Wait());
Brian Silverman797e71e2013-09-06 17:29:39 -0700246 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700247 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700248 condition_->m()->Unlock();
249 }
250 }
251
252 void Join() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700253 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700254 int status;
255 do {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700256 CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700257 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
258 child_ = -1;
259 }
260 void Kill() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700261 CHECK_NE(child_, -1);
262 PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700263 Join();
264 }
265
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800266 const chrono::milliseconds delay_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700267 const Action action_;
268 Condition *const condition_;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800269 const chrono::milliseconds timeout_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700270
271 pid_t child_;
272
273 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700274
275 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700276};
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800277constexpr chrono::milliseconds ConditionTestProcess::kMinimumDelay;
278constexpr chrono::milliseconds ConditionTestProcess::kDefaultTimeout;
Brian Silverman797e71e2013-09-06 17:29:39 -0700279
280// Makes sure that the testing framework and everything work for a really simple
281// Wait() and then Signal().
282TEST_F(ConditionTest, Basic) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800283 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700284 ConditionTestProcess::Action::kWait,
285 &shared_->condition);
286 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700287 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700288 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700289 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700290 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700291}
292
Brian Silverman2586a5d2013-09-13 13:45:52 -0700293// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700294TEST_F(ConditionTest, Locking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800295 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700296 ConditionTestProcess::Action::kWait,
297 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400298 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700299 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700300 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700301 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700302 // waiting to lock the mutex.
303 shared_->condition.Signal();
304 Settle();
305 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700306 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700307}
308
Brian Silverman2586a5d2013-09-13 13:45:52 -0700309// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700310// unlocked.
311TEST_F(ConditionTest, LockFirst) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800312 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700313 ConditionTestProcess::Action::kWait,
314 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400315 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700316 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700317 Settle();
318 shared_->condition.Signal();
319 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700320 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700321 shared_->mutex.Unlock();
322 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700323 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700324 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700325 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700326}
327
328// Tests that the mutex gets relocked after Wait() returns.
329TEST_F(ConditionTest, Relocking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800330 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700331 ConditionTestProcess::Action::kWaitNoUnlock,
332 &shared_->condition);
333 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700334 Settle();
335 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700336 EXPECT_FALSE(child.Hung());
Brian Silverman71c55c52014-08-19 14:31:59 -0400337 EXPECT_EQ(Mutex::State::kOwnerDied, shared_->mutex.TryLock());
338 shared_->mutex.Unlock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700339}
340
Brian Silverman2586a5d2013-09-13 13:45:52 -0700341// Tests that Signal() stops exactly 1 Wait()er.
342TEST_F(ConditionTest, SignalOne) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800343 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700344 ConditionTestProcess::Action::kWait,
345 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800346 ConditionTestProcess child2(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700347 ConditionTestProcess::Action::kWait,
348 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800349 ConditionTestProcess child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700350 ConditionTestProcess::Action::kWait,
351 &shared_->condition);
352 auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
353 (child2.IsFinished() ? 1 : 0) + (child3.IsFinished() ? 1 : 0); };
354 child1.Start();
355 child2.Start();
356 child3.Start();
357 Settle();
358 EXPECT_EQ(0, number_finished());
359 shared_->condition.Signal();
360 Settle();
361 EXPECT_EQ(1, number_finished());
362 shared_->condition.Signal();
363 Settle();
364 EXPECT_EQ(2, number_finished());
365 shared_->condition.Signal();
366 Settle();
367 EXPECT_EQ(3, number_finished());
368 EXPECT_FALSE(child1.Hung());
369 EXPECT_FALSE(child2.Hung());
370 EXPECT_FALSE(child3.Hung());
371}
372
373// Tests that Brodcast() wakes multiple Wait()ers.
374TEST_F(ConditionTest, Broadcast) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800375 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700376 ConditionTestProcess::Action::kWait,
377 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800378 ConditionTestProcess child2(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700379 ConditionTestProcess::Action::kWait,
380 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800381 ConditionTestProcess child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700382 ConditionTestProcess::Action::kWait,
383 &shared_->condition);
384 child1.Start();
385 child2.Start();
386 child3.Start();
387 Settle();
388 shared_->condition.Broadcast();
389 EXPECT_FALSE(child1.Hung());
390 EXPECT_FALSE(child2.Hung());
391 EXPECT_FALSE(child3.Hung());
392}
393
Brian Silverman797e71e2013-09-06 17:29:39 -0700394} // namespace testing
395} // namespace aos