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 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: 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 66 protected: 67 template <typename F> struct MutexTestThunker : 68 ThunkerBase<void, MutexTest, F>{}; 69 70 void* FastThread() { 71 mutex_.Lock(); 72 CHECK(busy_ == NULL); 73 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(); 80 CHECK(busy_ == NULL); 81 busy_ = "FastThread"; 82 CHECK(stage_ == 2); 83 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(); 92 CHECK(busy_== NULL); 93 busy_ = "SlowThread"; 94 CHECK(stage_ == 1); 95 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 107 class 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 126 protected: 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(); 137 CHECK(signalled_== 1); 138 cond_.NotifyOne(); 139 mutex_.Unlock(); 140 SleepUntil(MonotonicTimePoint::Now() + Milliseconds(100)); 141 mutex_.Lock(); 142 CHECK(signalled_ == 2); 143 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 160 class 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 177 protected: 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(); 188 CHECK(signalled_ == 2); 189 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 206 class 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 222 protected: 223 template <typename F> struct Thunker : 224 ThunkerBase<void, WaitUntilTest, F>{}; 225 226 void* SignalThread() { 227 SleepUntil(start_ + Milliseconds(200)); 228 mutex_.Lock(); 229 CHECK(stage_ == 2); 230 cond_.NotifyOne(); 231 stage_ = 3; 232 mutex_.Unlock(); 233 return NULL; 234 } 235 236 void* WaitThread() { 237 mutex_.Lock(); 238 CHECK(stage_ == 0); 239 stage_ = 1; 240 cond_.WaitUntil(start_ + Milliseconds(50)); 241 MonotonicTimePoint current(MonotonicTimePoint::Now()); 242 CHECK(Milliseconds(current - start_).count() >= 50); 243 CHECK(Milliseconds(current - start_).count() <= 100); 244 stage_ = 2; 245 cond_.WaitUntil(start_ + Milliseconds(1000)); 246 current = MonotonicTimePoint::Now(); 247 CHECK(Milliseconds(current - start_).count() <= 500); 248 CHECK(stage_ == 3); 249 stage_ = FINISHED; 250 mutex_.Unlock(); 251 return NULL; 252 } 253 254 Mutex mutex_; 255 ConditionVariable cond_; 256 int stage_; 257 MonotonicTimePoint start_; 258 }; 259 260 int main(int, char**argv) { 261 ::android::base::InitLogging(argv, android::base::StderrLogger); 262 MutexTest mt; 263 mt.Run(); 264 NotifyOneTest nt1; 265 nt1.Run(); 266 NotifyAllTest nta; 267 nta.Run(); 268 WaitUntilTest wu; 269 wu.Run(); 270 } 271