Index: base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc |
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc b/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc |
index 6db240a743cd85b0f84978cb1483d41075131c66..2439950433ed2c4e2294b551ec0639504d1308d1 100644 |
--- a/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc |
+++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager_unittest.cc |
@@ -14,6 +14,7 @@ |
#include "base/task_scheduler/task_tracker.h" |
#include "base/task_scheduler/task_traits.h" |
#include "base/test/test_timeouts.h" |
+#include "base/threading/simple_thread.h" |
#include "base/threading/thread.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -22,7 +23,7 @@ namespace internal { |
namespace { |
-enum WorkerPoolType { |
+enum WorkerPoolType : size_t { |
BACKGROUND_WORKER_POOL = 0, |
FOREGROUND_WORKER_POOL, |
}; |
@@ -32,6 +33,22 @@ static size_t GetThreadPoolIndexForTraits(const TaskTraits& traits) { |
: FOREGROUND_WORKER_POOL; |
} |
+std::vector<SchedulerWorkerPoolParams> GetParamsVector() { |
+ using StandbyThreadPolicy = SchedulerWorkerPoolParams::StandbyThreadPolicy; |
+ |
+ std::vector<SchedulerWorkerPoolParams> params_vector; |
+ |
+ DCHECK_EQ(BACKGROUND_WORKER_POOL, params_vector.size()); |
+ params_vector.emplace_back("Background", ThreadPriority::BACKGROUND, |
+ StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); |
+ |
+ DCHECK_EQ(FOREGROUND_WORKER_POOL, params_vector.size()); |
+ params_vector.emplace_back("Foreground", ThreadPriority::NORMAL, |
+ StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); |
+ |
+ return params_vector; |
+} |
+ |
class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test { |
public: |
TaskSchedulerSingleThreadTaskRunnerManagerTest() |
@@ -40,34 +57,26 @@ class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test { |
void SetUp() override { |
service_thread_.Start(); |
- using StandbyThreadPolicy = SchedulerWorkerPoolParams::StandbyThreadPolicy; |
- |
- std::vector<SchedulerWorkerPoolParams> params_vector; |
- |
- ASSERT_EQ(BACKGROUND_WORKER_POOL, params_vector.size()); |
- params_vector.emplace_back("Background", ThreadPriority::BACKGROUND, |
- StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); |
- |
- ASSERT_EQ(FOREGROUND_WORKER_POOL, params_vector.size()); |
- params_vector.emplace_back("Foreground", ThreadPriority::NORMAL, |
- StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); |
- |
delayed_task_manager_ = |
MakeUnique<DelayedTaskManager>(service_thread_.task_runner()); |
single_thread_task_runner_manager_ = |
MakeUnique<SchedulerSingleThreadTaskRunnerManager>( |
- params_vector, Bind(&GetThreadPoolIndexForTraits), &task_tracker_, |
- delayed_task_manager_.get()); |
+ GetParamsVector(), Bind(&GetThreadPoolIndexForTraits), |
+ &task_tracker_, delayed_task_manager_.get()); |
} |
void TearDown() override { |
- single_thread_task_runner_manager_->JoinForTesting(); |
- single_thread_task_runner_manager_.reset(); |
+ TearDownSingleThreadTaskRunnerManager(); |
delayed_task_manager_.reset(); |
service_thread_.Stop(); |
} |
protected: |
+ virtual void TearDownSingleThreadTaskRunnerManager() { |
+ single_thread_task_runner_manager_->JoinForTesting(); |
+ single_thread_task_runner_manager_.reset(); |
+ } |
+ |
std::unique_ptr<SchedulerSingleThreadTaskRunnerManager> |
single_thread_task_runner_manager_; |
TaskTracker task_tracker_; |
@@ -250,5 +259,101 @@ TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerTest, |
task_tracker_.Shutdown(); |
} |
+namespace { |
+ |
+class CallJoinFromDifferentThread : public SimpleThread { |
+ public: |
+ CallJoinFromDifferentThread( |
+ SchedulerSingleThreadTaskRunnerManager* manager_to_join) |
+ : SimpleThread("SchedulerSingleThreadTaskRunnerManagerJoinThread"), |
+ manager_to_join_(manager_to_join), |
+ run_started_event_(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED) {} |
+ |
+ ~CallJoinFromDifferentThread() override = default; |
+ |
+ void Run() override { |
+ run_started_event_.Signal(); |
+ manager_to_join_->JoinForTesting(); |
+ } |
+ |
+ void WaitForRunToStart() { run_started_event_.Wait(); } |
+ |
+ private: |
+ SchedulerSingleThreadTaskRunnerManager* const manager_to_join_; |
+ WaitableEvent run_started_event_; |
+ DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread); |
+}; |
+ |
+class TaskSchedulerSingleThreadTaskRunnerManagerJoinTest |
+ : public TaskSchedulerSingleThreadTaskRunnerManagerTest { |
+ public: |
+ TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() = default; |
+ ~TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() override = default; |
+ |
+ protected: |
+ void TearDownSingleThreadTaskRunnerManager() override { |
+ // The tests themselves are responsible for calling JoinForTesting(). |
+ single_thread_task_runner_manager_.reset(); |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest); |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) { |
+ WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED); |
+ WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED); |
+ |
+ { |
+ auto task_runner = single_thread_task_runner_manager_ |
+ ->CreateSingleThreadTaskRunnerWithTraits( |
+ TaskTraits().WithBaseSyncPrimitives()); |
+ EXPECT_TRUE(task_runner->PostTask( |
+ FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running)))); |
+ EXPECT_TRUE(task_runner->PostTask( |
+ FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking)))); |
+ } |
+ |
+ task_running.Wait(); |
+ CallJoinFromDifferentThread join_from_different_thread( |
+ single_thread_task_runner_manager_.get()); |
+ join_from_different_thread.Start(); |
+ join_from_different_thread.WaitForRunToStart(); |
+ task_blocking.Signal(); |
+ join_from_different_thread.Join(); |
+} |
+ |
+TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, |
+ ConcurrentJoinExtraSkippedTask) { |
+ WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED); |
+ WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, |
+ WaitableEvent::InitialState::NOT_SIGNALED); |
+ |
+ { |
+ auto task_runner = single_thread_task_runner_manager_ |
+ ->CreateSingleThreadTaskRunnerWithTraits( |
+ TaskTraits().WithBaseSyncPrimitives()); |
+ EXPECT_TRUE(task_runner->PostTask( |
+ FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running)))); |
+ EXPECT_TRUE(task_runner->PostTask( |
+ FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking)))); |
+ EXPECT_TRUE(task_runner->PostTask(FROM_HERE, Bind(&DoNothing))); |
+ } |
+ |
+ task_running.Wait(); |
+ CallJoinFromDifferentThread join_from_different_thread( |
+ single_thread_task_runner_manager_.get()); |
+ join_from_different_thread.Start(); |
+ join_from_different_thread.WaitForRunToStart(); |
+ task_blocking.Signal(); |
+ join_from_different_thread.Join(); |
+} |
+ |
} // namespace internal |
} // namespace base |