| OLD | NEW |
| (Empty) |
| 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 | |
| 22 namespace mojo { | |
| 23 namespace system { | |
| 24 namespace { | |
| 25 | |
| 26 const int64_t kMicrosPerMs = 1000; | |
| 27 const int64_t kPollTimeMicros = 10 * kMicrosPerMs; // 10 ms. | |
| 28 | |
| 29 class 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 | |
| 95 TEST(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 | |
| 212 TEST(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. | |
| 246 TEST(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 | |
| OLD | NEW |