190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "extensions/common/one_shot_event.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/callback.h"
8e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/lazy_instance.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/location.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/task_runner.h"
12e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/time/time.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using base::TaskRunner;
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace extensions {
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)struct OneShotEvent::TaskInfo {
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  TaskInfo() {}
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  TaskInfo(const tracked_objects::Location& from_here,
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)           const scoped_refptr<TaskRunner>& runner,
22e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch           const base::Closure& task,
23e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch           const base::TimeDelta& delay)
24e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      : from_here(from_here), runner(runner), task(task), delay(delay) {
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(runner.get());  // Detect mistakes with a decent stack frame.
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  tracked_objects::Location from_here;
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_refptr<TaskRunner> runner;
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::Closure task;
30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::TimeDelta delay;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OneShotEvent::OneShotEvent() : signaled_(false) {
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // It's acceptable to construct the OneShotEvent on one thread, but
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // immediately move it to another thread.
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  thread_checker_.DetachFromThread();
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)OneShotEvent::OneShotEvent(bool signaled) : signaled_(signaled) {
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  thread_checker_.DetachFromThread();
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OneShotEvent::~OneShotEvent() {}
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OneShotEvent::Post(const tracked_objects::Location& from_here,
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        const base::Closure& task) const {
45e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  PostImpl(
46e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      from_here, task, base::MessageLoopProxy::current(), base::TimeDelta());
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OneShotEvent::Post(const tracked_objects::Location& from_here,
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        const base::Closure& task,
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        const scoped_refptr<TaskRunner>& runner) const {
52e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  PostImpl(from_here, task, runner, base::TimeDelta());
53e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid OneShotEvent::PostDelayed(const tracked_objects::Location& from_here,
56e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                               const base::Closure& task,
57e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                               const base::TimeDelta& delay) const {
58e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  PostImpl(from_here, task, base::MessageLoopProxy::current(), delay);
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OneShotEvent::Signal() {
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CHECK(!signaled_) << "Only call Signal once.";
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  signaled_ = true;
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // After this point, a call to Post() from one of the queued tasks
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // could proceed immediately, but the fact that this object is
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // single-threaded prevents that from being relevant.
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // We could randomize tasks_ in debug mode in order to check that
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the order doesn't matter...
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < tasks_.size(); ++i) {
74e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const TaskInfo& task = tasks_[i];
75e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (task.delay != base::TimeDelta())
76e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      task.runner->PostDelayedTask(task.from_here, task.task, task.delay);
77e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    else
78e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      task.runner->PostTask(task.from_here, task.task);
79e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
80e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
81e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
82e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid OneShotEvent::PostImpl(const tracked_objects::Location& from_here,
83e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                            const base::Closure& task,
84e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                            const scoped_refptr<TaskRunner>& runner,
85e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                            const base::TimeDelta& delay) const {
86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (is_signaled()) {
89e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (delay != base::TimeDelta())
90e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      runner->PostDelayedTask(from_here, task, delay);
91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    else
92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      runner->PostTask(from_here, task);
93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  } else {
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    tasks_.push_back(TaskInfo(from_here, runner, task, delay));
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace extensions
99