[go: nahoru, domu]

blob: 7008182b52519a2902c913c05c51711c61cfc038 [file] [log] [blame]
// 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 <vector>
#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<TaskRunner> runner =
SequencedTaskRunner::GetCurrentDefault()) const;
void PostDelayed(const Location& from_here,
OnceClosure task,
const TimeDelta& delay,
scoped_refptr<TaskRunner> 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<TaskInfo> tasks_;
};
} // namespace base
#endif // BASE_ONE_SHOT_EVENT_H_