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#ifndef CC_TREES_BLOCKING_TASK_RUNNER_H_
6#define CC_TREES_BLOCKING_TASK_RUNNER_H_
7
8#include <vector>
9
10#include "base/location.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/single_thread_task_runner.h"
13#include "base/synchronization/lock.h"
14#include "base/threading/platform_thread.h"
15#include "cc/base/cc_export.h"
16
17namespace cc {
18
19// This class wraps a SingleThreadTaskRunner but allows posted tasks to be
20// run without a round trip through the message loop. This shortcutting
21// removes guarantees about ordering. Tasks posted while the
22// BlockingTaskRunner is in a capturing state will run in order, and tasks
23// posted while the BlockingTaskRunner is /not/ in a capturing state will
24// run in order, but the two sets of tasks will *not* run in order relative
25// to when they were posted.
26//
27// To use this class, post tasks to the task runner returned by
28// BlockingTaskRunner::Create(). The thread it is created on identifies the
29// thread you want the tasks to run on. The SingleThreadTaskRunner which is
30// passed into Create() is used to run tasks that are posted when not in a
31// capturing state.
32//
33// Then, on the thread that the given task runner belongs to, you may
34// instantiate a BlockingTaskRunner::CapturePostTasks. While this object
35// exists, the task runner will collect any PostTasks called on it, posting
36// tasks to that thread from anywhere. This CapturePostTasks object provides
37// a window in time where tasks can shortcut past the MessageLoop. As soon
38// as the CapturePostTasks object is destroyed (goes out of scope), all
39// tasks that had been posted to the thread during the window will be executed
40// immediately.
41//
42// Beware of re-entrancy, make sure the CapturePostTasks object is destroyed at
43// a time when it makes sense for the embedder to call arbitrary things.
44class CC_EXPORT BlockingTaskRunner {
45 public:
46  // Creates a BlockingTaskRunner for a given SingleThreadTaskRunner.
47  // |task_runner| will be used to run the tasks which are posted while we are
48  // not capturing. |task_runner| should belong to same the thread on which
49  // capturing is done.
50  static scoped_ptr<BlockingTaskRunner> Create(
51      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
52
53  ~BlockingTaskRunner();
54
55  // While an object of this type is held alive on a thread, any tasks
56  // posted to the thread will be captured and run as soon as the object
57  // is destroyed, shortcutting past the task runner.
58  class CC_EXPORT CapturePostTasks {
59   public:
60    explicit CapturePostTasks(BlockingTaskRunner* blocking_runner);
61    ~CapturePostTasks();
62
63   private:
64    BlockingTaskRunner* blocking_runner_;
65
66    DISALLOW_COPY_AND_ASSIGN(CapturePostTasks);
67  };
68
69  // True if tasks posted to the BlockingTaskRunner will run on the current
70  // thread.
71  bool BelongsToCurrentThread();
72
73  // Posts a task using the contained SingleThreadTaskRunner unless |capture_|
74  // is true. When |capture_| is true, tasks posted will be caught and stored
75  // until the capturing stops. At that time the tasks will be run directly
76  // instead of being posted to the SingleThreadTaskRunner.
77  bool PostTask(const tracked_objects::Location& from_here,
78                const base::Closure& task);
79
80 private:
81  explicit BlockingTaskRunner(
82      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
83
84  void SetCapture(bool capture);
85
86  base::PlatformThreadId thread_id_;
87  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
88
89  base::Lock lock_;
90  int capture_;
91  std::vector<base::Closure> captured_tasks_;
92
93  DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunner);
94};
95
96}  // namespace cc
97
98#endif  // CC_TREES_BLOCKING_TASK_RUNNER_H_
99