1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "cc/trees/blocking_task_runner.h" 6 7#include <utility> 8 9#include "base/logging.h" 10#include "base/memory/singleton.h" 11#include "base/message_loop/message_loop_proxy.h" 12 13namespace cc { 14 15struct TaskRunnerPairs { 16 static TaskRunnerPairs* GetInstance() { 17 return Singleton<TaskRunnerPairs>::get(); 18 } 19 20 base::Lock lock; 21 std::vector<scoped_refptr<BlockingTaskRunner> > runners; 22 23 private: 24 friend struct DefaultSingletonTraits<TaskRunnerPairs>; 25}; 26 27// static 28scoped_refptr<BlockingTaskRunner> BlockingTaskRunner::current() { 29 TaskRunnerPairs* task_runners = TaskRunnerPairs::GetInstance(); 30 base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); 31 32 base::AutoLock lock(task_runners->lock); 33 34 scoped_refptr<BlockingTaskRunner> current_task_runner; 35 36 for (size_t i = 0; i < task_runners->runners.size(); ++i) { 37 if (task_runners->runners[i]->thread_id_ == thread_id) { 38 current_task_runner = task_runners->runners[i]; 39 } else if (task_runners->runners[i]->HasOneRef()) { 40 task_runners->runners.erase(task_runners->runners.begin() + i); 41 i--; 42 } 43 } 44 45 if (current_task_runner) 46 return current_task_runner; 47 48 scoped_refptr<BlockingTaskRunner> runner = 49 new BlockingTaskRunner(base::MessageLoopProxy::current()); 50 task_runners->runners.push_back(runner); 51 return runner; 52} 53 54BlockingTaskRunner::BlockingTaskRunner( 55 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 56 : thread_id_(base::PlatformThread::CurrentId()), 57 task_runner_(task_runner), 58 capture_(0) { 59} 60 61BlockingTaskRunner::~BlockingTaskRunner() {} 62 63bool BlockingTaskRunner::BelongsToCurrentThread() { 64 return base::PlatformThread::CurrentId() == thread_id_; 65} 66 67bool BlockingTaskRunner::PostTask(const tracked_objects::Location& from_here, 68 const base::Closure& task) { 69 base::AutoLock lock(lock_); 70 DCHECK(task_runner_.get() || capture_); 71 if (!capture_) 72 return task_runner_->PostTask(from_here, task); 73 captured_tasks_.push_back(task); 74 return true; 75} 76 77void BlockingTaskRunner::SetCapture(bool capture) { 78 DCHECK(BelongsToCurrentThread()); 79 80 std::vector<base::Closure> tasks; 81 82 { 83 base::AutoLock lock(lock_); 84 capture_ += capture ? 1 : -1; 85 DCHECK_GE(capture_, 0); 86 87 if (capture_) 88 return; 89 90 // We're done capturing, so grab all the captured tasks and run them. 91 tasks.swap(captured_tasks_); 92 } 93 for (size_t i = 0; i < tasks.size(); ++i) 94 tasks[i].Run(); 95} 96 97BlockingTaskRunner::CapturePostTasks::CapturePostTasks() 98 : blocking_runner_(BlockingTaskRunner::current()) { 99 blocking_runner_->SetCapture(true); 100} 101 102BlockingTaskRunner::CapturePostTasks::~CapturePostTasks() { 103 blocking_runner_->SetCapture(false); 104} 105 106} // namespace cc 107