blob: 0e7bfe477862f84fd051f02b160ba2967c27eda7 [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>
Brian Silverman71c55c52014-08-19 14:31:59 -04008#include <thread>
Brian Silvermanf1194642014-09-04 13:01:17 -04009
Brian Silverman797e71e2013-09-06 17:29:39 -070010#include "gtest/gtest.h"
11
Brian Silverman797e71e2013-09-06 17:29:39 -070012#include "aos/common/time.h"
13#include "aos/common/mutex.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050014#include "aos/testing/test_shm.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070015#include "aos/common/type_traits.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -080016#include "aos/linux_code/ipc_lib/core_lib.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070017#include "aos/common/logging/logging.h"
Brian Silverman2586a5d2013-09-13 13:45:52 -070018#include "aos/common/macros.h"
Brian Silvermandc1eb272014-08-19 14:25:59 -040019#include "aos/linux_code/ipc_lib/aos_sync.h"
Brian Silverman8d2e56e2013-09-23 17:55:03 -070020#include "aos/common/die.h"
Brian Silvermanf1194642014-09-04 13:01:17 -040021#include "aos/common/util/thread.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050022#include "aos/testing/prevent_exit.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070023
24using ::aos::time::Time;
Brian Silverman797e71e2013-09-06 17:29:39 -070025
26namespace aos {
27namespace testing {
28
Brian Silvermanf1194642014-09-04 13:01:17 -040029class ConditionTestCommon : public ::testing::Test {
30 public:
31 ConditionTestCommon() {}
32
33 void Settle() {
34 time::SleepFor(::Time::InSeconds(0.008));
35 }
36
37 private:
38 DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
39};
40
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050041// Some simple tests that don't rely on a TestSharedMemory to help with
Brian Silvermanf1194642014-09-04 13:01:17 -040042// debugging problems that cause tests using that to just completely lock up.
43class SimpleConditionTest : public ConditionTestCommon {
44 public:
45 SimpleConditionTest() : condition_(&mutex_) {}
46
47 Mutex mutex_;
48 Condition condition_;
49
50 private:
51 DISALLOW_COPY_AND_ASSIGN(SimpleConditionTest);
52};
53
54// Makes sure that nothing crashes or anything with a basic Wait() and then
55// Signal().
56// This test is written to hopefully fail instead of deadlocking on failure, but
57// it's tricky because there's no way to kill the child in the middle.
58TEST_F(SimpleConditionTest, Basic) {
59 ::std::atomic_bool child_finished(false);
60 Condition child_ready(&mutex_);
61 ASSERT_FALSE(mutex_.Lock());
62 util::FunctionThread child([this, &child_finished, &child_ready](
63 util::FunctionThread *) {
64 ASSERT_FALSE(mutex_.Lock());
65 child_ready.Broadcast();
66 ASSERT_FALSE(condition_.Wait());
67 child_finished.store(true);
68 mutex_.Unlock();
69 });
70 child.Start();
71 ASSERT_FALSE(child_ready.Wait());
72 EXPECT_FALSE(child_finished.load());
73 condition_.Signal();
74 mutex_.Unlock();
75 child.Join();
76 EXPECT_TRUE(child_finished.load());
77}
78
Brian Silverman71c55c52014-08-19 14:31:59 -040079// Tests that contention on the associated mutex doesn't break anything.
80// This seems likely to cause issues with AddressSanitizer in particular.
81TEST_F(SimpleConditionTest, MutexContention) {
82 for (int i = 0; i < 1000; ++i) {
83 ASSERT_FALSE(mutex_.Lock());
84 ::std::thread thread([this]() {
85 ASSERT_FALSE(mutex_.Lock());
86 condition_.Signal();
87 mutex_.Unlock();
88 });
89 ASSERT_FALSE(condition_.Wait());
90 mutex_.Unlock();
91 thread.join();
92 }
93}
94
Brian Silvermanf1194642014-09-04 13:01:17 -040095class ConditionTest : public ConditionTestCommon {
Brian Silverman797e71e2013-09-06 17:29:39 -070096 public:
97 struct Shared {
98 Shared() : condition(&mutex) {}
99
100 Mutex mutex;
101 Condition condition;
102 };
103 static_assert(shm_ok<Shared>::value,
104 "it's going to get shared between forked processes");
105
106 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
107 new (shared_) Shared();
108 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400109 ~ConditionTest() {
110 shared_->~Shared();
111 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700112
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500113 ::aos::testing::TestSharedMemory my_shm_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700114
115 Shared *const shared_;
116
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700117 protected:
118 void SetUp() override {
119 SetDieTestMode(true);
120 }
121
Brian Silverman2586a5d2013-09-13 13:45:52 -0700122 private:
123 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700124};
125
126class ConditionTestProcess {
127 public:
128 enum class Action {
129 kWaitLockStart, // lock, delay, wait, unlock
130 kWait, // delay, lock, wait, unlock
131 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700132 };
133
134 // This amount gets added to any passed in delay to make the test repeatable.
Brian Silvermandc1eb272014-08-19 14:25:59 -0400135 static constexpr ::Time kMinimumDelay = ::Time::InSeconds(0.15);
136 static constexpr ::Time kDefaultTimeout = ::Time::InSeconds(0.15);
Brian Silverman797e71e2013-09-06 17:29:39 -0700137
138 // delay is how long to wait before doing action to condition.
139 // timeout is how long to wait after delay before deciding that it's hung.
140 ConditionTestProcess(const ::Time &delay, Action action, Condition *condition,
141 const ::Time &timeout = kDefaultTimeout)
142 : delay_(kMinimumDelay + delay), action_(action), condition_(condition),
143 timeout_(delay_ + timeout), child_(-1),
144 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
145 new (shared_) Shared();
146 }
147 ~ConditionTestProcess() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700148 CHECK_EQ(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700149 }
150
151 void Start() {
152 ASSERT_FALSE(shared_->started);
153
154 child_ = fork();
155 if (child_ == 0) { // in child
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500156 ::aos::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700157 Run();
158 exit(EXIT_SUCCESS);
159 } else { // in parent
Brian Silvermanfe457de2014-05-26 22:04:08 -0700160 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700161
Brian Silvermandc1eb272014-08-19 14:25:59 -0400162 ASSERT_EQ(0, futex_wait(&shared_->ready));
Brian Silverman797e71e2013-09-06 17:29:39 -0700163
164 shared_->started = true;
165 }
166 }
167
168 bool IsFinished() {
169 return shared_->finished;
170 }
171
172 ::testing::AssertionResult Hung() {
173 if (!shared_->started) {
174 ADD_FAILURE();
175 return ::testing::AssertionFailure() << "not started yet";
176 }
177 if (shared_->finished) {
178 Join();
179 return ::testing::AssertionFailure() << "already returned";
180 }
181 if (shared_->delayed) {
182 if (shared_->start_time > ::Time::Now() + timeout_) {
183 Kill();
184 return ::testing::AssertionSuccess() << "already been too long";
185 }
186 } else {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400187 CHECK_EQ(0, futex_wait(&shared_->done_delaying));
Brian Silverman797e71e2013-09-06 17:29:39 -0700188 }
189 time::SleepFor(::Time::InSeconds(0.01));
190 if (!shared_->finished) time::SleepUntil(shared_->start_time + timeout_);
191 if (shared_->finished) {
192 Join();
193 return ::testing::AssertionFailure() << "completed within timeout";
194 } else {
195 Kill();
196 return ::testing::AssertionSuccess() << "took too long";
197 }
198 }
199 ::testing::AssertionResult Test() {
200 Start();
201 return Hung();
202 }
203
204 private:
205 struct Shared {
206 Shared()
Brian Silvermandc1eb272014-08-19 14:25:59 -0400207 : started(false), delayed(false), done_delaying(0), start_time(0, 0),
208 finished(false), ready(0) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700209 }
210
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700211 volatile bool started;
212 volatile bool delayed;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400213 aos_futex done_delaying;
Brian Silverman797e71e2013-09-06 17:29:39 -0700214 ::Time start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700215 volatile bool finished;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400216 aos_futex ready;
Brian Silverman797e71e2013-09-06 17:29:39 -0700217 };
218 static_assert(shm_ok<Shared>::value,
219 "it's going to get shared between forked processes");
220
221 void Run() {
222 if (action_ == Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400223 ASSERT_EQ(1, futex_set(&shared_->ready));
224 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700225 }
226 time::SleepFor(delay_);
227 shared_->start_time = ::Time::Now();
228 shared_->delayed = true;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400229 ASSERT_NE(-1, futex_set(&shared_->done_delaying));
Brian Silverman2586a5d2013-09-13 13:45:52 -0700230 if (action_ != Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400231 ASSERT_EQ(1, futex_set(&shared_->ready));
232 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700233 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400234 // TODO(brians): Test this returning true (aka the owner dying).
235 ASSERT_FALSE(condition_->Wait());
Brian Silverman797e71e2013-09-06 17:29:39 -0700236 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700237 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700238 condition_->m()->Unlock();
239 }
240 }
241
242 void Join() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700243 CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700244 int status;
245 do {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700246 CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700247 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
248 child_ = -1;
249 }
250 void Kill() {
Brian Silvermanfe457de2014-05-26 22:04:08 -0700251 CHECK_NE(child_, -1);
252 PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700253 Join();
254 }
255
256 const ::Time delay_;
257 const Action action_;
258 Condition *const condition_;
259 const ::Time timeout_;
260
261 pid_t child_;
262
263 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700264
265 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700266};
267constexpr ::Time ConditionTestProcess::kMinimumDelay;
268constexpr ::Time ConditionTestProcess::kDefaultTimeout;
269
270// Makes sure that the testing framework and everything work for a really simple
271// Wait() and then Signal().
272TEST_F(ConditionTest, Basic) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700273 ConditionTestProcess child(::Time(0, 0),
274 ConditionTestProcess::Action::kWait,
275 &shared_->condition);
276 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700277 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700278 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700279 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700280 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700281}
282
Brian Silverman2586a5d2013-09-13 13:45:52 -0700283// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700284TEST_F(ConditionTest, Locking) {
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();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700291 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700292 // waiting to lock the mutex.
293 shared_->condition.Signal();
294 Settle();
295 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700296 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700297}
298
Brian Silverman2586a5d2013-09-13 13:45:52 -0700299// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700300// unlocked.
301TEST_F(ConditionTest, LockFirst) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700302 ConditionTestProcess child(::Time(0, 0),
303 ConditionTestProcess::Action::kWait,
304 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400305 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700306 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700307 Settle();
308 shared_->condition.Signal();
309 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700310 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700311 shared_->mutex.Unlock();
312 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700313 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700314 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700315 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700316}
317
318// Tests that the mutex gets relocked after Wait() returns.
319TEST_F(ConditionTest, Relocking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700320 ConditionTestProcess child(::Time(0, 0),
321 ConditionTestProcess::Action::kWaitNoUnlock,
322 &shared_->condition);
323 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700324 Settle();
325 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700326 EXPECT_FALSE(child.Hung());
Brian Silverman71c55c52014-08-19 14:31:59 -0400327 EXPECT_EQ(Mutex::State::kOwnerDied, shared_->mutex.TryLock());
328 shared_->mutex.Unlock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700329}
330
Brian Silverman2586a5d2013-09-13 13:45:52 -0700331// Tests that Signal() stops exactly 1 Wait()er.
332TEST_F(ConditionTest, SignalOne) {
333 ConditionTestProcess child1(::Time(0, 0),
334 ConditionTestProcess::Action::kWait,
335 &shared_->condition);
336 ConditionTestProcess child2(::Time(0, 0),
337 ConditionTestProcess::Action::kWait,
338 &shared_->condition);
339 ConditionTestProcess child3(::Time(0, 0),
340 ConditionTestProcess::Action::kWait,
341 &shared_->condition);
342 auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
343 (child2.IsFinished() ? 1 : 0) + (child3.IsFinished() ? 1 : 0); };
344 child1.Start();
345 child2.Start();
346 child3.Start();
347 Settle();
348 EXPECT_EQ(0, number_finished());
349 shared_->condition.Signal();
350 Settle();
351 EXPECT_EQ(1, number_finished());
352 shared_->condition.Signal();
353 Settle();
354 EXPECT_EQ(2, number_finished());
355 shared_->condition.Signal();
356 Settle();
357 EXPECT_EQ(3, number_finished());
358 EXPECT_FALSE(child1.Hung());
359 EXPECT_FALSE(child2.Hung());
360 EXPECT_FALSE(child3.Hung());
361}
362
363// Tests that Brodcast() wakes multiple Wait()ers.
364TEST_F(ConditionTest, Broadcast) {
365 ConditionTestProcess child1(::Time(0, 0),
366 ConditionTestProcess::Action::kWait,
367 &shared_->condition);
368 ConditionTestProcess child2(::Time(0, 0),
369 ConditionTestProcess::Action::kWait,
370 &shared_->condition);
371 ConditionTestProcess child3(::Time(0, 0),
372 ConditionTestProcess::Action::kWait,
373 &shared_->condition);
374 child1.Start();
375 child2.Start();
376 child3.Start();
377 Settle();
378 shared_->condition.Broadcast();
379 EXPECT_FALSE(child1.Hung());
380 EXPECT_FALSE(child2.Hung());
381 EXPECT_FALSE(child3.Hung());
382}
383
Brian Silverman797e71e2013-09-06 17:29:39 -0700384} // namespace testing
385} // namespace aos