• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
16 #include "common/libs/threads/cuttlefish_thread.h"
17 
18 #include <android-base/logging.h>
19 #include "common/libs/threads/thunkers.h"
20 #include "common/libs/time/monotonic_time.h"
21 
22 using cvd::ConditionVariable;
23 using cvd::Mutex;
24 using cvd::ScopedThread;
25 using cvd::time::MonotonicTimePoint;
26 using cvd::time::Milliseconds;
27 
28 static const int FINISHED = 100;
29 
SleepUntil(const MonotonicTimePoint & in)30 static 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 
49 class MutexTest {
50  public:
MutexTest()51   MutexTest() : busy_(NULL), stage_(0) {}
52 
Run()53   void Run() {
54     {
55       ScopedThread thread_a(cvd::thunk<void, &MutexTest::FastThread>, this);
56       ScopedThread thread_b(cvd::thunk<void, &MutexTest::SlowThread>, this);
57     }
58     LOG(INFO) << "MutexTest: completed at stage "
59               << stage_
60               << ", result: "
61               << ((stage_ == FINISHED) ? "PASSED" : "FAILED");
62   }
63 
64 protected:
FastThread()65   void* FastThread() {
66     mutex_.Lock();
67     CHECK(busy_ == NULL);
68     busy_ = "FastThread";
69     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
70     stage_ = 1;
71     busy_ = NULL;
72     mutex_.Unlock();
73     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(10));
74     mutex_.Lock();
75     CHECK(busy_ == NULL);
76     busy_ = "FastThread";
77     CHECK(stage_ == 2);
78     stage_ = FINISHED;
79     busy_ = NULL;
80     mutex_.Unlock();
81     return NULL;
82   }
83 
SlowThread()84   void* SlowThread() {
85     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(50));
86     mutex_.Lock();
87     CHECK(busy_== NULL);
88     busy_ = "SlowThread";
89     CHECK(stage_ == 1);
90     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
91     stage_ = 2;
92     busy_ = NULL;
93     mutex_.Unlock();
94     return NULL;
95   }
96 
97   Mutex mutex_;
98   const char* busy_;
99   int stage_;
100 };
101 
102 class NotifyOneTest {
103  public:
NotifyOneTest()104   NotifyOneTest() : cond_(&mutex_), signalled_(0) {}
105 
Run()106   void Run() {
107     {
108       ScopedThread thread_s(
109           cvd::thunk<void, &NotifyOneTest::SignalThread>, this);
110       ScopedThread thread_w1(
111           cvd::thunk<void, &NotifyOneTest::WaitThread>, this);
112       ScopedThread thread_w2(
113           cvd::thunk<void, &NotifyOneTest::WaitThread>, this);
114     }
115     LOG(INFO) << "NotifyOneTest: completed, signalled "
116               << signalled_
117               << ", result: "
118               << ((signalled_ == 2) ? "PASSED" : "FAILED");
119   }
120 
121 protected:
SignalThread()122   void* SignalThread() {
123     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
124     mutex_.Lock();
125     cond_.NotifyOne();
126     mutex_.Unlock();
127     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
128     mutex_.Lock();
129     CHECK(signalled_== 1);
130     cond_.NotifyOne();
131     mutex_.Unlock();
132     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
133     mutex_.Lock();
134     CHECK(signalled_ == 2);
135     mutex_.Unlock();
136     return NULL;
137   }
138 
WaitThread()139   void* WaitThread() {
140     mutex_.Lock();
141     cond_.Wait();
142     signalled_++;
143     mutex_.Unlock();
144     return NULL;
145   }
146 
147   Mutex mutex_;
148   ConditionVariable cond_;
149   int signalled_;
150 };
151 
152 class NotifyAllTest {
153  public:
NotifyAllTest()154   NotifyAllTest() : cond_(&mutex_), signalled_(0) {}
155 
Run()156   void Run() {
157     {
158       ScopedThread thread_s(
159           cvd::thunk<void, &NotifyAllTest::SignalThread>, this);
160       ScopedThread thread_w1(
161           cvd::thunk<void, &NotifyAllTest::WaitThread>, this);
162       ScopedThread thread_w2(
163           cvd::thunk<void, &NotifyAllTest::WaitThread>, this);
164     }
165     printf("NotifyAllTest: completed, signalled %d (%s)\n",
166            signalled_, (signalled_ == 2) ? "PASSED" : "FAILED");
167   }
168 
169 protected:
SignalThread()170   void* SignalThread() {
171     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
172     mutex_.Lock();
173     cond_.NotifyAll();
174     mutex_.Unlock();
175     SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100));
176     mutex_.Lock();
177     CHECK(signalled_ == 2);
178     mutex_.Unlock();
179     return NULL;
180   }
181 
WaitThread()182   void* WaitThread() {
183     mutex_.Lock();
184     cond_.Wait();
185     signalled_++;
186     mutex_.Unlock();
187     return NULL;
188   }
189 
190   Mutex mutex_;
191   ConditionVariable cond_;
192   int signalled_;
193 };
194 
195 class WaitUntilTest {
196  public:
WaitUntilTest()197   WaitUntilTest() : cond_(&mutex_), stage_(0) {}
198 
Run()199   void Run() {
200     start_ = MonotonicTimePoint::Now();
201     {
202       ScopedThread thread_s(
203           cvd::thunk<void, &WaitUntilTest::SignalThread>, this);
204       ScopedThread thread_w2(
205           cvd::thunk<void, &WaitUntilTest::WaitThread>, this);
206     }
207     printf("WaitUntilTest: completed, stage %d (%s)\n",
208            stage_, (stage_ == FINISHED) ? "PASSED" : "FAILED");
209   }
210 
211 protected:
SignalThread()212   void* SignalThread() {
213     SleepUntil(start_ + Milliseconds(200));
214     mutex_.Lock();
215     CHECK(stage_ == 2);
216     cond_.NotifyOne();
217     stage_ = 3;
218     mutex_.Unlock();
219     return NULL;
220   }
221 
WaitThread()222   void* WaitThread() {
223     mutex_.Lock();
224     CHECK(stage_ == 0);
225     stage_ = 1;
226     cond_.WaitUntil(start_ + Milliseconds(50));
227     MonotonicTimePoint current(MonotonicTimePoint::Now());
228     CHECK(Milliseconds(current - start_).count() >= 50);
229     CHECK(Milliseconds(current - start_).count() <= 100);
230     stage_ = 2;
231     cond_.WaitUntil(start_ + Milliseconds(1000));
232     current = MonotonicTimePoint::Now();
233     CHECK(Milliseconds(current - start_).count() <= 500);
234     CHECK(stage_ == 3);
235     stage_ = FINISHED;
236     mutex_.Unlock();
237     return NULL;
238   }
239 
240   Mutex mutex_;
241   ConditionVariable cond_;
242   int stage_;
243   MonotonicTimePoint start_;
244 };
245 
main(int,char ** argv)246 int main(int, char**argv) {
247   ::android::base::InitLogging(argv, android::base::StderrLogger);
248   MutexTest mt;
249   mt.Run();
250   NotifyOneTest nt1;
251   nt1.Run();
252   NotifyAllTest nta;
253   nta.Run();
254   WaitUntilTest wu;
255   wu.Run();
256 }
257