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 13 namespace cc { 14 15 typedef std::pair<base::SingleThreadTaskRunner*, 16 scoped_refptr<BlockingTaskRunner> > TaskRunnerPair; 17 18 struct TaskRunnerPairs { 19 static TaskRunnerPairs* GetInstance() { 20 return Singleton<TaskRunnerPairs>::get(); 21 } 22 23 base::Lock lock; 24 std::vector<TaskRunnerPair> pairs; 25 26 private: 27 friend struct DefaultSingletonTraits<TaskRunnerPairs>; 28 }; 29 30 // static 31 scoped_refptr<BlockingTaskRunner> BlockingTaskRunner::current() { 32 TaskRunnerPairs* task_runners = TaskRunnerPairs::GetInstance(); 33 34 base::AutoLock lock(task_runners->lock); 35 36 for (size_t i = 0; i < task_runners->pairs.size(); ++i) { 37 if (task_runners->pairs[i].first->HasOneRef()) { 38 // The SingleThreadTaskRunner is kept alive by its MessageLoop, and we 39 // hold a second reference in the TaskRunnerPairs array. If the 40 // SingleThreadTaskRunner has one ref, then it is being held alive only 41 // by the BlockingTaskRunner and the MessageLoop is gone, so drop the 42 // BlockingTaskRunner from the TaskRunnerPairs array along with the 43 // SingleThreadTaskRunner. 44 task_runners->pairs.erase(task_runners->pairs.begin() + i); 45 --i; 46 } 47 } 48 49 scoped_refptr<base::SingleThreadTaskRunner> current = 50 base::MessageLoopProxy::current(); 51 for (size_t i = 0; i < task_runners->pairs.size(); ++i) { 52 if (task_runners->pairs[i].first == current.get()) 53 return task_runners->pairs[i].second.get(); 54 } 55 56 scoped_refptr<BlockingTaskRunner> runner = new BlockingTaskRunner(current); 57 task_runners->pairs.push_back(TaskRunnerPair(current, runner)); 58 return runner; 59 } 60 61 BlockingTaskRunner::BlockingTaskRunner( 62 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 63 : task_runner_(task_runner), capture_(0) {} 64 65 BlockingTaskRunner::~BlockingTaskRunner() {} 66 67 bool BlockingTaskRunner::PostTask(const tracked_objects::Location& from_here, 68 const base::Closure& task) { 69 base::AutoLock lock(lock_); 70 if (!capture_) 71 return task_runner_->PostTask(from_here, task); 72 captured_tasks_.push_back(task); 73 return true; 74 } 75 76 void BlockingTaskRunner::SetCapture(bool capture) { 77 DCHECK(BelongsToCurrentThread()); 78 79 std::vector<base::Closure> tasks; 80 81 { 82 base::AutoLock lock(lock_); 83 capture_ += capture ? 1 : -1; 84 DCHECK_GE(capture_, 0); 85 86 if (capture_) 87 return; 88 89 // We're done capturing, so grab all the captured tasks and run them. 90 tasks.swap(captured_tasks_); 91 } 92 for (size_t i = 0; i < tasks.size(); ++i) 93 tasks[i].Run(); 94 } 95 96 BlockingTaskRunner::CapturePostTasks::CapturePostTasks() 97 : blocking_runner_(BlockingTaskRunner::current()) { 98 blocking_runner_->SetCapture(true); 99 } 100 101 BlockingTaskRunner::CapturePostTasks::~CapturePostTasks() { 102 blocking_runner_->SetCapture(false); 103 } 104 105 } // namespace cc 106