blob: c83dc191af150f064349147fe40c00f003d2cd41 [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
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 }
Austin Schuh60e77942022-05-16 17:48:24 -0700105 ~ConditionTest() { shared_->~Shared(); }
Brian Silverman797e71e2013-09-06 17:29:39 -0700106
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500107 ::aos::testing::TestSharedMemory my_shm_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700108
109 Shared *const shared_;
110
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700111 protected:
Austin Schuh60e77942022-05-16 17:48:24 -0700112 void SetUp() override { SetDieTestMode(true); }
Brian Silverman8d2e56e2013-09-23 17:55:03 -0700113
Brian Silverman2586a5d2013-09-13 13:45:52 -0700114 private:
115 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -0700116};
117
118class ConditionTestProcess {
119 public:
120 enum class Action {
121 kWaitLockStart, // lock, delay, wait, unlock
Austin Schuh60e77942022-05-16 17:48:24 -0700122 kWait, // delay, lock, wait, unlock
123 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -0700124 };
125
126 // This amount gets added to any passed in delay to make the test repeatable.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800127 static constexpr chrono::milliseconds kMinimumDelay =
128 chrono::milliseconds(150);
129 static constexpr chrono::milliseconds kDefaultTimeout =
130 chrono::milliseconds(150);
Brian Silverman797e71e2013-09-06 17:29:39 -0700131
132 // delay is how long to wait before doing action to condition.
133 // timeout is how long to wait after delay before deciding that it's hung.
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800134 ConditionTestProcess(chrono::milliseconds delay, Action action,
135 Condition *condition,
136 chrono::milliseconds timeout = kDefaultTimeout)
137 : delay_(kMinimumDelay + delay),
138 action_(action),
139 condition_(condition),
140 timeout_(delay_ + timeout),
141 child_(-1),
142 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700143 new (shared_) Shared();
144 }
Austin Schuh60e77942022-05-16 17:48:24 -0700145 ~ConditionTestProcess() { AOS_CHECK_EQ(child_, -1); }
Brian Silverman797e71e2013-09-06 17:29:39 -0700146
147 void Start() {
148 ASSERT_FALSE(shared_->started);
149
150 child_ = fork();
151 if (child_ == 0) { // in child
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500152 ::aos::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -0700153 Run();
154 exit(EXIT_SUCCESS);
155 } else { // in parent
Austin Schuhf257f3c2019-10-27 21:00:43 -0700156 AOS_CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700157
Brian Silvermandc1eb272014-08-19 14:25:59 -0400158 ASSERT_EQ(0, futex_wait(&shared_->ready));
Brian Silverman797e71e2013-09-06 17:29:39 -0700159
160 shared_->started = true;
161 }
162 }
163
Austin Schuh60e77942022-05-16 17:48:24 -0700164 bool IsFinished() { return shared_->finished; }
Brian Silverman797e71e2013-09-06 17:29:39 -0700165
166 ::testing::AssertionResult Hung() {
167 if (!shared_->started) {
168 ADD_FAILURE();
169 return ::testing::AssertionFailure() << "not started yet";
170 }
171 if (shared_->finished) {
172 Join();
173 return ::testing::AssertionFailure() << "already returned";
174 }
175 if (shared_->delayed) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800176 if (shared_->start_time > monotonic_clock::now() + timeout_) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700177 Kill();
178 return ::testing::AssertionSuccess() << "already been too long";
179 }
180 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700181 AOS_CHECK_EQ(0, futex_wait(&shared_->done_delaying));
Brian Silverman797e71e2013-09-06 17:29:39 -0700182 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800183 ::std::this_thread::sleep_for(chrono::milliseconds(10));
184 if (!shared_->finished) {
185 ::std::this_thread::sleep_until(shared_->start_time + timeout_);
186 }
Brian Silverman797e71e2013-09-06 17:29:39 -0700187 if (shared_->finished) {
188 Join();
189 return ::testing::AssertionFailure() << "completed within timeout";
190 } else {
191 Kill();
192 return ::testing::AssertionSuccess() << "took too long";
193 }
194 }
195 ::testing::AssertionResult Test() {
196 Start();
197 return Hung();
198 }
199
200 private:
201 struct Shared {
202 Shared()
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800203 : started(false),
204 delayed(false),
205 done_delaying(0),
206 start_time(monotonic_clock::epoch()),
207 finished(false),
208 ready(0) {}
Brian Silverman797e71e2013-09-06 17:29:39 -0700209
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700210 volatile bool started;
211 volatile bool delayed;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400212 aos_futex done_delaying;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800213 monotonic_clock::time_point start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700214 volatile bool finished;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400215 aos_futex ready;
Brian Silverman797e71e2013-09-06 17:29:39 -0700216 };
217 static_assert(shm_ok<Shared>::value,
218 "it's going to get shared between forked processes");
219
220 void Run() {
221 if (action_ == Action::kWaitLockStart) {
Brian Silvermandc1eb272014-08-19 14:25:59 -0400222 ASSERT_EQ(1, futex_set(&shared_->ready));
223 ASSERT_FALSE(condition_->m()->Lock());
Brian Silverman797e71e2013-09-06 17:29:39 -0700224 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800225 ::std::this_thread::sleep_for(delay_);
226 shared_->start_time = monotonic_clock::now();
Brian Silverman797e71e2013-09-06 17:29:39 -0700227 shared_->delayed = true;
Brian Silvermandc1eb272014-08-19 14:25:59 -0400228 ASSERT_NE(-1, futex_set(&shared_->done_delaying));
Brian Silverman2586a5d2013-09-13 13:45:52 -0700229 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 }
Brian Silvermandc1eb272014-08-19 14:25:59 -0400233 // TODO(brians): Test this returning true (aka the owner dying).
234 ASSERT_FALSE(condition_->Wait());
Brian Silverman797e71e2013-09-06 17:29:39 -0700235 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700236 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700237 condition_->m()->Unlock();
238 }
239 }
240
241 void Join() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700242 AOS_CHECK_NE(child_, -1);
Brian Silverman797e71e2013-09-06 17:29:39 -0700243 int status;
244 do {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700245 AOS_CHECK_EQ(waitpid(child_, &status, 0), child_);
Brian Silverman797e71e2013-09-06 17:29:39 -0700246 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
247 child_ = -1;
248 }
249 void Kill() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700250 AOS_CHECK_NE(child_, -1);
251 AOS_PCHECK(kill(child_, SIGTERM));
Brian Silverman797e71e2013-09-06 17:29:39 -0700252 Join();
253 }
254
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800255 const chrono::milliseconds delay_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700256 const Action action_;
257 Condition *const condition_;
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800258 const chrono::milliseconds timeout_;
Brian Silverman797e71e2013-09-06 17:29:39 -0700259
260 pid_t child_;
261
262 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700263
264 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700265};
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800266constexpr chrono::milliseconds ConditionTestProcess::kMinimumDelay;
267constexpr chrono::milliseconds ConditionTestProcess::kDefaultTimeout;
Brian Silverman797e71e2013-09-06 17:29:39 -0700268
269// Makes sure that the testing framework and everything work for a really simple
270// Wait() and then Signal().
271TEST_F(ConditionTest, Basic) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800272 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700273 ConditionTestProcess::Action::kWait,
274 &shared_->condition);
275 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700276 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700277 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700278 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700279 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700280}
281
Brian Silverman2586a5d2013-09-13 13:45:52 -0700282// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700283TEST_F(ConditionTest, Locking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800284 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700285 ConditionTestProcess::Action::kWait,
286 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400287 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700288 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700289 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700290 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700291 // waiting to lock the mutex.
292 shared_->condition.Signal();
293 Settle();
294 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700295 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700296}
297
Brian Silverman2586a5d2013-09-13 13:45:52 -0700298// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700299// unlocked.
300TEST_F(ConditionTest, LockFirst) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800301 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700302 ConditionTestProcess::Action::kWait,
303 &shared_->condition);
Brian Silvermandc1eb272014-08-19 14:25:59 -0400304 ASSERT_FALSE(shared_->mutex.Lock());
Brian Silverman2586a5d2013-09-13 13:45:52 -0700305 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700306 Settle();
307 shared_->condition.Signal();
308 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700309 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700310 shared_->mutex.Unlock();
311 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700312 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700313 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700314 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700315}
316
317// Tests that the mutex gets relocked after Wait() returns.
318TEST_F(ConditionTest, Relocking) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800319 ConditionTestProcess child(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700320 ConditionTestProcess::Action::kWaitNoUnlock,
321 &shared_->condition);
322 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700323 Settle();
324 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700325 EXPECT_FALSE(child.Hung());
Brian Silverman71c55c52014-08-19 14:31:59 -0400326 EXPECT_EQ(Mutex::State::kOwnerDied, shared_->mutex.TryLock());
327 shared_->mutex.Unlock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700328}
329
Brian Silverman2586a5d2013-09-13 13:45:52 -0700330// Tests that Signal() stops exactly 1 Wait()er.
331TEST_F(ConditionTest, SignalOne) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800332 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700333 ConditionTestProcess::Action::kWait,
334 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800335 ConditionTestProcess child2(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700336 ConditionTestProcess::Action::kWait,
337 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800338 ConditionTestProcess child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700339 ConditionTestProcess::Action::kWait,
340 &shared_->condition);
Austin Schuh60e77942022-05-16 17:48:24 -0700341 auto number_finished = [&]() {
342 return (child1.IsFinished() ? 1 : 0) + (child2.IsFinished() ? 1 : 0) +
343 (child3.IsFinished() ? 1 : 0);
344 };
Brian Silverman2586a5d2013-09-13 13:45:52 -0700345 child1.Start();
346 child2.Start();
347 child3.Start();
348 Settle();
349 EXPECT_EQ(0, number_finished());
350 shared_->condition.Signal();
351 Settle();
352 EXPECT_EQ(1, number_finished());
353 shared_->condition.Signal();
354 Settle();
355 EXPECT_EQ(2, number_finished());
356 shared_->condition.Signal();
357 Settle();
358 EXPECT_EQ(3, number_finished());
359 EXPECT_FALSE(child1.Hung());
360 EXPECT_FALSE(child2.Hung());
361 EXPECT_FALSE(child3.Hung());
362}
363
364// Tests that Brodcast() wakes multiple Wait()ers.
365TEST_F(ConditionTest, Broadcast) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800366 ConditionTestProcess child1(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700367 ConditionTestProcess::Action::kWait,
368 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800369 ConditionTestProcess child2(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700370 ConditionTestProcess::Action::kWait,
371 &shared_->condition);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800372 ConditionTestProcess child3(chrono::milliseconds(0),
Brian Silverman2586a5d2013-09-13 13:45:52 -0700373 ConditionTestProcess::Action::kWait,
374 &shared_->condition);
375 child1.Start();
376 child2.Start();
377 child3.Start();
378 Settle();
379 shared_->condition.Broadcast();
380 EXPECT_FALSE(child1.Hung());
381 EXPECT_FALSE(child2.Hung());
382 EXPECT_FALSE(child3.Hung());
383}
384
Brian Silverman797e71e2013-09-06 17:29:39 -0700385} // namespace testing
386} // namespace aos