OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |