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 {
GetInstancecc::TaskRunnerPairs19 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
current()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
BlockingTaskRunner(scoped_refptr<base::SingleThreadTaskRunner> task_runner)61 BlockingTaskRunner::BlockingTaskRunner(
62 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
63 : task_runner_(task_runner), capture_(0) {}
64
~BlockingTaskRunner()65 BlockingTaskRunner::~BlockingTaskRunner() {}
66
PostTask(const tracked_objects::Location & from_here,const base::Closure & task)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
SetCapture(bool capture)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
CapturePostTasks()96 BlockingTaskRunner::CapturePostTasks::CapturePostTasks()
97 : blocking_runner_(BlockingTaskRunner::current()) {
98 blocking_runner_->SetCapture(true);
99 }
100
~CapturePostTasks()101 BlockingTaskRunner::CapturePostTasks::~CapturePostTasks() {
102 blocking_runner_->SetCapture(false);
103 }
104
105 } // namespace cc
106