Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Side by Side Diff: mojo/edk/system/wait_set_dispatcher_unittest.cc

Issue 2090353004: Add a basic threaded test for WaitSetDispatcher. (Closed) Base URL: https://github.com/domokit/mojo.git@work790_wait_set_5
Patch Set: doh Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 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
5 #include "mojo/edk/system/wait_set_dispatcher.h" 10 #include "mojo/edk/system/wait_set_dispatcher.h"
6 11
12 #include <thread>
13
14 #include "mojo/edk/platform/test_stopwatch.h"
15 #include "mojo/edk/platform/thread_utils.h"
7 #include "mojo/edk/system/mock_simple_dispatcher.h" 16 #include "mojo/edk/system/mock_simple_dispatcher.h"
17 #include "mojo/edk/system/test/timeouts.h"
8 #include "testing/gtest/include/gtest/gtest.h" 18 #include "testing/gtest/include/gtest/gtest.h"
9 19
20 using mojo::platform::test::Stopwatch;
21 using mojo::platform::ThreadSleep;
10 using mojo::util::MakeRefCounted; 22 using mojo::util::MakeRefCounted;
11 23
12 namespace mojo { 24 namespace mojo {
13 namespace system { 25 namespace system {
14 namespace { 26 namespace {
15 27
16 // Helper to check if an array of |MojoWaitSetResult|s has a result |r| for the 28 // Helper to check if an array of |MojoWaitSetResult|s has a result |r| for the
17 // given cookie, in which case: 29 // given cookie, in which case:
18 // - |r.wait_result| must equal |wait_result|. 30 // - |r.wait_result| must equal |wait_result|.
19 // - If |wait_result| is |MOJO_RESULT_OK| or 31 // - If |wait_result| is |MOJO_RESULT_OK| or
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 } 213 }
202 214
203 // Can close a dispatcher that's "in" the wait set. This should make 215 // Can close a dispatcher that's "in" the wait set. This should make
204 // |kCookie1| "cancelled". 216 // |kCookie1| "cancelled".
205 EXPECT_EQ(MOJO_RESULT_OK, d_member1->Close()); 217 EXPECT_EQ(MOJO_RESULT_OK, d_member1->Close());
206 218
207 // Wait. 219 // Wait.
208 { 220 {
209 uint32_t num_results = 10u; 221 uint32_t num_results = 10u;
210 MojoWaitSetResult results[10] = {}; 222 MojoWaitSetResult results[10] = {};
211 uint32_t max_results = static_cast<uint32_t>(-1); 223 // Try passing null for |max_results|.
212 EXPECT_EQ(MOJO_RESULT_OK, 224 EXPECT_EQ(MOJO_RESULT_OK,
213 d->WaitSetWait(k10ms, MakeUserPointer(&num_results), 225 d->WaitSetWait(k10ms, MakeUserPointer(&num_results),
214 MakeUserPointer(results), 226 MakeUserPointer(results), NullUserPointer()));
215 MakeUserPointer(&max_results)));
216 EXPECT_EQ(3u, num_results); 227 EXPECT_EQ(3u, num_results);
217 EXPECT_EQ(3u, max_results);
218 228
219 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0, 229 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0,
220 MOJO_RESULT_OK, 230 MOJO_RESULT_OK,
221 d_member0->GetHandleSignalsState())); 231 d_member0->GetHandleSignalsState()));
222 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1, 232 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1,
223 MOJO_RESULT_CANCELLED, 233 MOJO_RESULT_CANCELLED,
224 MojoHandleSignalsState())); 234 MojoHandleSignalsState()));
225 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2, 235 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2,
226 MOJO_RESULT_FAILED_PRECONDITION, 236 MOJO_RESULT_FAILED_PRECONDITION,
227 d_member0->GetHandleSignalsState())); 237 d_member0->GetHandleSignalsState()));
228 } 238 }
229 239
240 // Wait with zero |num_results| (in which case a null |results| is OK).
241 {
242 uint32_t num_results = 0u;
243 uint32_t max_results = static_cast<uint32_t>(-1);
244 EXPECT_EQ(MOJO_RESULT_OK,
245 d->WaitSetWait(k10ms, MakeUserPointer(&num_results),
246 NullUserPointer(), MakeUserPointer(&max_results)));
247 EXPECT_EQ(0u, num_results);
248 EXPECT_EQ(3u, max_results);
249 }
250
230 // Can remove something whose dispatcher has been closed. 251 // Can remove something whose dispatcher has been closed.
231 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetRemove(kCookie1)); 252 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetRemove(kCookie1));
232 253
233 // Can close the wait set when it's not empty. 254 // Can close the wait set when it's not empty.
234 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); 255 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
235 256
236 EXPECT_EQ(MOJO_RESULT_OK, d_member0->Close()); 257 EXPECT_EQ(MOJO_RESULT_OK, d_member0->Close());
237 } 258 }
238 259
260 TEST(WaitSetDispatcherTest, TimeOut) {
261 Stopwatch stopwatch;
262
263 auto d = WaitSetDispatcher::Create(WaitSetDispatcher::kDefaultCreateOptions);
264
265 // Wait with timeout without any entries.
266 {
267 uint32_t num_results = 1u;
268 MojoWaitSetResult results[1] = {{456u}};
269 uint32_t max_results = 789u;
270 stopwatch.Start();
271 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
272 d->WaitSetWait(
273 2 * test::EpsilonTimeout(), MakeUserPointer(&num_results),
274 MakeUserPointer(results), MakeUserPointer(&max_results)));
275 MojoDeadline elapsed = stopwatch.Elapsed();
276 EXPECT_GT(elapsed, test::EpsilonTimeout());
277 EXPECT_LT(elapsed, 3 * test::EpsilonTimeout());
278 // The inputs should be untouched.
279 EXPECT_EQ(1u, num_results);
280 EXPECT_EQ(456u, results[0].cookie);
281 EXPECT_EQ(789u, max_results);
282 }
283
284 auto d_member = MakeRefCounted<test::MockSimpleDispatcher>(
285 MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE);
286 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member.Clone(),
287 MOJO_HANDLE_SIGNAL_READABLE, 123u));
288
289 // Wait with timeout with an unsatisfied (but satisfiable) entry.
290 {
291 uint32_t num_results = 1u;
292 MojoWaitSetResult results[1] = {{456u}};
293 uint32_t max_results = 789u;
294 stopwatch.Start();
295 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
296 d->WaitSetWait(
297 2 * test::EpsilonTimeout(), MakeUserPointer(&num_results),
298 MakeUserPointer(results), MakeUserPointer(&max_results)));
299 MojoDeadline elapsed = stopwatch.Elapsed();
300 EXPECT_GT(elapsed, test::EpsilonTimeout());
301 EXPECT_LT(elapsed, 3 * test::EpsilonTimeout());
302 // The inputs should be untouched.
303 EXPECT_EQ(1u, num_results);
304 EXPECT_EQ(456u, results[0].cookie);
305 EXPECT_EQ(789u, max_results);
306 }
307
308 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
309 EXPECT_EQ(MOJO_RESULT_OK, d_member->Close());
310 }
311
312 TEST(WaitSetDispatcherTest, BasicThreaded) {
313 static constexpr auto kNone = MOJO_HANDLE_SIGNAL_NONE;
314 static constexpr auto kR = MOJO_HANDLE_SIGNAL_READABLE;
315 static constexpr auto kW = MOJO_HANDLE_SIGNAL_WRITABLE;
316
317 const auto epsilon = test::EpsilonTimeout();
318
319 auto d = WaitSetDispatcher::Create(WaitSetDispatcher::kDefaultCreateOptions);
320
321 // These will be members of our wait set.
322 auto d_member0 = MakeRefCounted<test::MockSimpleDispatcher>(kNone, kR | kW);
323 auto d_member1 = MakeRefCounted<test::MockSimpleDispatcher>(kNone, kR);
324
325 // Add |d_member0|.
326 static constexpr uint64_t kCookie0 = 123u;
327 static constexpr auto kSignals0 = kR;
328 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member0.Clone(),
329 kSignals0, kCookie0));
330
331 // Add |d_member1|.
332 static constexpr uint64_t kCookie1 = 456u;
333 static constexpr auto kSignals1 = kR;
334 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member1.Clone(),
335 kSignals1, kCookie1));
336
337 // Can add |d_member0| again with a different cookie.
338 static constexpr uint64_t kCookie2 = 789u;
339 static constexpr auto kSignals2 = kW;
340 EXPECT_EQ(MOJO_RESULT_OK, d->WaitSetAdd(NullUserPointer(), d_member0.Clone(),
341 kSignals2, kCookie2));
342
343 // We'll wait on the main thread, and do stuff on another thread.
344
345 {
346 // Trigger |kCookie0|.
347 std::thread t([epsilon, d_member0]() {
348 // Sleep to try to ensure that waiting has started.
349 ThreadSleep(epsilon);
350 d_member0->SetSatisfiedSignals(kR);
351 });
352
353 uint32_t num_results = 10u;
354 MojoWaitSetResult results[10] = {};
355 uint32_t max_results = static_cast<uint32_t>(-1);
356 EXPECT_EQ(MOJO_RESULT_OK,
357 d->WaitSetWait(3 * epsilon, MakeUserPointer(&num_results),
358 MakeUserPointer(results),
359 MakeUserPointer(&max_results)));
360 EXPECT_EQ(1u, num_results);
361 EXPECT_EQ(1u, max_results);
362
363 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0,
364 MOJO_RESULT_OK,
365 d_member0->GetHandleSignalsState()));
366
367 t.join();
368 }
369
370 // Untrigger |kCookie0|.
371 d_member0->SetSatisfiedSignals(kNone);
372
373 {
374 // Make |kCookie2| unsatisfiable.
375 std::thread t([epsilon, d_member0]() {
376 // Sleep to try to ensure that waiting has started.
377 ThreadSleep(epsilon);
378 d_member0->SetSatisfiableSignals(kR);
379 });
380
381 uint32_t num_results = 10u;
382 MojoWaitSetResult results[10] = {};
383 EXPECT_EQ(MOJO_RESULT_OK,
384 d->WaitSetWait(3 * epsilon, MakeUserPointer(&num_results),
385 MakeUserPointer(results), NullUserPointer()));
386 EXPECT_EQ(1u, num_results);
387
388 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2,
389 MOJO_RESULT_FAILED_PRECONDITION,
390 d_member0->GetHandleSignalsState()));
391
392 t.join();
393 }
394
395 {
396 // Trigger |kCookie1|.
397 std::thread t(
398 [epsilon, d_member1]() { d_member1->SetSatisfiedSignals(kR); });
399
400 // Sleep to try to ensure that |kCookie1| has been triggered.
401 ThreadSleep(epsilon);
402
403 uint32_t num_results = 10u;
404 MojoWaitSetResult results[10] = {};
405 EXPECT_EQ(MOJO_RESULT_OK,
406 d->WaitSetWait(3 * epsilon, MakeUserPointer(&num_results),
407 MakeUserPointer(results), NullUserPointer()));
408 EXPECT_EQ(2u, num_results);
409
410 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie1, kSignals1,
411 MOJO_RESULT_OK,
412 d_member1->GetHandleSignalsState()));
413 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2,
414 MOJO_RESULT_FAILED_PRECONDITION,
415 d_member0->GetHandleSignalsState()));
416
417 t.join();
418 }
419
420 // Make |kCookie0| satisfiable again.
421 d_member0->SetSatisfiableSignals(kR | kW);
422 // Untrigger |kCookie1|.
423 d_member1->SetSatisfiedSignals(kNone);
424
425 {
426 // Cancel |kCookie0| and |kCookie2| by closing |d_member0|.
427 std::thread t([epsilon, d_member0]() {
428 // Sleep to try to ensure that waiting has started.
429 ThreadSleep(epsilon);
430 EXPECT_EQ(MOJO_RESULT_OK, d_member0->Close());
431 });
432
433 uint32_t num_results = 10u;
434 MojoWaitSetResult results[10] = {};
435 EXPECT_EQ(MOJO_RESULT_OK,
436 d->WaitSetWait(3 * epsilon, MakeUserPointer(&num_results),
437 MakeUserPointer(results), NullUserPointer()));
438 EXPECT_EQ(2u, num_results);
439
440 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie0, kSignals0,
441 MOJO_RESULT_CANCELLED,
442 MojoHandleSignalsState()));
443 EXPECT_TRUE(CheckHasResult(num_results, results, kCookie2, kSignals2,
444 MOJO_RESULT_CANCELLED,
445 MojoHandleSignalsState()));
446
447 t.join();
448 }
449
450 EXPECT_EQ(MOJO_RESULT_OK, d_member1->Close());
451 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
452 }
453
454 // TODO(vtl): Test adding/removing on another thread.
455 // TODO(vtl): Test waiting on multiple threads.
456 // TODO(vtl): Stress tests.
457
239 // TODO(vtl): Test options validation for "create" and "add" (not that there's 458 // TODO(vtl): Test options validation for "create" and "add" (not that there's
240 // much to test). 459 // much to test).
241 460
242 } // namespace 461 } // namespace
243 } // namespace system 462 } // namespace system
244 } // namespace mojo 463 } // namespace mojo
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698