blob: 1551cb0de3bd413546802924eabe864802a66036 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/condition.h"
Brian Silverman797e71e2013-09-06 17:29:39 -07002
Brian Silverman797e71e2013-09-06 17:29:39 -07003#include <sys/types.h>
4#include <sys/wait.h>
Austin Schuh60e77942022-05-16 17:48:24 -07005#include <unistd.h>
Brian Silverman797e71e2013-09-06 17:29:39 -07006
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
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "gtest/gtest.h"
12
Austin Schuh60e77942022-05-16 17:48:24 -070013#include "aos/die.h"
14#include "aos/ipc_lib/aos_sync.h"
John Park398c74a2018-10-20 21:17:39 -070015#include "aos/ipc_lib/core_lib.h"
John Park33858a32018-09-28 23:05:48 -070016#include "aos/logging/logging.h"
17#include "aos/macros.h"
Austin Schuh60e77942022-05-16 17:48:24 -070018#include "aos/mutex/mutex.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050019#include "aos/testing/prevent_exit.h"
Austin Schuh60e77942022-05-16 17:48:24 -070020#include "aos/testing/test_shm.h"
21#include "aos/time/time.h"
22#include "aos/type_traits/type_traits.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070023
Stephan Pleinesf63bde82024-01-13 15:59:33 -080024namespace aos::testing {
Brian Silverman797e71e2013-09-06 17:29:39 -070025
Austin Schuhf2a50ba2016-12-24 16:16:26 -080026namespace chrono = ::std::chrono;
27
Brian Silvermanf1194642014-09-04 13:01:17 -040028class ConditionTestCommon : public ::testing::Test {
29 public:
30 ConditionTestCommon() {}
31
Austin Schuhf2a50ba2016-12-24 16:16:26 -080032 void Settle() { ::std::this_thread::sleep_for(chrono::milliseconds(8)); }
Brian Silvermanf1194642014-09-04 13:01:17 -040033
34 private:
35 DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
36};
37
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050038// Some simple tests that don't rely on a TestSharedMemory to help with
Brian Silvermanf1194642014-09-04 13:01:17 -040039// debugging problems that cause tests using that to just completely lock up.
40class SimpleConditionTest : public ConditionTestCommon {
41 public:
42 SimpleConditionTest() : condition_(&mutex_) {}
43
44 Mutex mutex_;
45 Condition condition_;
46
47 private:
48 DISALLOW_COPY_AND_ASSIGN(SimpleConditionTest);
49};
50
51// Makes sure that nothing crashes or anything with a basic Wait() and then
52// Signal().
53// This test is written to hopefully fail instead of deadlocking on failure, but
54// it's tricky because there's no way to kill the child in the middle.
55TEST_F(SimpleConditionTest, Basic) {
56 ::std::atomic_bool child_finished(false);
57 Condition child_ready(&mutex_);
58 ASSERT_FALSE(mutex_.Lock());
Kai Tinkessbf1385d2020-01-18 14:18:49 -080059 std::thread child([this, &child_finished, &child_ready] {
Brian Silvermanf1194642014-09-04 13:01:17 -040060 ASSERT_FALSE(mutex_.Lock());
61 child_ready.Broadcast();
62 ASSERT_FALSE(condition_.Wait());
63 child_finished.store(true);
64 mutex_.Unlock();
65 });
Brian Silvermanf1194642014-09-04 13:01:17 -040066 ASSERT_FALSE(child_ready.Wait());
67 EXPECT_FALSE(child_finished.load());
68 condition_.Signal();
69 mutex_.Unlock();
Kai Tinkessbf1385d2020-01-18 14:18:49 -080070 child.join();
Brian Silvermanf1194642014-09-04 13:01:17 -040071 EXPECT_TRUE(child_finished.load());
72}
73
Brian Silverman71c55c52014-08-19 14:31:59 -040074// Tests that contention on the associated mutex doesn't break anything.
75// This seems likely to cause issues with AddressSanitizer in particular.
76TEST_F(SimpleConditionTest, MutexContention) {
77 for (int i = 0; i < 1000; ++i) {
78 ASSERT_FALSE(mutex_.Lock());
79 ::std::thread thread([this]() {
80 ASSERT_FALSE(mutex_.Lock());
81 condition_.Signal();
82 mutex_.Unlock();
83 });
84 ASSERT_FALSE(condition_.Wait());
85 mutex_.Unlock();
86 thread.join();
87 }
88}
89
Brian Silvermanf1194642014-09-04 13:01:17 -040090class ConditionTest : public ConditionTestCommon {
Brian Silverman797e71e2013-09-06 17:29:39 -070091 public:
92 struct Shared {
93 Shared() : condition(&mutex) {}
94
95 Mutex mutex;
96 Condition condition;
97 };
98 static_assert(shm_ok<Shared>::value,
99 "it's going to get shared between forked processes");
100
101 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
102 new (shared_) Shared();
103 }
Austin Schuh60e77942022-05-16 17:48:24 -0700104 ~ConditionTest() { shared_->~Shared(); }
Brian Silverman797e71e2013-09-06 17:29:39 -0700105
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500106 ::aos::testing::TestSharedMemory my_shm_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700107
108 Shared *const shared_;
109
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700110 protected:
Austin Schuh60e77942022-05-16 17:48:24 -0700111 void SetUp() override { SetDieTestMode(true); }
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700112
Brian Silverman2586a5d2013-09-13 13:45:52 -0700113 private:
114 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700115};
116
117class ConditionTestProcess {
118 public:
119 enum class Action {
120 kWaitLockStart, // lock, delay, wait, unlock
Austin Schuh60e77942022-05-16 17:48:24 -0700121 kWait, // delay, lock, wait, unlock
122 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700123 };
124
125 // This amount gets added to any passed in delay to make the test repeatable.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800126 static constexpr chrono::milliseconds kMinimumDelay =
127 chrono::milliseconds(150);
128 static constexpr chrono::milliseconds kDefaultTimeout =
129 chrono::milliseconds(150);
Brian Silverman797e71e2013-09-06 17:29:39 -0700130
131 // delay is how long to wait before doing action to condition.
132 // timeout is how long to wait after delay before deciding that it's hung.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800133 ConditionTestProcess(chrono::milliseconds delay, Action action,
134 Condition *condition,
135 chrono::milliseconds timeout = kDefaultTimeout)
136 : delay_(kMinimumDelay + delay),
137 action_(action),
138 condition_(condition),
139 timeout_(delay_ + timeout),
140 child_(-1),
141 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700142 new (shared_) Shared();
143 }
Austin Schuh60e77942022-05-16 17:48:24 -0700144 ~ConditionTestProcess() { AOS_CHECK_EQ(child_, -1); }
Brian Silverman797e71e2013-09-06 17:29:39 -0700145
146 void Start() {
147 ASSERT_FALSE(shared_->started);
148
149 child_ = fork();
150 if (child_ == 0) { // in child
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500151 ::aos::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700152 Run();
153 exit(EXIT_SUCCESS);
154 } else { // in parent
Austin Schuhf257f3c2019-10-27 21:00:43 -0700155 AOS_CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700156
Brian Silvermandc1eb272014-08-19 14:25:59 -0400157 ASSERT_EQ(0, futex_wait(&shared_->ready));
Brian Silverman797e71e2013-09-06 17:29:39 -0700158
159 shared_->started = true;
160 }
161 }
162
Austin Schuh60e77942022-05-16 17:48:24 -0700163 bool IsFinished() { return shared_->finished; }
Brian Silverman797e71e2013-09-06 17:29:39 -0700164
165 ::testing::AssertionResult Hung() {
166 if (!shared_->started) {
167 ADD_FAILURE();
168 return ::testing::AssertionFailure() << "not started yet";
169 }
170 if (shared_->finished) {
171 Join();
172 return ::testing::AssertionFailure() << "already returned";
173 }
174 if (shared_->delayed) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800175 if (shared_->start_time > monotonic_clock::now() + timeout_) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700176 Kill();
177 return ::testing::AssertionSuccess() << "already been too long";
178 }
179 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700180 AOS_CHECK_EQ(0, futex_wait(&shared_->done_delaying));
Brian Silverman797e71e2013-09-06 17:29:39 -0700181 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800182 ::std::this_thread::sleep_for(chrono::milliseconds(10));
183 if (!shared_->finished) {
184 ::std::this_thread::sleep_until(shared_->start_time + timeout_);
185 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700186 if (shared_->finished) {
187 Join();
188 return ::testing::AssertionFailure() << "completed within timeout";
189 } else {
190 Kill();
191 return ::testing::AssertionSuccess() << "took too long";
192 }
193 }
194 ::testing::AssertionResult Test() {
195 Start();
196 return Hung();
197 }
198
199 private:
200 struct Shared {
201 Shared()
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800202 : started(false),
203 delayed(false),
204 done_delaying(0),
205 start_time(monotonic_clock::epoch()),
206 finished(false),
207 ready(0) {}
Brian Silverman797e71e2013-09-06 17:29:39 -0700208
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700209 volatile bool started;
210 volatile bool delayed;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400211 aos_futex done_delaying;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800212 monotonic_clock::time_point start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700213 volatile bool finished;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400214 aos_futex ready;
Brian Silverman797e71e2013-09-06 17:29:39 -0700215 };
216 static_assert(shm_ok<Shared>::value,
217 "it's going to get shared between forked processes");
218
219 void Run() {
220 if (action_ == Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400221 ASSERT_EQ(1, futex_set(&shared_->ready));
222 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700223 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800224 ::std::this_thread::sleep_for(delay_);
225 shared_->start_time = monotonic_clock::now();
Brian Silverman797e71e2013-09-06 17:29:39 -0700226 shared_->delayed = true;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400227 ASSERT_NE(-1, futex_set(&shared_->done_delaying));
Brian Silverman2586a5d2013-09-13 13:45:52 -0700228 if (action_ != Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400229 ASSERT_EQ(1, futex_set(&shared_->ready));
230 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700231 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400232 // TODO(brians): Test this returning true (aka the owner dying).
233 ASSERT_FALSE(condition_->Wait());
Brian Silverman797e71e2013-09-06 17:29:39 -0700234 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700235 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700236 condition_->m()->Unlock();
237 }
238 }
239
240 void Join() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700241 AOS_CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700242 int status;
243 do {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700244 AOS_CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700245 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
246 child_ = -1;
247 }
248 void Kill() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700249 AOS_CHECK_NE(child_, -1);
250 AOS_PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700251 Join();
252 }
253
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800254 const chrono::milliseconds delay_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700255 const Action action_;
256 Condition *const condition_;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800257 const chrono::milliseconds timeout_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700258
259 pid_t child_;
260
261 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700262
263 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700264};
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800265constexpr chrono::milliseconds ConditionTestProcess::kMinimumDelay;
266constexpr chrono::milliseconds ConditionTestProcess::kDefaultTimeout;
Brian Silverman797e71e2013-09-06 17:29:39 -0700267
268// Makes sure that the testing framework and everything work for a really simple
269// Wait() and then Signal().
270TEST_F(ConditionTest, Basic) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800271 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700272 ConditionTestProcess::Action::kWait,
273 &shared_->condition);
274 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700275 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700276 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700277 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700278 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700279}
280
Brian Silverman2586a5d2013-09-13 13:45:52 -0700281// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700282TEST_F(ConditionTest, Locking) {
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);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400286 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700287 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700288 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700289 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700290 // waiting to lock the mutex.
291 shared_->condition.Signal();
292 Settle();
293 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700294 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700295}
296
Brian Silverman2586a5d2013-09-13 13:45:52 -0700297// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700298// unlocked.
299TEST_F(ConditionTest, LockFirst) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800300 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700301 ConditionTestProcess::Action::kWait,
302 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400303 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700304 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700305 Settle();
306 shared_->condition.Signal();
307 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700308 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700309 shared_->mutex.Unlock();
310 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700311 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700312 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700313 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700314}
315
316// Tests that the mutex gets relocked after Wait() returns.
317TEST_F(ConditionTest, Relocking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800318 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700319 ConditionTestProcess::Action::kWaitNoUnlock,
320 &shared_->condition);
321 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700322 Settle();
323 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700324 EXPECT_FALSE(child.Hung());
Brian Silverman71c55c52014-08-19 14:31:59 -0400325 EXPECT_EQ(Mutex::State::kOwnerDied, shared_->mutex.TryLock());
326 shared_->mutex.Unlock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700327}
328
Brian Silverman2586a5d2013-09-13 13:45:52 -0700329// Tests that Signal() stops exactly 1 Wait()er.
330TEST_F(ConditionTest, SignalOne) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800331 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700332 ConditionTestProcess::Action::kWait,
333 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800334 ConditionTestProcess child2(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700335 ConditionTestProcess::Action::kWait,
336 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800337 ConditionTestProcess child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700338 ConditionTestProcess::Action::kWait,
339 &shared_->condition);
Austin Schuh60e77942022-05-16 17:48:24 -0700340 auto number_finished = [&]() {
341 return (child1.IsFinished() ? 1 : 0) + (child2.IsFinished() ? 1 : 0) +
342 (child3.IsFinished() ? 1 : 0);
343 };
Brian Silverman2586a5d2013-09-13 13:45:52 -0700344 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) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800365 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700366 ConditionTestProcess::Action::kWait,
367 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800368 ConditionTestProcess child2(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700369 ConditionTestProcess::Action::kWait,
370 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800371 ConditionTestProcess child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700372 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
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800384} // namespace aos::testing