// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_ONE_SHOT_EVENT_H_ #define BASE_ONE_SHOT_EVENT_H_ #include #include "base/base_export.h" #include "base/check.h" #include "base/functional/callback_forward.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" namespace base { class Location; class TimeDelta; // 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 closures are // destroyed without being run. // // This class is similar to a `WaitableEvent` combined with several // `WaitableEventWatcher`s, but using it is simpler. // // This class' methods must be used from a single sequence (although not // necessarily the one in which it has been constructed). // However, there are no restrictions on the `TaskRunner`s used - and hence, the // sequence/thread on which the posted tasks will run. By default they will // be posted to the current sequence's default task runner. class BASE_EXPORT 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_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return signaled_; } // Causes `is_signaled` to return true and all tasks to be posted to their // corresponding task runners in the FIFO order. Note that tasks posted to // different `TaskRunner`s may still execute in arbitrary order. This // method must only be called once. void Signal(); // Schedules `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. // // Tasks are posted in FIFO order, however, tasks may still execute in an // arbitrary order (specified by the combination and type of `TaskRunner`s // used). Tasks will never be called on the current sequence 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. void Post(const Location& from_here, OnceClosure task, scoped_refptr runner = SequencedTaskRunner::GetCurrentDefault()) const; void PostDelayed(const Location& from_here, OnceClosure task, const TimeDelta& delay, scoped_refptr runner = SequencedTaskRunner::GetCurrentDefault()) const; private: struct TaskInfo; SEQUENCE_CHECKER(sequence_checker_); bool signaled_ = false; // 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 tasks_; }; } // namespace base #endif // BASE_ONE_SHOT_EVENT_H_