普通文本  |  99行  |  3.28 KB

// 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 "base/callback.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/task_runner.h"
#include "base/time/time.h"

using base::TaskRunner;

namespace extensions {

struct OneShotEvent::TaskInfo {
  TaskInfo() {}
  TaskInfo(const tracked_objects::Location& from_here,
           const scoped_refptr<TaskRunner>& 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<TaskRunner> 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::MessageLoopProxy::current(), base::TimeDelta());
}

void OneShotEvent::Post(const tracked_objects::Location& from_here,
                        const base::Closure& task,
                        const scoped_refptr<TaskRunner>& 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::MessageLoopProxy::current(), 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<TaskRunner>& 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