blob: a10275b3766854c6a6ba98ace82daf7ad063d8ed [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
7#include "gtest/gtest.h"
8
Brian Silverman797e71e2013-09-06 17:29:39 -07009#include "aos/common/time.h"
10#include "aos/common/mutex.h"
11#include "aos/common/queue_testutils.h"
12#include "aos/common/type_traits.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -080013#include "aos/linux_code/ipc_lib/core_lib.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070014#include "aos/common/logging/logging.h"
Brian Silverman2586a5d2013-09-13 13:45:52 -070015#include "aos/common/macros.h"
Brian Silverman797e71e2013-09-06 17:29:39 -070016
17using ::aos::time::Time;
18using ::aos::common::testing::GlobalCoreInstance;
19
20namespace aos {
21namespace testing {
22
23class ConditionTest : public ::testing::Test {
24 public:
25 struct Shared {
26 Shared() : condition(&mutex) {}
27
28 Mutex mutex;
29 Condition condition;
30 };
31 static_assert(shm_ok<Shared>::value,
32 "it's going to get shared between forked processes");
33
34 ConditionTest() : shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
35 new (shared_) Shared();
36 }
37
38 GlobalCoreInstance my_core;
39
40 Shared *const shared_;
41
42 void Settle() {
Brian Silverman4c04efd2013-09-07 14:51:33 -070043 time::SleepFor(::Time::InSeconds(0.008));
Brian Silverman797e71e2013-09-06 17:29:39 -070044 }
Brian Silverman2586a5d2013-09-13 13:45:52 -070045
46 private:
47 DISALLOW_COPY_AND_ASSIGN(ConditionTest);
Brian Silverman797e71e2013-09-06 17:29:39 -070048};
49
50class ConditionTestProcess {
51 public:
52 enum class Action {
53 kWaitLockStart, // lock, delay, wait, unlock
54 kWait, // delay, lock, wait, unlock
55 kWaitNoUnlock, // delay, lock, wait
Brian Silverman797e71e2013-09-06 17:29:39 -070056 };
57
58 // This amount gets added to any passed in delay to make the test repeatable.
59 static constexpr ::Time kMinimumDelay = ::Time::InSeconds(0.015);
Brian Silverman4c04efd2013-09-07 14:51:33 -070060 static constexpr ::Time kDefaultTimeout = ::Time::InSeconds(0.09);
Brian Silverman797e71e2013-09-06 17:29:39 -070061
62 // delay is how long to wait before doing action to condition.
63 // timeout is how long to wait after delay before deciding that it's hung.
64 ConditionTestProcess(const ::Time &delay, Action action, Condition *condition,
65 const ::Time &timeout = kDefaultTimeout)
66 : delay_(kMinimumDelay + delay), action_(action), condition_(condition),
67 timeout_(delay_ + timeout), child_(-1),
68 shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
69 new (shared_) Shared();
70 }
71 ~ConditionTestProcess() {
72 assert(child_ == -1);
73 }
74
75 void Start() {
76 ASSERT_FALSE(shared_->started);
77
78 child_ = fork();
79 if (child_ == 0) { // in child
Brian Silvermaneeb62ca2013-09-11 15:08:03 -070080 ::aos::common::testing::PreventExit();
Brian Silverman797e71e2013-09-06 17:29:39 -070081 Run();
82 exit(EXIT_SUCCESS);
83 } else { // in parent
84 assert(child_ != -1);
85
86 shared_->ready.Lock();
87
88 shared_->started = true;
89 }
90 }
91
92 bool IsFinished() {
93 return shared_->finished;
94 }
95
96 ::testing::AssertionResult Hung() {
97 if (!shared_->started) {
98 ADD_FAILURE();
99 return ::testing::AssertionFailure() << "not started yet";
100 }
101 if (shared_->finished) {
102 Join();
103 return ::testing::AssertionFailure() << "already returned";
104 }
105 if (shared_->delayed) {
106 if (shared_->start_time > ::Time::Now() + timeout_) {
107 Kill();
108 return ::testing::AssertionSuccess() << "already been too long";
109 }
110 } else {
111 shared_->done_delaying.Lock();
112 }
113 time::SleepFor(::Time::InSeconds(0.01));
114 if (!shared_->finished) time::SleepUntil(shared_->start_time + timeout_);
115 if (shared_->finished) {
116 Join();
117 return ::testing::AssertionFailure() << "completed within timeout";
118 } else {
119 Kill();
120 return ::testing::AssertionSuccess() << "took too long";
121 }
122 }
123 ::testing::AssertionResult Test() {
124 Start();
125 return Hung();
126 }
127
128 private:
129 struct Shared {
130 Shared()
131 : started(false), delayed(false), start_time(0, 0), finished(false) {
132 done_delaying.Lock();
133 ready.Lock();
134 }
135
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700136 volatile bool started;
137 volatile bool delayed;
Brian Silverman797e71e2013-09-06 17:29:39 -0700138 Mutex done_delaying;
139 ::Time start_time;
Brian Silvermaneeb62ca2013-09-11 15:08:03 -0700140 volatile bool finished;
Brian Silverman797e71e2013-09-06 17:29:39 -0700141 Mutex ready;
142 };
143 static_assert(shm_ok<Shared>::value,
144 "it's going to get shared between forked processes");
145
146 void Run() {
147 if (action_ == Action::kWaitLockStart) {
148 shared_->ready.Unlock();
149 condition_->m()->Lock();
150 }
151 time::SleepFor(delay_);
152 shared_->start_time = ::Time::Now();
153 shared_->delayed = true;
154 shared_->done_delaying.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700155 if (action_ != Action::kWaitLockStart) {
156 shared_->ready.Unlock();
157 condition_->m()->Lock();
Brian Silverman797e71e2013-09-06 17:29:39 -0700158 }
Brian Silverman2586a5d2013-09-13 13:45:52 -0700159 condition_->Wait();
Brian Silverman797e71e2013-09-06 17:29:39 -0700160 shared_->finished = true;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700161 if (action_ != Action::kWaitNoUnlock) {
Brian Silverman797e71e2013-09-06 17:29:39 -0700162 condition_->m()->Unlock();
163 }
164 }
165
166 void Join() {
167 assert(child_ != -1);
168 int status;
169 do {
170 assert(waitpid(child_, &status, 0) == child_);
171 } while (!(WIFEXITED(status) || WIFSIGNALED(status)));
172 child_ = -1;
173 }
174 void Kill() {
175 assert(child_ != -1);
176 assert(kill(child_, SIGTERM) == 0);
177 Join();
178 }
179
180 const ::Time delay_;
181 const Action action_;
182 Condition *const condition_;
183 const ::Time timeout_;
184
185 pid_t child_;
186
187 Shared *const shared_;
Brian Silverman2586a5d2013-09-13 13:45:52 -0700188
189 DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
Brian Silverman797e71e2013-09-06 17:29:39 -0700190};
191constexpr ::Time ConditionTestProcess::kMinimumDelay;
192constexpr ::Time ConditionTestProcess::kDefaultTimeout;
193
194// Makes sure that the testing framework and everything work for a really simple
195// Wait() and then Signal().
196TEST_F(ConditionTest, Basic) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700197 ConditionTestProcess child(::Time(0, 0),
198 ConditionTestProcess::Action::kWait,
199 &shared_->condition);
200 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700201 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700202 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700203 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700204 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700205}
206
Brian Silverman2586a5d2013-09-13 13:45:52 -0700207// Makes sure that the worker child locks before it tries to Wait() etc.
Brian Silverman797e71e2013-09-06 17:29:39 -0700208TEST_F(ConditionTest, Locking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700209 ConditionTestProcess child(::Time(0, 0),
210 ConditionTestProcess::Action::kWait,
211 &shared_->condition);
Brian Silverman797e71e2013-09-06 17:29:39 -0700212 shared_->mutex.Lock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700213 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700214 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700215 // This Signal() shouldn't do anything because the child should still be
Brian Silverman797e71e2013-09-06 17:29:39 -0700216 // waiting to lock the mutex.
217 shared_->condition.Signal();
218 Settle();
219 shared_->mutex.Unlock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700220 EXPECT_TRUE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700221}
222
Brian Silverman2586a5d2013-09-13 13:45:52 -0700223// Tests that the work child only catches a Signal() after the mutex gets
Brian Silverman797e71e2013-09-06 17:29:39 -0700224// unlocked.
225TEST_F(ConditionTest, LockFirst) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700226 ConditionTestProcess child(::Time(0, 0),
227 ConditionTestProcess::Action::kWait,
228 &shared_->condition);
Brian Silverman797e71e2013-09-06 17:29:39 -0700229 shared_->mutex.Lock();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700230 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700231 Settle();
232 shared_->condition.Signal();
233 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700234 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700235 shared_->mutex.Unlock();
236 Settle();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700237 EXPECT_FALSE(child.IsFinished());
Brian Silverman797e71e2013-09-06 17:29:39 -0700238 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700239 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700240}
241
242// Tests that the mutex gets relocked after Wait() returns.
243TEST_F(ConditionTest, Relocking) {
Brian Silverman2586a5d2013-09-13 13:45:52 -0700244 ConditionTestProcess child(::Time(0, 0),
245 ConditionTestProcess::Action::kWaitNoUnlock,
246 &shared_->condition);
247 child.Start();
Brian Silverman797e71e2013-09-06 17:29:39 -0700248 Settle();
249 shared_->condition.Signal();
Brian Silverman2586a5d2013-09-13 13:45:52 -0700250 EXPECT_FALSE(child.Hung());
Brian Silverman797e71e2013-09-06 17:29:39 -0700251 EXPECT_FALSE(shared_->mutex.TryLock());
252}
253
Brian Silverman2586a5d2013-09-13 13:45:52 -0700254// Tests that Signal() stops exactly 1 Wait()er.
255TEST_F(ConditionTest, SignalOne) {
256 ConditionTestProcess child1(::Time(0, 0),
257 ConditionTestProcess::Action::kWait,
258 &shared_->condition);
259 ConditionTestProcess child2(::Time(0, 0),
260 ConditionTestProcess::Action::kWait,
261 &shared_->condition);
262 ConditionTestProcess child3(::Time(0, 0),
263 ConditionTestProcess::Action::kWait,
264 &shared_->condition);
265 auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
266 (child2.IsFinished() ? 1 : 0) + (child3.IsFinished() ? 1 : 0); };
267 child1.Start();
268 child2.Start();
269 child3.Start();
270 Settle();
271 EXPECT_EQ(0, number_finished());
272 shared_->condition.Signal();
273 Settle();
274 EXPECT_EQ(1, number_finished());
275 shared_->condition.Signal();
276 Settle();
277 EXPECT_EQ(2, number_finished());
278 shared_->condition.Signal();
279 Settle();
280 EXPECT_EQ(3, number_finished());
281 EXPECT_FALSE(child1.Hung());
282 EXPECT_FALSE(child2.Hung());
283 EXPECT_FALSE(child3.Hung());
284}
285
286// Tests that Brodcast() wakes multiple Wait()ers.
287TEST_F(ConditionTest, Broadcast) {
288 ConditionTestProcess child1(::Time(0, 0),
289 ConditionTestProcess::Action::kWait,
290 &shared_->condition);
291 ConditionTestProcess child2(::Time(0, 0),
292 ConditionTestProcess::Action::kWait,
293 &shared_->condition);
294 ConditionTestProcess child3(::Time(0, 0),
295 ConditionTestProcess::Action::kWait,
296 &shared_->condition);
297 child1.Start();
298 child2.Start();
299 child3.Start();
300 Settle();
301 shared_->condition.Broadcast();
302 EXPECT_FALSE(child1.Hung());
303 EXPECT_FALSE(child2.Hung());
304 EXPECT_FALSE(child3.Hung());
305}
306
Brian Silverman797e71e2013-09-06 17:29:39 -0700307} // namespace testing
308} // namespace aos