blob: 9ea1a5dff9276435e5c8b1e20afdfabf6cbaebd2 [file] [log] [blame]
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Greg Hartmana4ff2482017-10-03 16:35:00 -070016#include "common/libs/threads/cuttlefish_thread.h"
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070017
Greg Hartmana4ff2482017-10-03 16:35:00 -070018#include <android-base/logging.h>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070019#include "common/libs/threads/thunkers.h"
20#include "common/libs/time/monotonic_time.h"
21
22using avd::ConditionVariable;
23using avd::Mutex;
24using avd::ScopedThread;
25using avd::time::MonotonicTimePoint;
26using avd::time::Milliseconds;
27
28static const int FINISHED = 100;
29
30static void SleepUntil(const MonotonicTimePoint& in) {
31 struct timespec ts;
32 in.ToTimespec(&ts);
33#ifdef CLOCK_MONOTONIC_RAW
34 // WARNING:
35 // While we do have CLOCK_MONOTONIC_RAW, we can't depend on it until:
36 // - ALL places relying on MonotonicTimePoint are fixed,
37 // - pthread supports pthread_timewait_monotonic.
38 // - CLOCK_MONOTONIC_RAW is re-enabled in monotonic_time.h.
39 //
40 // This is currently observable as a LEGITIMATE problem while running
41 // this test. DO NOT revert this to CLOCK_MONOTONIC_RAW until this is
42 // fixed everywhere AND this test passes.
43 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
44#else
45 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
46#endif
47}
48
49class MutexTest {
50 public:
51 MutexTest() : busy_(NULL), stage_(0) {}
52
53 void Run() {
54 {
55 ScopedThread thread_a(
56 MutexTestThunker<void*()>::call<&MutexTest::FastThread>, this);
57 ScopedThread thread_b(
58 MutexTestThunker<void*()>::call<&MutexTest::SlowThread>, this);
59 }
60 LOG(INFO) << "MutexTest: completed at stage "
61 << stage_
62 << ", result: "
63 << ((stage_ == FINISHED) ? "PASSED" : "FAILED");
64 }
65
66protected:
67 template <typename F> struct MutexTestThunker :
68 ThunkerBase<void, MutexTest, F>{};
69
70 void* FastThread() {
71 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -070072 CHECK(busy_ == NULL);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070073 busy_ = "FastThread";
74 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
75 stage_ = 1;
76 busy_ = NULL;
77 mutex_.Unlock();
78 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(10));
79 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -070080 CHECK(busy_ == NULL);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070081 busy_ = "FastThread";
Greg Hartmana4ff2482017-10-03 16:35:00 -070082 CHECK(stage_ == 2);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070083 stage_ = FINISHED;
84 busy_ = NULL;
85 mutex_.Unlock();
86 return NULL;
87 }
88
89 void* SlowThread() {
90 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(50));
91 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -070092 CHECK(busy_== NULL);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070093 busy_ = "SlowThread";
Greg Hartmana4ff2482017-10-03 16:35:00 -070094 CHECK(stage_ == 1);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070095 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
96 stage_ = 2;
97 busy_ = NULL;
98 mutex_.Unlock();
99 return NULL;
100 }
101
102 Mutex mutex_;
103 const char* busy_;
104 int stage_;
105};
106
107class NotifyOneTest {
108 public:
109 NotifyOneTest() : cond_(&mutex_), signalled_(0) {}
110
111 void Run() {
112 {
113 ScopedThread thread_s(
114 Thunker<void*()>::call<&NotifyOneTest::SignalThread>, this);
115 ScopedThread thread_w1(
116 Thunker<void*()>::call<&NotifyOneTest::WaitThread>, this);
117 ScopedThread thread_w2(
118 Thunker<void*()>::call<&NotifyOneTest::WaitThread>, this);
119 }
120 LOG(INFO) << "NotifyOneTest: completed, signalled "
121 << signalled_
122 << ", result: "
123 << ((signalled_ == 2) ? "PASSED" : "FAILED");
124 }
125
126protected:
127 template <typename F> struct Thunker :
128 ThunkerBase<void, NotifyOneTest, F>{};
129
130 void* SignalThread() {
131 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
132 mutex_.Lock();
133 cond_.NotifyOne();
134 mutex_.Unlock();
135 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
136 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -0700137 CHECK(signalled_== 1);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700138 cond_.NotifyOne();
139 mutex_.Unlock();
140 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
141 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -0700142 CHECK(signalled_ == 2);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700143 mutex_.Unlock();
144 return NULL;
145 }
146
147 void* WaitThread() {
148 mutex_.Lock();
149 cond_.Wait();
150 signalled_++;
151 mutex_.Unlock();
152 return NULL;
153 }
154
155 Mutex mutex_;
156 ConditionVariable cond_;
157 int signalled_;
158};
159
160class NotifyAllTest {
161 public:
162 NotifyAllTest() : cond_(&mutex_), signalled_(0) {}
163
164 void Run() {
165 {
166 ScopedThread thread_s(
167 Thunker<void*()>::call<&NotifyAllTest::SignalThread>, this);
168 ScopedThread thread_w1(
169 Thunker<void*()>::call<&NotifyAllTest::WaitThread>, this);
170 ScopedThread thread_w2(
171 Thunker<void*()>::call<&NotifyAllTest::WaitThread>, this);
172 }
173 printf("NotifyAllTest: completed, signalled %d (%s)\n",
174 signalled_, (signalled_ == 2) ? "PASSED" : "FAILED");
175 }
176
177protected:
178 template <typename F> struct Thunker :
179 ThunkerBase<void, NotifyAllTest, F>{};
180
181 void* SignalThread() {
182 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
183 mutex_.Lock();
184 cond_.NotifyAll();
185 mutex_.Unlock();
186 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
187 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -0700188 CHECK(signalled_ == 2);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700189 mutex_.Unlock();
190 return NULL;
191 }
192
193 void* WaitThread() {
194 mutex_.Lock();
195 cond_.Wait();
196 signalled_++;
197 mutex_.Unlock();
198 return NULL;
199 }
200
201 Mutex mutex_;
202 ConditionVariable cond_;
203 int signalled_;
204};
205
206class WaitUntilTest {
207 public:
208 WaitUntilTest() : cond_(&mutex_), stage_(0) {}
209
210 void Run() {
211 start_ = MonotonicTimePoint::Now();
212 {
213 ScopedThread thread_s(
214 Thunker<void*()>::call<&WaitUntilTest::SignalThread>, this);
215 ScopedThread thread_w2(
216 Thunker<void*()>::call<&WaitUntilTest::WaitThread>, this);
217 }
218 printf("WaitUntilTest: completed, stage %d (%s)\n",
219 stage_, (stage_ == FINISHED) ? "PASSED" : "FAILED");
220 }
221
222protected:
223 template <typename F> struct Thunker :
224 ThunkerBase<void, WaitUntilTest, F>{};
225
226 void* SignalThread() {
227 SleepUntil(start_ + Milliseconds(200));
228 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -0700229 CHECK(stage_ == 2);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700230 cond_.NotifyOne();
231 stage_ = 3;
232 mutex_.Unlock();
233 return NULL;
234 }
235
236 void* WaitThread() {
237 mutex_.Lock();
Greg Hartmana4ff2482017-10-03 16:35:00 -0700238 CHECK(stage_ == 0);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700239 stage_ = 1;
240 cond_.WaitUntil(start_ + Milliseconds(50));
241 MonotonicTimePoint current(MonotonicTimePoint::Now());
Greg Hartmana4ff2482017-10-03 16:35:00 -0700242 CHECK(Milliseconds(current - start_).count() >= 50);
243 CHECK(Milliseconds(current - start_).count() <= 100);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700244 stage_ = 2;
245 cond_.WaitUntil(start_ + Milliseconds(1000));
246 current = MonotonicTimePoint::Now();
Greg Hartmana4ff2482017-10-03 16:35:00 -0700247 CHECK(Milliseconds(current - start_).count() <= 500);
248 CHECK(stage_ == 3);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700249 stage_ = FINISHED;
250 mutex_.Unlock();
251 return NULL;
252 }
253
254 Mutex mutex_;
255 ConditionVariable cond_;
256 int stage_;
257 MonotonicTimePoint start_;
258};
259
Greg Hartmana4ff2482017-10-03 16:35:00 -0700260int main(int, char**argv) {
261 ::android::base::InitLogging(argv, android::base::StderrLogger);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700262 MutexTest mt;
263 mt.Run();
264 NotifyOneTest nt1;
265 nt1.Run();
266 NotifyAllTest nta;
267 nta.Run();
268 WaitUntilTest wu;
269 wu.Run();
270}