thread_pool.cc revision 35883cc623fdf475a4ead1dafcba9e9becc1ed11
102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier#include "casts.h"
20e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "runtime.h"
30e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "stl_util.h"
40e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "thread.h"
50e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier#include "thread_pool.h"
60e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
70e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiernamespace art {
80e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
90e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name,
100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier                                   size_t stack_size)
110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    : thread_pool_(thread_pool),
120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier      name_(name),
130e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier      stack_size_(stack_size) {
140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  const char* reason = "new thread pool worker thread";
15bcc2926b9721f94c17ed98fae5264cc98f0e066fBrian Carlstrom  pthread_attr_t attr;
160e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), reason);
180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  CHECK_PTHREAD_CALL(pthread_create, (&pthread_, &attr, &Callback, this), reason);
190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
210e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPoolWorker::~ThreadPoolWorker() {
230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  CHECK_PTHREAD_CALL(pthread_join, (pthread_, NULL), "thread pool worker shutdown");
240e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
260e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid ThreadPoolWorker::Run() {
270e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  Thread* self = Thread::Current();
2802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Task* task = NULL;
2935883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier  thread_pool_->creation_barier_.Wait(self);
300e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  while ((task = thread_pool_->GetTask(self)) != NULL) {
310e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    task->Run(self);
3202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    task->Finalize();
330e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  }
340e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
350e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
360e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid* ThreadPoolWorker::Callback(void* arg) {
370e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg);
380e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  Runtime* runtime = Runtime::Current();
39664bebf92eb2151b9b570ccd42ac4b6056c3ea9cMathieu Chartier  CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, NULL, false));
400e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Do work until its time to shut down.
410e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  worker->Run();
420e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  runtime->DetachCurrentThread();
430e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  return NULL;
440e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
4602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiervoid ThreadPool::AddTask(Thread* self, Task* task){
470e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  MutexLock mu(self, task_queue_lock_);
480e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  tasks_.push_back(task);
490e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // If we have any waiters, signal one.
500e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  if (waiting_count_ != 0) {
510e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    task_queue_condition_.Signal(self);
520e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  }
530e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
540e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
550e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPool::ThreadPool(size_t num_threads)
560e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  : task_queue_lock_("task queue lock"),
570e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    task_queue_condition_("task queue condition", task_queue_lock_),
580e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    completion_condition_("task completion condition", task_queue_lock_),
590e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    started_(false),
600e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    shutting_down_(false),
6135883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier    waiting_count_(0),
6235883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier    // Add one since the caller of constructor waits on the barrier too.
6335883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier    creation_barier_(num_threads + 1) {
6435883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier  Thread* self = Thread::Current();
650e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  while (GetThreadCount() < num_threads) {
6602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    const std::string name = StringPrintf("Thread pool worker %zu", GetThreadCount());
6702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    threads_.push_back(new ThreadPoolWorker(this, name, ThreadPoolWorker::kDefaultStackSize));
680e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  }
6935883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier  // Wait for all of the threads to attach.
7035883cc623fdf475a4ead1dafcba9e9becc1ed11Mathieu Chartier  creation_barier_.Wait(self);
710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
720e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
730e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu ChartierThreadPool::~ThreadPool() {
74e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier  {
75e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier    Thread* self = Thread::Current();
76e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier    MutexLock mu(self, task_queue_lock_);
77e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier    // Tell any remaining workers to shut down.
78e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier    shutting_down_ = true;
79e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier    // Broadcast to everyone waiting.
80e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier    task_queue_condition_.Broadcast(self);
8102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    completion_condition_.Broadcast(self);
82e46cd75f182a3d738c5e2ef3cc90b2f0b1de56eeMathieu Chartier  }
830e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Wait for the threads to finish.
840e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  STLDeleteElements(&threads_);
850e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
860e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
870e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid ThreadPool::StartWorkers(Thread* self) {
880e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  MutexLock mu(self, task_queue_lock_);
890e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  started_ = true;
900e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  task_queue_condition_.Broadcast(self);
9102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  start_time_ = NanoTime();
9202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  total_wait_time_ = 0;
930e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
940e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
950e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartiervoid ThreadPool::StopWorkers(Thread* self) {
960e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  MutexLock mu(self, task_queue_lock_);
970e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  started_ = false;
980e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
990e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
10002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierTask* ThreadPool::GetTask(Thread* self) {
1010e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  MutexLock mu(self, task_queue_lock_);
10202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  while (!IsShuttingDown()) {
10302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    Task* task = TryGetTaskLocked(self);
10402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    if (task != NULL) {
1050e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier      return task;
1060e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    }
1070e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
1080e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    waiting_count_++;
1090e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    if (waiting_count_ == GetThreadCount() && tasks_.empty()) {
1100e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier      // We may be done, lets broadcast to the completion condition.
1110e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier      completion_condition_.Broadcast(self);
1120e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    }
11302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    const uint64_t wait_start = NanoTime();
1140e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    task_queue_condition_.Wait(self);
11502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    const uint64_t wait_end = NanoTime();
11602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    total_wait_time_ += wait_end - std::max(wait_start, start_time_);
1170e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    waiting_count_--;
1180e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  }
1190e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
1200e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // We are shutting down, return NULL to tell the worker thread to stop looping.
1210e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  return NULL;
1220e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
1230e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
12402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierTask* ThreadPool::TryGetTask(Thread* self) {
1250e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  MutexLock mu(self, task_queue_lock_);
12602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  return TryGetTaskLocked(self);
12702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
12802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
12902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierTask* ThreadPool::TryGetTaskLocked(Thread* self) {
13002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  if (started_ && !tasks_.empty()) {
13102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    Task* task = tasks_.front();
13202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    tasks_.pop_front();
13302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    return task;
13402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
13502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  return NULL;
13602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
13702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
13802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiervoid ThreadPool::Wait(Thread* self, bool do_work) {
13902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Task* task = NULL;
14002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  while ((task = TryGetTask(self)) != NULL) {
14102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    task->Run(self);
14202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    task->Finalize();
14302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
14402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
1450e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  // Wait until each thread is waiting and the task list is empty.
14602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  MutexLock mu(self, task_queue_lock_);
14702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) {
1480e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier    completion_condition_.Wait(self);
1490e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier  }
1500e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}
1510e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier
15202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiersize_t ThreadPool::GetTaskCount(Thread* self){
15302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  MutexLock mu(self, task_queue_lock_);
15402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  return tasks_.size();
15502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
15602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
15702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingWorker::WorkStealingWorker(ThreadPool* thread_pool, const std::string& name,
15802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier                                       size_t stack_size)
15902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    : ThreadPoolWorker(thread_pool, name, stack_size),
16002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      task_(NULL) {
16102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
16202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
16302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
16402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartiervoid WorkStealingWorker::Run() {
16502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Thread* self = Thread::Current();
16602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  Task* task = NULL;
16702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  WorkStealingThreadPool* thread_pool = down_cast<WorkStealingThreadPool*>(thread_pool_);
16802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  while ((task = thread_pool_->GetTask(self)) != NULL) {
16902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    WorkStealingTask* stealing_task = down_cast<WorkStealingTask*>(task);
17002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
17102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    {
17202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      CHECK(task_ == NULL);
17302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      MutexLock mu(self, thread_pool->work_steal_lock_);
17402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      // Register that we are running the task
17502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      ++stealing_task->ref_count_;
17602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      task_ = stealing_task;
17702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    }
17802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    stealing_task->Run(self);
17902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // Mark ourselves as not running a task so that nobody tries to steal from us.
18002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // There is a race condition that someone starts stealing from us at this point. This is okay
18102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // due to the reference counting.
18202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    task_ = NULL;
18302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
18402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    bool finalize;
18502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
18602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // Steal work from tasks until there is none left to steal. Note: There is a race, but
18702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // all that happens when the race occurs is that we steal some work instead of processing a
18802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // task from the queue.
18902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    while (thread_pool->GetTaskCount(self) == 0) {
19002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      WorkStealingTask* steal_from_task  = NULL;
19102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
19202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      {
19302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        MutexLock mu(self, thread_pool->work_steal_lock_);
19402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        // Try finding a task to steal from.
19502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        steal_from_task = thread_pool->FindTaskToStealFrom(self);
19602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        if (steal_from_task != NULL) {
19702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          CHECK_NE(stealing_task, steal_from_task)
19802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier              << "Attempting to steal from completed self task";
19902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          steal_from_task->ref_count_++;
20002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        } else {
20102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          break;
20202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        }
20302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      }
20402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
20502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      if (steal_from_task != NULL) {
20602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        // Task which completed earlier is going to steal some work.
20702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        stealing_task->StealFrom(self, steal_from_task);
20802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
20902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        {
21002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          // We are done stealing from the task, lets decrement its reference count.
21102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          MutexLock mu(self, thread_pool->work_steal_lock_);
21202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          finalize = !--steal_from_task->ref_count_;
21302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        }
21402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
21502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        if (finalize) {
21602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier          steal_from_task->Finalize();
21702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier        }
21802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      }
21902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    }
22002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
22102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    {
22202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      MutexLock mu(self, thread_pool->work_steal_lock_);
22302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      // If nobody is still referencing task_ we can finalize it.
22402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      finalize = !--stealing_task->ref_count_;
22502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    }
22602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
22702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    if (finalize) {
22802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      stealing_task->Finalize();
22902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    }
23002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
23102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
23202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
23302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingWorker::~WorkStealingWorker() {
23402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
23502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
23602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
23702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingThreadPool::WorkStealingThreadPool(size_t num_threads)
23802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    : ThreadPool(0),
23902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      work_steal_lock_("work stealing lock"),
24002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      steal_index_(0) {
24102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  while (GetThreadCount() < num_threads) {
24202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    const std::string name = StringPrintf("Work stealing worker %zu", GetThreadCount());
24302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    threads_.push_back(new WorkStealingWorker(this, name, ThreadPoolWorker::kDefaultStackSize));
24402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
24502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
24602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
24702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingTask* WorkStealingThreadPool::FindTaskToStealFrom(Thread* self) {
24802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  const size_t thread_count = GetThreadCount();
24902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  for (size_t i = 0; i < thread_count; ++i) {
25002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    // TODO: Use CAS instead of lock.
25102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    ++steal_index_;
25202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    if (steal_index_ >= thread_count) {
25302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      steal_index_-= thread_count;
25402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    }
25502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
25602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    WorkStealingWorker* worker = down_cast<WorkStealingWorker*>(threads_[steal_index_]);
25702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    WorkStealingTask* task = worker->task_;
25802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    if (task) {
25902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      // Not null, we can probably steal from this worker.
26002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier      return task;
26102b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier    }
26202b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  }
26302b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  // Couldn't find something to steal.
26402b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier  return NULL;
26502b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
26602b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
26702b6a78038f12c109f95eb31713cfc747f5512f1Mathieu ChartierWorkStealingThreadPool::~WorkStealingThreadPool() {
26802b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
26902b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier}
27002b6a78038f12c109f95eb31713cfc747f5512f1Mathieu Chartier
2710e4627e593bc39f8e3d89c31f8977d55054c07ccMathieu Chartier}  // namespace art
272