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

Side by Side Diff: base/task_scheduler/scheduler_worker_unittest.cc

Issue 2686593003: DESIGN DISCUSSION ONLY Task Scheduler Single Thread Task Runner Manager for Dedicated Threads per S… (Closed)
Patch Set: Wait for Detached Thread to Complete Created 3 years, 10 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
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 #include "base/task_scheduler/scheduler_worker.h" 5 #include "base/task_scheduler/scheduler_worker.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <memory>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/synchronization/condition_variable.h" 16 #include "base/synchronization/condition_variable.h"
17 #include "base/synchronization/waitable_event.h" 17 #include "base/synchronization/waitable_event.h"
18 #include "base/task_scheduler/scheduler_lock.h" 18 #include "base/task_scheduler/scheduler_lock.h"
19 #include "base/task_scheduler/sequence.h" 19 #include "base/task_scheduler/sequence.h"
20 #include "base/task_scheduler/task.h" 20 #include "base/task_scheduler/task.h"
21 #include "base/task_scheduler/task_tracker.h" 21 #include "base/task_scheduler/task_tracker.h"
22 #include "base/test/test_timeouts.h"
22 #include "base/threading/platform_thread.h" 23 #include "base/threading/platform_thread.h"
23 #include "base/time/time.h" 24 #include "base/time/time.h"
24 #include "build/build_config.h" 25 #include "build/build_config.h"
25 #include "testing/gmock/include/gmock/gmock.h" 26 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h" 27 #include "testing/gtest/include/gtest/gtest.h"
27 28
28 #if defined(OS_WIN) 29 #if defined(OS_WIN)
29 #include <objbase.h> 30 #include <objbase.h>
30 #endif 31 #endif
31 32
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 TaskSchedulerWorkerTest, 349 TaskSchedulerWorkerTest,
349 ::testing::Values(1)); 350 ::testing::Values(1));
350 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, 351 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence,
351 TaskSchedulerWorkerTest, 352 TaskSchedulerWorkerTest,
352 ::testing::Values(2)); 353 ::testing::Values(2));
353 354
354 namespace { 355 namespace {
355 356
356 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { 357 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate {
357 public: 358 public:
358 ControllableDetachDelegate(TaskTracker* task_tracker) 359 ControllableDetachDelegate()
359 : task_tracker_(task_tracker), 360 : work_processed_(WaitableEvent::ResetPolicy::MANUAL,
360 work_processed_(WaitableEvent::ResetPolicy::MANUAL,
361 WaitableEvent::InitialState::NOT_SIGNALED), 361 WaitableEvent::InitialState::NOT_SIGNALED),
362 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, 362 detach_requested_(WaitableEvent::ResetPolicy::MANUAL,
363 WaitableEvent::InitialState::NOT_SIGNALED), 363 WaitableEvent::InitialState::NOT_SIGNALED),
364 detached_(WaitableEvent::ResetPolicy::MANUAL, 364 detached_(WaitableEvent::ResetPolicy::MANUAL,
365 WaitableEvent::InitialState::NOT_SIGNALED) { 365 WaitableEvent::InitialState::NOT_SIGNALED) {}
366 EXPECT_TRUE(task_tracker_);
367 }
368 366
369 ~ControllableDetachDelegate() override = default; 367 ~ControllableDetachDelegate() override = default;
370 368
371 // SchedulerWorker::Delegate: 369 // SchedulerWorker::Delegate:
372 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); 370 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker));
373 371
374 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) 372 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker)
375 override { 373 override {
376 // Sends one item of work to signal |work_processed_|. On subsequent calls, 374 // Sends one item of work to signal |work_processed_|. On subsequent calls,
377 // sends nullptr to indicate there's no more work to be done. 375 // sends nullptr to indicate there's no more work to be done.
378 if (work_requested_) 376 if (work_requested_)
379 return nullptr; 377 return nullptr;
380 378
381 work_requested_ = true; 379 work_requested_ = true;
382 scoped_refptr<Sequence> sequence(new Sequence); 380 scoped_refptr<Sequence> sequence(new Sequence);
383 std::unique_ptr<Task> task(new Task( 381 std::unique_ptr<Task> task(new Task(
384 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), 382 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)),
385 TaskTraits(), TimeDelta())); 383 TaskTraits(), TimeDelta()));
386 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); 384 EXPECT_TRUE(task_tracker_.WillPostTask(task.get()));
387 sequence->PushTask(std::move(task)); 385 sequence->PushTask(std::move(task));
388 return sequence; 386 return sequence;
389 } 387 }
390 388
391 void DidRunTask() override {} 389 void DidRunTask() override {}
392 390
393 bool CanDetach(SchedulerWorker* worker) override { 391 bool CanDetach(SchedulerWorker* worker) override {
394 detach_requested_.Signal(); 392 detach_requested_.Signal();
395 return can_detach_; 393 return can_detach_;
396 } 394 }
(...skipping 15 matching lines...) Expand all
412 void WaitForDetach() { detached_.Wait(); } 410 void WaitForDetach() { detached_.Wait(); }
413 411
414 void ResetState() { 412 void ResetState() {
415 work_requested_ = false; 413 work_requested_ = false;
416 work_processed_.Reset(); 414 work_processed_.Reset();
417 detach_requested_.Reset(); 415 detach_requested_.Reset();
418 } 416 }
419 417
420 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } 418 void set_can_detach(bool can_detach) { can_detach_ = can_detach; }
421 419
420 // This delegate owns the TaskTracker because during detachment, threads may
421 // outlive the test case.
fdoray 2017/02/08 17:59:02 I think this is no longer true if you do https://c
robliao 2017/02/11 02:13:34 That is true. Removed.
422 TaskTracker* task_tracker() { return &task_tracker_; }
423
422 private: 424 private:
423 TaskTracker* const task_tracker_; 425 TaskTracker task_tracker_;
424 bool work_requested_ = false; 426 bool work_requested_ = false;
425 bool can_detach_ = false; 427 bool can_detach_ = false;
426 WaitableEvent work_processed_; 428 WaitableEvent work_processed_;
427 WaitableEvent detach_requested_; 429 WaitableEvent detach_requested_;
428 WaitableEvent detached_; 430 WaitableEvent detached_;
429 431
430 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); 432 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate);
431 }; 433 };
432 434
433 } // namespace 435 } // namespace
434 436
435 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { 437 TEST(TaskSchedulerWorkerTest, WorkerDetaches) {
436 TaskTracker task_tracker;
437 // Will be owned by SchedulerWorker. 438 // Will be owned by SchedulerWorker.
438 ControllableDetachDelegate* delegate = 439 ControllableDetachDelegate* delegate =
439 new StrictMock<ControllableDetachDelegate>(&task_tracker); 440 new StrictMock<ControllableDetachDelegate>();
440 delegate->set_can_detach(true); 441 delegate->set_can_detach(true);
441 EXPECT_CALL(*delegate, OnMainEntry(_)); 442 EXPECT_CALL(*delegate, OnMainEntry(_));
442 std::unique_ptr<SchedulerWorker> worker = 443 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create(
443 SchedulerWorker::Create( 444 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(),
444 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, 445 SchedulerWorker::InitialState::ALIVE);
445 SchedulerWorker::InitialState::ALIVE);
446 worker->WakeUp(); 446 worker->WakeUp();
447 delegate->WaitForWorkToRun(); 447 delegate->WaitForWorkToRun();
448 Mock::VerifyAndClear(delegate); 448 Mock::VerifyAndClear(delegate);
449 delegate->WaitForDetachRequest(); 449 delegate->WaitForDetachRequest();
450 delegate->WaitForDetach(); 450 delegate->WaitForDetach();
451 ASSERT_FALSE(worker->ThreadAliveForTesting()); 451 ASSERT_FALSE(worker->ThreadAliveForTesting());
452 } 452 }
453 453
454 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { 454 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroys) {
455 TaskTracker task_tracker; 455 // This test shouldn't crash or leak resources.
456 // Will be owned by SchedulerWorker. 456 // Will be owned by SchedulerWorker.
457 ControllableDetachDelegate* delegate = 457 ControllableDetachDelegate* delegate =
458 new StrictMock<ControllableDetachDelegate>(&task_tracker); 458 new StrictMock<ControllableDetachDelegate>();
459 delegate->set_can_detach(true); 459 delegate->set_can_detach(true);
460 EXPECT_CALL(*delegate, OnMainEntry(_)); 460 EXPECT_CALL(*delegate, OnMainEntry(_));
461 std::unique_ptr<SchedulerWorker> worker = 461 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create(
462 SchedulerWorker::Create( 462 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(),
463 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, 463 SchedulerWorker::InitialState::ALIVE);
464 SchedulerWorker::InitialState::ALIVE); 464 worker->WakeUp();
465 SchedulerWorker::DestroyAfterDetachment(std::move(worker));
466 // Give a chance for the other thread to clean up.
fdoray 2017/02/08 17:59:02 You could signal an event in ~ControllableDetachDe
robliao 2017/02/11 02:13:34 I went with a refcounted event instead.
467 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
468 }
469
470 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) {
471 // Will be owned by SchedulerWorker.
472 ControllableDetachDelegate* delegate =
473 new StrictMock<ControllableDetachDelegate>();
474 delegate->set_can_detach(true);
475 EXPECT_CALL(*delegate, OnMainEntry(_));
476 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create(
477 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(),
478 SchedulerWorker::InitialState::ALIVE);
465 worker->WakeUp(); 479 worker->WakeUp();
466 delegate->WaitForWorkToRun(); 480 delegate->WaitForWorkToRun();
467 Mock::VerifyAndClear(delegate); 481 Mock::VerifyAndClear(delegate);
468 delegate->WaitForDetachRequest(); 482 delegate->WaitForDetachRequest();
469 delegate->WaitForDetach(); 483 delegate->WaitForDetach();
470 ASSERT_FALSE(worker->ThreadAliveForTesting()); 484 ASSERT_FALSE(worker->ThreadAliveForTesting());
471 485
472 delegate->ResetState(); 486 delegate->ResetState();
473 delegate->set_can_detach(false); 487 delegate->set_can_detach(false);
474 // Expect OnMainEntry() to be called when SchedulerWorker recreates its 488 // Expect OnMainEntry() to be called when SchedulerWorker recreates its
475 // thread. 489 // thread.
476 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); 490 EXPECT_CALL(*delegate, OnMainEntry(worker.get()));
477 worker->WakeUp(); 491 worker->WakeUp();
478 delegate->WaitForWorkToRun(); 492 delegate->WaitForWorkToRun();
479 Mock::VerifyAndClear(delegate); 493 Mock::VerifyAndClear(delegate);
480 delegate->WaitForDetachRequest(); 494 delegate->WaitForDetachRequest();
481 delegate->WaitForDetach(); 495 delegate->WaitForDetach();
482 ASSERT_TRUE(worker->ThreadAliveForTesting()); 496 ASSERT_TRUE(worker->ThreadAliveForTesting());
483 worker->JoinForTesting(); 497 worker->JoinForTesting();
484 } 498 }
485 499
486 TEST(TaskSchedulerWorkerTest, CreateDetached) { 500 TEST(TaskSchedulerWorkerTest, CreateDetached) {
487 TaskTracker task_tracker;
488 // Will be owned by SchedulerWorker. 501 // Will be owned by SchedulerWorker.
489 ControllableDetachDelegate* delegate = 502 ControllableDetachDelegate* delegate =
490 new StrictMock<ControllableDetachDelegate>(&task_tracker); 503 new StrictMock<ControllableDetachDelegate>();
491 std::unique_ptr<SchedulerWorker> worker = 504 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create(
492 SchedulerWorker::Create( 505 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(),
493 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, 506 SchedulerWorker::InitialState::DETACHED);
494 SchedulerWorker::InitialState::DETACHED);
495 ASSERT_FALSE(worker->ThreadAliveForTesting()); 507 ASSERT_FALSE(worker->ThreadAliveForTesting());
496 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); 508 EXPECT_CALL(*delegate, OnMainEntry(worker.get()));
497 worker->WakeUp(); 509 worker->WakeUp();
498 delegate->WaitForWorkToRun(); 510 delegate->WaitForWorkToRun();
499 Mock::VerifyAndClear(delegate); 511 Mock::VerifyAndClear(delegate);
500 delegate->WaitForDetachRequest(); 512 delegate->WaitForDetachRequest();
501 ASSERT_TRUE(worker->ThreadAliveForTesting()); 513 ASSERT_TRUE(worker->ThreadAliveForTesting());
502 worker->JoinForTesting(); 514 worker->JoinForTesting();
503 } 515 }
504 516
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
676 // COM library wasn't already initialized on the thread. 688 // COM library wasn't already initialized on the thread.
677 EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); 689 EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult());
678 690
679 worker->JoinForTesting(); 691 worker->JoinForTesting();
680 } 692 }
681 693
682 #endif // defined(OS_WIN) 694 #endif // defined(OS_WIN)
683 695
684 } // namespace internal 696 } // namespace internal
685 } // namespace base 697 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698