summaryrefslogtreecommitdiffstats
path: root/extensions/common/one_shot_event.cc
blob: a61cac8a21844d84ba4785e4c9197e6ca205e407 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/common/one_shot_event.h"

#include <stddef.h>

#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"

using base::SingleThreadTaskRunner;

namespace extensions {

struct OneShotEvent::TaskInfo {
  TaskInfo() {}
  TaskInfo(const tracked_objects::Location& from_here,
           const scoped_refptr<SingleThreadTaskRunner>& runner,
           const base::Closure& task,
           const base::TimeDelta& delay)
      : from_here(from_here), runner(runner), task(task), delay(delay) {
    CHECK(runner.get());  // Detect mistakes with a decent stack frame.
  }
  tracked_objects::Location from_here;
  scoped_refptr<SingleThreadTaskRunner> runner;
  base::Closure task;
  base::TimeDelta delay;
};

OneShotEvent::OneShotEvent() : signaled_(false) {
  // It's acceptable to construct the OneShotEvent on one thread, but
  // immediately move it to another thread.
  thread_checker_.DetachFromThread();
}
OneShotEvent::OneShotEvent(bool signaled) : signaled_(signaled) {
  thread_checker_.DetachFromThread();
}
OneShotEvent::~OneShotEvent() {}

void OneShotEvent::Post(const tracked_objects::Location& from_here,
                        const base::Closure& task) const {
  PostImpl(from_here, task, base::ThreadTaskRunnerHandle::Get(),
           base::TimeDelta());
}

void OneShotEvent::Post(
    const tracked_objects::Location& from_here,
    const base::Closure& task,
    const scoped_refptr<SingleThreadTaskRunner>& runner) const {
  PostImpl(from_here, task, runner, base::TimeDelta());
}

void OneShotEvent::PostDelayed(const tracked_objects::Location& from_here,
                               const base::Closure& task,
                               const base::TimeDelta& delay) const {
  PostImpl(from_here, task, base::ThreadTaskRunnerHandle::Get(), delay);
}

void OneShotEvent::Signal() {
  DCHECK(thread_checker_.CalledOnValidThread());

  CHECK(!signaled_) << "Only call Signal once.";

  signaled_ = true;
  // After this point, a call to Post() from one of the queued tasks
  // could proceed immediately, but the fact that this object is
  // single-threaded prevents that from being relevant.

  // We could randomize tasks_ in debug mode in order to check that
  // the order doesn't matter...
  for (size_t i = 0; i < tasks_.size(); ++i) {
    const TaskInfo& task = tasks_[i];
    if (task.delay != base::TimeDelta())
      task.runner->PostDelayedTask(task.from_here, task.task, task.delay);
    else
      task.runner->PostTask(task.from_here, task.task);
  }
}

void OneShotEvent::PostImpl(const tracked_objects::Location& from_here,
                            const base::Closure& task,
                            const scoped_refptr<SingleThreadTaskRunner>& runner,
                            const base::TimeDelta& delay) const {
  DCHECK(thread_checker_.CalledOnValidThread());

  if (is_signaled()) {
    if (delay != base::TimeDelta())
      runner->PostDelayedTask(from_here, task, delay);
    else
      runner->PostTask(from_here, task);
  } else {
    tasks_.push_back(TaskInfo(from_here, runner, task, delay));
  }
}

}  // namespace extensions