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