13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/worker_pool_posix.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <set>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
93f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/condition_variable.h"
1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/lock.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/task.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/waitable_event.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base {
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Peer class to provide passthrough access to PosixDynamicThreadPool internals.
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  explicit PosixDynamicThreadPoolPeer(PosixDynamicThreadPool* pool)
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : pool_(pool) {}
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock* lock() { return &pool_->lock_; }
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable* tasks_available_cv() {
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return &pool_->tasks_available_cv_;
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const std::queue<Task*>& tasks() const { return pool_->tasks_; }
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int num_idle_threads() const { return pool_->num_idle_threads_; }
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable* num_idle_threads_cv() {
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return pool_->num_idle_threads_cv_.get();
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void set_num_idle_threads_cv(ConditionVariable* cv) {
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    pool_->num_idle_threads_cv_.reset(cv);
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PosixDynamicThreadPool* pool_;
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPoolPeer);
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// IncrementingTask's main purpose is to increment a counter.  It also updates a
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// set of unique thread ids, and signals a ConditionVariable on completion.
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Note that since it does not block, there is no way to control the number of
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// threads used if more than one IncrementingTask is consecutively posted to the
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// thread pool, since the first one might finish executing before the subsequent
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// PostTask() calls get invoked.
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass IncrementingTask : public Task {
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  IncrementingTask(Lock* counter_lock,
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   int* counter,
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   Lock* unique_threads_lock,
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   std::set<PlatformThreadId>* unique_threads)
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : counter_lock_(counter_lock),
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        unique_threads_lock_(unique_threads_lock),
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        unique_threads_(unique_threads),
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        counter_(counter) {}
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void Run() {
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AddSelfToUniqueThreadSet();
6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock locked(*counter_lock_);
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    (*counter_)++;
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void AddSelfToUniqueThreadSet() {
6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock locked(*unique_threads_lock_);
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    unique_threads_->insert(PlatformThread::CurrentId());
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock* counter_lock_;
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock* unique_threads_lock_;
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::set<PlatformThreadId>* unique_threads_;
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int* counter_;
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DISALLOW_COPY_AND_ASSIGN(IncrementingTask);
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// BlockingIncrementingTask is a simple wrapper around IncrementingTask that
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// allows for waiting at the start of Run() for a WaitableEvent to be signalled.
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass BlockingIncrementingTask : public Task {
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockingIncrementingTask(Lock* counter_lock,
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           int* counter,
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           Lock* unique_threads_lock,
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           std::set<PlatformThreadId>* unique_threads,
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           Lock* num_waiting_to_start_lock,
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           int* num_waiting_to_start,
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           ConditionVariable* num_waiting_to_start_cv,
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           base::WaitableEvent* start)
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : incrementer_(
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          counter_lock, counter, unique_threads_lock, unique_threads),
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        num_waiting_to_start_lock_(num_waiting_to_start_lock),
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        num_waiting_to_start_(num_waiting_to_start),
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        num_waiting_to_start_cv_(num_waiting_to_start_cv),
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        start_(start) {}
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void Run() {
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    {
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock num_waiting_to_start_locked(*num_waiting_to_start_lock_);
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      (*num_waiting_to_start_)++;
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    num_waiting_to_start_cv_->Signal();
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CHECK(start_->Wait());
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    incrementer_.Run();
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  IncrementingTask incrementer_;
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock* num_waiting_to_start_lock_;
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int* num_waiting_to_start_;
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable* num_waiting_to_start_cv_;
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::WaitableEvent* start_;
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DISALLOW_COPY_AND_ASSIGN(BlockingIncrementingTask);
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass PosixDynamicThreadPoolTest : public testing::Test {
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott protected:
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PosixDynamicThreadPoolTest()
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        peer_(pool_.get()),
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        counter_(0),
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        num_waiting_to_start_(0),
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        start_(true, false) {}
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void SetUp() {
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void TearDown() {
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Wake up the idle threads so they can terminate.
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (pool_.get()) pool_->Terminate();
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void WaitForTasksToStart(int num_tasks) {
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (num_waiting_to_start_ < num_tasks) {
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      num_waiting_to_start_cv_.Wait();
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void WaitForIdleThreads(int num_idle_threads) {
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock pool_locked(*peer_.lock());
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (peer_.num_idle_threads() < num_idle_threads) {
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      peer_.num_idle_threads_cv()->Wait();
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Task* CreateNewIncrementingTask() {
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return new IncrementingTask(&counter_lock_, &counter_,
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                &unique_threads_lock_, &unique_threads_);
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Task* CreateNewBlockingIncrementingTask() {
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return new BlockingIncrementingTask(
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        &counter_lock_, &counter_, &unique_threads_lock_, &unique_threads_,
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        &num_waiting_to_start_lock_, &num_waiting_to_start_,
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        &num_waiting_to_start_cv_, &start_);
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_refptr<base::PosixDynamicThreadPool> pool_;
16721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::PosixDynamicThreadPool::PosixDynamicThreadPoolPeer peer_;
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock counter_lock_;
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int counter_;
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock unique_threads_lock_;
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::set<PlatformThreadId> unique_threads_;
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock num_waiting_to_start_lock_;
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int num_waiting_to_start_;
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable num_waiting_to_start_cv_;
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::WaitableEvent start_;
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace
1793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
18021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(PosixDynamicThreadPoolTest, Basic) {
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(0, peer_.num_idle_threads());
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(0U, unique_threads_.size());
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(0U, peer_.tasks().size());
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add one task and wait for it to be completed.
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewIncrementingTask());
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(1);
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(1U, unique_threads_.size()) <<
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "There should be only one thread allocated for one task.";
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(1, peer_.num_idle_threads());
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(1, counter_);
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add one task and wait for it to be completed.
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewIncrementingTask());
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(1);
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add another 2 tasks.  One should reuse the existing worker thread.
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewBlockingIncrementingTask());
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewBlockingIncrementingTask());
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForTasksToStart(2);
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  start_.Signal();
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(2);
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2U, unique_threads_.size());
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2, peer_.num_idle_threads());
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(3, counter_);
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add two blocking tasks.
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewBlockingIncrementingTask());
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewBlockingIncrementingTask());
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(0, counter_) << "Blocking tasks should not have started yet.";
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForTasksToStart(2);
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  start_.Signal();
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(2);
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2U, unique_threads_.size());
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2, counter_);
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(PosixDynamicThreadPoolTest, Complex) {
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add two non blocking tasks and wait for them to finish.
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewIncrementingTask());
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(1);
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add two blocking tasks, start them simultaneously, and wait for them to
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // finish.
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewBlockingIncrementingTask());
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewBlockingIncrementingTask());
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForTasksToStart(2);
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  start_.Signal();
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(2);
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(3, counter_);
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2, peer_.num_idle_threads());
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(2U, unique_threads_.size());
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wake up all idle threads so they can exit.
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock locked(*peer_.lock());
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (peer_.num_idle_threads() > 0) {
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      peer_.tasks_available_cv()->Signal();
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      peer_.num_idle_threads_cv()->Wait();
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Add another non blocking task.  There are no threads to reuse.
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(CreateNewIncrementingTask());
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WaitForIdleThreads(1);
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(3U, unique_threads_.size());
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(1, peer_.num_idle_threads());
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_EQ(4, counter_);
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
269