- add sources.
[platform/framework/web/crosswalk.git] / src / cc / trees / blocking_task_runner.cc
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