1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // NOTE(vtl): These tests are inherently flaky (e.g., if run on a heavily-loaded 6 // system). Sorry. |kEpsilonMicros| may be increased to increase tolerance and 7 // reduce observed flakiness. 8 9 #include "mojo/system/waiter.h" 10 11 #include "base/basictypes.h" 12 #include "base/compiler_specific.h" 13 #include "base/synchronization/lock.h" 14 #include "base/threading/platform_thread.h" // For |Sleep()|. 15 #include "base/threading/simple_thread.h" 16 #include "base/time/time.h" 17 #include "mojo/system/test_utils.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace mojo { 21 namespace system { 22 namespace { 23 24 const int64_t kMicrosPerMs = 1000; 25 const int64_t kEpsilonMicros = 15 * kMicrosPerMs; // 15 ms. 26 const int64_t kPollTimeMicros = 10 * kMicrosPerMs; // 10 ms. 27 28 class WaitingThread : public base::SimpleThread { 29 public: 30 explicit WaitingThread(MojoDeadline deadline) 31 : base::SimpleThread("waiting_thread"), 32 deadline_(deadline), 33 done_(false), 34 result_(MOJO_RESULT_UNKNOWN), 35 elapsed_micros_(-1) { 36 waiter_.Init(); 37 } 38 39 virtual ~WaitingThread() { 40 Join(); 41 } 42 43 void WaitUntilDone(MojoResult* result, int64_t* elapsed_micros) { 44 for (;;) { 45 { 46 base::AutoLock locker(lock_); 47 if (done_) { 48 *result = result_; 49 *elapsed_micros = elapsed_micros_; 50 break; 51 } 52 } 53 54 base::PlatformThread::Sleep( 55 base::TimeDelta::FromMicroseconds(kPollTimeMicros)); 56 } 57 } 58 59 Waiter* waiter() { return &waiter_; } 60 61 private: 62 virtual void Run() OVERRIDE { 63 test::Stopwatch stopwatch; 64 MojoResult result; 65 int64_t elapsed_micros; 66 67 stopwatch.Start(); 68 result = waiter_.Wait(deadline_); 69 elapsed_micros = stopwatch.Elapsed(); 70 71 { 72 base::AutoLock locker(lock_); 73 done_ = true; 74 result_ = result; 75 elapsed_micros_ = elapsed_micros; 76 } 77 } 78 79 const MojoDeadline deadline_; 80 Waiter waiter_; // Thread-safe. 81 82 base::Lock lock_; // Protects the following members. 83 bool done_; 84 MojoResult result_; 85 int64_t elapsed_micros_; 86 87 DISALLOW_COPY_AND_ASSIGN(WaitingThread); 88 }; 89 90 TEST(WaiterTest, Basic) { 91 MojoResult result; 92 int64_t elapsed_micros; 93 94 // Finite deadline. 95 96 // Awake immediately after thread start. 97 { 98 WaitingThread thread(static_cast<MojoDeadline>(10 * kEpsilonMicros)); 99 thread.Start(); 100 thread.waiter()->Awake(0); 101 thread.WaitUntilDone(&result, &elapsed_micros); 102 EXPECT_EQ(0, result); 103 EXPECT_LT(elapsed_micros, kEpsilonMicros); 104 } 105 106 // Awake before after thread start. 107 { 108 WaitingThread thread(static_cast<MojoDeadline>(10 * kEpsilonMicros)); 109 thread.waiter()->Awake(MOJO_RESULT_CANCELLED); 110 thread.Start(); 111 thread.WaitUntilDone(&result, &elapsed_micros); 112 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 113 EXPECT_LT(elapsed_micros, kEpsilonMicros); 114 } 115 116 // Awake some time after thread start. 117 { 118 WaitingThread thread(static_cast<MojoDeadline>(10 * kEpsilonMicros)); 119 thread.Start(); 120 base::PlatformThread::Sleep( 121 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); 122 thread.waiter()->Awake(1); 123 thread.WaitUntilDone(&result, &elapsed_micros); 124 EXPECT_EQ(1, result); 125 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); 126 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); 127 } 128 129 // Awake some longer time after thread start. 130 { 131 WaitingThread thread(static_cast<MojoDeadline>(10 * kEpsilonMicros)); 132 thread.Start(); 133 base::PlatformThread::Sleep( 134 base::TimeDelta::FromMicroseconds(5 * kEpsilonMicros)); 135 thread.waiter()->Awake(1); 136 thread.WaitUntilDone(&result, &elapsed_micros); 137 EXPECT_EQ(1, result); 138 EXPECT_GT(elapsed_micros, (5-1) * kEpsilonMicros); 139 EXPECT_LT(elapsed_micros, (5+1) * kEpsilonMicros); 140 } 141 142 // Don't awake -- time out (on another thread). 143 { 144 WaitingThread thread(static_cast<MojoDeadline>(2 * kEpsilonMicros)); 145 thread.Start(); 146 thread.WaitUntilDone(&result, &elapsed_micros); 147 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); 148 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); 149 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); 150 } 151 152 // No (indefinite) deadline. 153 154 // Awake immediately after thread start. 155 { 156 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 157 thread.Start(); 158 thread.waiter()->Awake(0); 159 thread.WaitUntilDone(&result, &elapsed_micros); 160 EXPECT_EQ(0, result); 161 EXPECT_LT(elapsed_micros, kEpsilonMicros); 162 } 163 164 // Awake before after thread start. 165 { 166 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 167 thread.waiter()->Awake(MOJO_RESULT_CANCELLED); 168 thread.Start(); 169 thread.WaitUntilDone(&result, &elapsed_micros); 170 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); 171 EXPECT_LT(elapsed_micros, kEpsilonMicros); 172 } 173 174 // Awake some time after thread start. 175 { 176 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 177 thread.Start(); 178 base::PlatformThread::Sleep( 179 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); 180 thread.waiter()->Awake(1); 181 thread.WaitUntilDone(&result, &elapsed_micros); 182 EXPECT_EQ(1, result); 183 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); 184 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); 185 } 186 187 // Awake some longer time after thread start. 188 { 189 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 190 thread.Start(); 191 base::PlatformThread::Sleep( 192 base::TimeDelta::FromMicroseconds(5 * kEpsilonMicros)); 193 thread.waiter()->Awake(1); 194 thread.WaitUntilDone(&result, &elapsed_micros); 195 EXPECT_EQ(1, result); 196 EXPECT_GT(elapsed_micros, (5-1) * kEpsilonMicros); 197 EXPECT_LT(elapsed_micros, (5+1) * kEpsilonMicros); 198 } 199 } 200 201 TEST(WaiterTest, TimeOut) { 202 test::Stopwatch stopwatch; 203 int64_t elapsed_micros; 204 205 Waiter waiter; 206 207 waiter.Init(); 208 stopwatch.Start(); 209 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); 210 elapsed_micros = stopwatch.Elapsed(); 211 EXPECT_LT(elapsed_micros, kEpsilonMicros); 212 213 waiter.Init(); 214 stopwatch.Start(); 215 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, 216 waiter.Wait(static_cast<MojoDeadline>(2 * kEpsilonMicros))); 217 elapsed_micros = stopwatch.Elapsed(); 218 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros); 219 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros); 220 221 waiter.Init(); 222 stopwatch.Start(); 223 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, 224 waiter.Wait(static_cast<MojoDeadline>(5 * kEpsilonMicros))); 225 elapsed_micros = stopwatch.Elapsed(); 226 EXPECT_GT(elapsed_micros, (5-1) * kEpsilonMicros); 227 EXPECT_LT(elapsed_micros, (5+1) * kEpsilonMicros); 228 } 229 230 // The first |Awake()| should always win. 231 TEST(WaiterTest, MultipleAwakes) { 232 MojoResult result; 233 int64_t elapsed_micros; 234 235 { 236 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 237 thread.Start(); 238 thread.waiter()->Awake(0); 239 thread.waiter()->Awake(1); 240 thread.WaitUntilDone(&result, &elapsed_micros); 241 EXPECT_EQ(0, result); 242 EXPECT_LT(elapsed_micros, kEpsilonMicros); 243 } 244 245 { 246 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 247 thread.waiter()->Awake(1); 248 thread.Start(); 249 thread.waiter()->Awake(0); 250 thread.WaitUntilDone(&result, &elapsed_micros); 251 EXPECT_EQ(1, result); 252 EXPECT_LT(elapsed_micros, kEpsilonMicros); 253 } 254 255 { 256 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); 257 thread.Start(); 258 thread.waiter()->Awake(10); 259 base::PlatformThread::Sleep( 260 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); 261 thread.waiter()->Awake(20); 262 thread.WaitUntilDone(&result, &elapsed_micros); 263 EXPECT_EQ(10, result); 264 EXPECT_LT(elapsed_micros, kEpsilonMicros); 265 } 266 267 { 268 WaitingThread thread(static_cast<MojoDeadline>(10 * kEpsilonMicros)); 269 thread.Start(); 270 base::PlatformThread::Sleep( 271 base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros)); 272 thread.waiter()->Awake(MOJO_RESULT_FAILED_PRECONDITION); 273 base::PlatformThread::Sleep( 274 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros)); 275 thread.waiter()->Awake(0); 276 thread.WaitUntilDone(&result, &elapsed_micros); 277 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); 278 EXPECT_GT(elapsed_micros, (1-1) * kEpsilonMicros); 279 EXPECT_LT(elapsed_micros, (1+1) * kEpsilonMicros); 280 } 281 } 282 283 } // namespace 284 } // namespace system 285 } // namespace mojo 286