// 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. #ifndef EXTENSIONS_COMMON_ONE_SHOT_EVENT_H_ #define EXTENSIONS_COMMON_ONE_SHOT_EVENT_H_ #include <vector> #include "base/callback_forward.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" namespace base { class TaskRunner; class TimeDelta; } namespace tracked_objects { class Location; } namespace extensions { // This class represents an event that's expected to happen once. It // allows clients to guarantee that code is run after the OneShotEvent // is signaled. If the OneShotEvent is destroyed before it's // signaled, the delayed closures are destroyed without being run. // // This class is similar to a WaitableEvent combined with several // WaitableEventWatchers, but using it is simpler. // // This class is not thread-safe, and must be used from a single thread. class OneShotEvent { public: OneShotEvent(); // Use the following constructor to create an already signaled event. This is // useful if you construct the event on a different thread from where it is // used, in which case it is not possible to call Signal() just after // construction. explicit OneShotEvent(bool signaled); ~OneShotEvent(); // True if Signal has been called. This function is mostly for // migrating old code; usually calling Post() unconditionally will // result in more readable code. bool is_signaled() const { DCHECK(thread_checker_.CalledOnValidThread()); return signaled_; } // Causes is_signaled() to return true and all queued tasks to be // run in an arbitrary order. This method must only be called once. void Signal(); // Scheduled |task| to be called on |runner| after is_signaled() // becomes true. If called with |delay|, then the task will happen // (roughly) |delay| after is_signaled(), *not* |delay| after the // post. Inside |task|, if this OneShotEvent is still alive, // CHECK(is_signaled()) will never fail (which implies that // OneShotEvent::Reset() doesn't exist). // // If |*this| is destroyed before being released, none of these // tasks will be executed. // // Omitting the |runner| argument indicates that |task| should run // on MessageLoopProxy::current(). // // Tasks may be run in an arbitrary order, not just FIFO. Tasks // will never be called on the current thread before this function // returns. Beware that there's no simple way to wait for all tasks // on a OneShotEvent to complete, so it's almost never safe to use // base::Unretained() when creating one. // // Const because Post() doesn't modify the logical state of this // object (which is just the is_signaled() bit). void Post(const tracked_objects::Location& from_here, const base::Closure& task) const; void Post(const tracked_objects::Location& from_here, const base::Closure& task, const scoped_refptr<base::TaskRunner>& runner) const; void PostDelayed(const tracked_objects::Location& from_here, const base::Closure& task, const base::TimeDelta& delay) const; private: struct TaskInfo; void PostImpl(const tracked_objects::Location& from_here, const base::Closure& task, const scoped_refptr<base::TaskRunner>& runner, const base::TimeDelta& delay) const; base::ThreadChecker thread_checker_; bool signaled_; // The task list is mutable because it's not part of the logical // state of the object. This lets us return const references to the // OneShotEvent to clients that just want to run tasks through it // without worrying that they'll signal the event. // // Optimization note: We could reduce the size of this class to a // single pointer by storing |signaled_| in the low bit of a // pointer, and storing the size and capacity of the array (if any) // on the far end of the pointer. mutable std::vector<TaskInfo> tasks_; }; } // namespace extensions #endif // EXTENSIONS_COMMON_ONE_SHOT_EVENT_H_