Home | History | Annotate | Download | only in trees
      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