blob: b49f27ce4ac75e05b4ac6eb607521abb59e59f2e [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"
John Park398c74a2018-10-20 21:17:39 -070017#include "aos/ipc_lib/core_lib.h"
John Park33858a32018-09-28 23:05:48 -070018#include "aos/logging/logging.h"
19#include "aos/macros.h"
John Park398c74a2018-10-20 21:17:39 -070020#include "aos/ipc_lib/aos_sync.h"
John Park33858a32018-09-28 23:05:48 -070021#include "aos/die.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050022#include "aos/testing/prevent_exit.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070023
Brian Silverman797e71e2013-09-06 17:29:39 -070024namespace aos {
25namespace testing {
26
Austin Schuhf2a50ba2016-12-24 16:16:26 -080027namespace chrono = ::std::chrono;
28
Brian Silvermanf1194642014-09-04 13:01:17 -040029class ConditionTestCommon : public ::testing::Test {
30 public:
31 ConditionTestCommon() {}
32
Austin Schuhf2a50ba2016-12-24 16:16:26 -080033 void Settle() { ::std::this_thread::sleep_for(chrono::milliseconds(8)); }
Brian Silvermanf1194642014-09-04 13:01:17 -040034
35 private:
36 DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
37};
38
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050039// Some simple tests that don't rely on a TestSharedMemory to help with
Brian Silvermanf1194642014-09-04 13:01:17 -040040// 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());
Kai Tinkessbf1385d2020-01-18 14:18:49 -080060 std::thread child([this, &child_finished, &child_ready] {
Brian Silvermanf1194642014-09-04 13:01:17 -040061 ASSERT_FALSE(mutex_.Lock());
62 child_ready.Broadcast();
63 ASSERT_FALSE(condition_.Wait());
64 child_finished.store(true);
65 mutex_.Unlock();
66 });
Brian Silvermanf1194642014-09-04 13:01:17 -040067 ASSERT_FALSE(child_ready.Wait());
68 EXPECT_FALSE(child_finished.load());
69 condition_.Signal();
70 mutex_.Unlock();
Kai Tinkessbf1385d2020-01-18 14:18:49 -080071 child.join();
Brian Silvermanf1194642014-09-04 13:01:17 -040072 EXPECT_TRUE(child_finished.load());
73}
74
Brian Silverman71c55c52014-08-19 14:31:59 -040075// Tests that contention on the associated mutex doesn't break anything.
76// This seems likely to cause issues with AddressSanitizer in particular.
77TEST_F(SimpleConditionTest, MutexContention) {
78 for (int i = 0; i < 1000; ++i) {
79 ASSERT_FALSE(mutex_.Lock());
80 ::std::thread thread([this]() {
81 ASSERT_FALSE(mutex_.Lock());
82 condition_.Signal();
83 mutex_.Unlock();
84 });
85 ASSERT_FALSE(condition_.Wait());
86 mutex_.Unlock();
87 thread.join();
88 }
89}
90
Brian Silvermanf1194642014-09-04 13:01:17 -040091class ConditionTest : public ConditionTestCommon {
Brian Silverman797e71e2013-09-06 17:29:39 -070092 public:
93 struct Shared {
94 Shared() : condition(&mutex) {}
95
96 Mutex mutex;
97 Condition condition;
98 };
99 static_assert(shm_ok<Shared>::value,
100 "it's going to get shared between forked processes");
101
102 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
103 new (shared_) Shared();
104 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400105 ~ConditionTest() {
106 shared_->~Shared();
107 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700108
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500109 ::aos::testing::TestSharedMemory my_shm_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700110
111 Shared *const shared_;
112
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700113 protected:
114 void SetUp() override {
115 SetDieTestMode(true);
116 }
117
Brian Silverman2586a5d2013-09-13 13:45:52 -0700118 private:
119 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700120};
121
122class ConditionTestProcess {
123 public:
124 enum class Action {
125 kWaitLockStart, // lock, delay, wait, unlock
126 kWait, // delay, lock, wait, unlock
127 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700128 };
129
130 // This amount gets added to any passed in delay to make the test repeatable.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800131 static constexpr chrono::milliseconds kMinimumDelay =
132 chrono::milliseconds(150);
133 static constexpr chrono::milliseconds kDefaultTimeout =
134 chrono::milliseconds(150);
Brian Silverman797e71e2013-09-06 17:29:39 -0700135
136 // delay is how long to wait before doing action to condition.
137 // timeout is how long to wait after delay before deciding that it's hung.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800138 ConditionTestProcess(chrono::milliseconds delay, Action action,
139 Condition *condition,
140 chrono::milliseconds timeout = kDefaultTimeout)
141 : delay_(kMinimumDelay + delay),
142 action_(action),
143 condition_(condition),
144 timeout_(delay_ + timeout),
145 child_(-1),
146 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700147 new (shared_) Shared();
148 }
149 ~ConditionTestProcess() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700150 AOS_CHECK_EQ(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700151 }
152
153 void Start() {
154 ASSERT_FALSE(shared_->started);
155
156 child_ = fork();
157 if (child_ == 0) { // in child
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500158 ::aos::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700159 Run();
160 exit(EXIT_SUCCESS);
161 } else { // in parent
Austin Schuhf257f3c2019-10-27 21:00:43 -0700162 AOS_CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700163
Brian Silvermandc1eb272014-08-19 14:25:59 -0400164 ASSERT_EQ(0, futex_wait(&shared_->ready));
Brian Silverman797e71e2013-09-06 17:29:39 -0700165
166 shared_->started = true;
167 }
168 }
169
170 bool IsFinished() {
171 return shared_->finished;
172 }
173
174 ::testing::AssertionResult Hung() {
175 if (!shared_->started) {
176 ADD_FAILURE();
177 return ::testing::AssertionFailure() << "not started yet";
178 }
179 if (shared_->finished) {
180 Join();
181 return ::testing::AssertionFailure() << "already returned";
182 }
183 if (shared_->delayed) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800184 if (shared_->start_time > monotonic_clock::now() + timeout_) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700185 Kill();
186 return ::testing::AssertionSuccess() << "already been too long";
187 }
188 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700189 AOS_CHECK_EQ(0, futex_wait(&shared_->done_delaying));
Brian Silverman797e71e2013-09-06 17:29:39 -0700190 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800191 ::std::this_thread::sleep_for(chrono::milliseconds(10));
192 if (!shared_->finished) {
193 ::std::this_thread::sleep_until(shared_->start_time + timeout_);
194 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700195 if (shared_->finished) {
196 Join();
197 return ::testing::AssertionFailure() << "completed within timeout";
198 } else {
199 Kill();
200 return ::testing::AssertionSuccess() << "took too long";
201 }
202 }
203 ::testing::AssertionResult Test() {
204 Start();
205 return Hung();
206 }
207
208 private:
209 struct Shared {
210 Shared()
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800211 : started(false),
212 delayed(false),
213 done_delaying(0),
214 start_time(monotonic_clock::epoch()),
215 finished(false),
216 ready(0) {}
Brian Silverman797e71e2013-09-06 17:29:39 -0700217
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700218 volatile bool started;
219 volatile bool delayed;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400220 aos_futex done_delaying;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800221 monotonic_clock::time_point start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700222 volatile bool finished;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400223 aos_futex ready;
Brian Silverman797e71e2013-09-06 17:29:39 -0700224 };
225 static_assert(shm_ok<Shared>::value,
226 "it's going to get shared between forked processes");
227
228 void Run() {
229 if (action_ == Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400230 ASSERT_EQ(1, futex_set(&shared_->ready));
231 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700232 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800233 ::std::this_thread::sleep_for(delay_);
234 shared_->start_time = monotonic_clock::now();
Brian Silverman797e71e2013-09-06 17:29:39 -0700235 shared_->delayed = true;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400236 ASSERT_NE(-1, futex_set(&shared_->done_delaying));
Brian Silverman2586a5d2013-09-13 13:45:52 -0700237 if (action_ != Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400238 ASSERT_EQ(1, futex_set(&shared_->ready));
239 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700240 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400241 // TODO(brians): Test this returning true (aka the owner dying).
242 ASSERT_FALSE(condition_->Wait());
Brian Silverman797e71e2013-09-06 17:29:39 -0700243 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700244 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700245 condition_->m()->Unlock();
246 }
247 }
248
249 void Join() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700250 AOS_CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700251 int status;
252 do {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700253 AOS_CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700254 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
255 child_ = -1;
256 }
257 void Kill() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700258 AOS_CHECK_NE(child_, -1);
259 AOS_PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700260 Join();
261 }
262
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800263 const chrono::milliseconds delay_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700264 const Action action_;
265 Condition *const condition_;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800266 const chrono::milliseconds timeout_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700267
268 pid_t child_;
269
270 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700271
272 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700273};
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800274constexpr chrono::milliseconds ConditionTestProcess::kMinimumDelay;
275constexpr chrono::milliseconds ConditionTestProcess::kDefaultTimeout;
Brian Silverman797e71e2013-09-06 17:29:39 -0700276
277// Makes sure that the testing framework and everything work for a really simple
278// Wait() and then Signal().
279TEST_F(ConditionTest, Basic) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800280 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700281 ConditionTestProcess::Action::kWait,
282 &shared_->condition);
283 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700284 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700285 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700286 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700287 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700288}
289
Brian Silverman2586a5d2013-09-13 13:45:52 -0700290// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700291TEST_F(ConditionTest, Locking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800292 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700293 ConditionTestProcess::Action::kWait,
294 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400295 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700296 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700297 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700298 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700299 // waiting to lock the mutex.
300 shared_->condition.Signal();
301 Settle();
302 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700303 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700304}
305
Brian Silverman2586a5d2013-09-13 13:45:52 -0700306// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700307// unlocked.
308TEST_F(ConditionTest, LockFirst) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800309 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700310 ConditionTestProcess::Action::kWait,
311 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400312 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700313 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700314 Settle();
315 shared_->condition.Signal();
316 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700317 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700318 shared_->mutex.Unlock();
319 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700320 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700321 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700322 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700323}
324
325// Tests that the mutex gets relocked after Wait() returns.
326TEST_F(ConditionTest, Relocking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800327 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700328 ConditionTestProcess::Action::kWaitNoUnlock,
329 &shared_->condition);
330 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700331 Settle();
332 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700333 EXPECT_FALSE(child.Hung());
Brian Silverman71c55c52014-08-19 14:31:59 -0400334 EXPECT_EQ(Mutex::State::kOwnerDied, shared_->mutex.TryLock());
335 shared_->mutex.Unlock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700336}
337
Brian Silverman2586a5d2013-09-13 13:45:52 -0700338// Tests that Signal() stops exactly 1 Wait()er.
339TEST_F(ConditionTest, SignalOne) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800340 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700341 ConditionTestProcess::Action::kWait,
342 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800343 ConditionTestProcess child2(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 child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700347 ConditionTestProcess::Action::kWait,
348 &shared_->condition);
349 auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
350 (child2.IsFinished() ? 1 : 0) + (child3.IsFinished() ? 1 : 0); };
351 child1.Start();
352 child2.Start();
353 child3.Start();
354 Settle();
355 EXPECT_EQ(0, number_finished());
356 shared_->condition.Signal();
357 Settle();
358 EXPECT_EQ(1, number_finished());
359 shared_->condition.Signal();
360 Settle();
361 EXPECT_EQ(2, number_finished());
362 shared_->condition.Signal();
363 Settle();
364 EXPECT_EQ(3, number_finished());
365 EXPECT_FALSE(child1.Hung());
366 EXPECT_FALSE(child2.Hung());
367 EXPECT_FALSE(child3.Hung());
368}
369
370// Tests that Brodcast() wakes multiple Wait()ers.
371TEST_F(ConditionTest, Broadcast) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800372 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700373 ConditionTestProcess::Action::kWait,
374 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800375 ConditionTestProcess child2(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 child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700379 ConditionTestProcess::Action::kWait,
380 &shared_->condition);
381 child1.Start();
382 child2.Start();
383 child3.Start();
384 Settle();
385 shared_->condition.Broadcast();
386 EXPECT_FALSE(child1.Hung());
387 EXPECT_FALSE(child2.Hung());
388 EXPECT_FALSE(child3.Hung());
389}
390
Brian Silverman797e71e2013-09-06 17:29:39 -0700391} // namespace testing
392} // namespace aos