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