// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_CORE_WATCHER_DISPATCHER_H_
#define MOJO_CORE_WATCHER_DISPATCHER_H_
#include <stdint.h>
#include <set>
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/lock.h"
#include "mojo/core/dispatcher.h"
#include "mojo/core/handle_signals_state.h"
#include "mojo/core/system_impl_export.h"
#include "mojo/public/c/system/trap.h"
namespace mojo {
namespace core {
class Watch;
// The dispatcher type which backs watcher handles.
class WatcherDispatcher : public Dispatcher {
public:
// Constructs a new WatcherDispatcher which invokes |handler| when a
// registered watch observes some relevant state change.
explicit WatcherDispatcher(MojoTrapEventHandler handler);
WatcherDispatcher(const WatcherDispatcher&) = delete;
WatcherDispatcher& operator=(const WatcherDispatcher&) = delete;
// Methods used by watched dispatchers to notify watchers of events.
void NotifyHandleState(Dispatcher* dispatcher,
const HandleSignalsState& state);
void NotifyHandleClosed(Dispatcher* dispatcher);
// Method used by RequestContext (indirectly, via Watch) to complete
// notification operations from a safe stack frame to avoid reentrancy.
void InvokeWatchCallback(uintptr_t context,
MojoResult result,
const HandleSignalsState& state,
MojoTrapEventFlags flags);
// Dispatcher:
Type GetType() const override;
MojoResult Close() override;
MojoResult WatchDispatcher(scoped_refptr<Dispatcher> dispatcher,
MojoHandleSignals signals,
MojoTriggerCondition condition,
uintptr_t context) override;
MojoResult CancelWatch(uintptr_t context) override;
MojoResult Arm(uint32_t* num_blocking_events,
MojoTrapEvent* blocking_events) override;
private:
friend class Watch;
using WatchSet = std::set<raw_ptr<const Watch, SetExperimental>>;
~WatcherDispatcher() override;
const MojoTrapEventHandler handler_;
// Guards access to the fields below.
//
// NOTE: This may be acquired while holding another dispatcher's lock, as
// watched dispatchers call into WatcherDispatcher methods which lock this
// when issuing state change notifications. WatcherDispatcher must therefore
// take caution to NEVER acquire other dispatcher locks while this is held.
base::Lock lock_;
bool armed_ = false;
bool closed_ = false;
// A mapping from context to Watch.
base::flat_map<uintptr_t, scoped_refptr<Watch>> watches_;
// A mapping from watched dispatcher to Watch.
base::flat_map<Dispatcher*, scoped_refptr<Watch>> watched_handles_;
// The set of all Watch instances which are currently ready to signal. This is
// used for efficient arming behavior, as it allows for O(1) discovery of
// whether or not arming can succeed and quick determination of who's
// responsible if it can't.
WatchSet ready_watches_;
// Tracks the last Watch whose state was returned by Arm(). This is used to
// ensure consistent round-robin behavior in the event that multiple Watches
// remain ready over the span of several Arm() attempts.
//
// NOTE: This can point toward a deleted Watch, so it must never be
// dereferenced. This is only used to do arithmetical comparisons in the
// |ready_watches_| set, so it is represented by a uintptr_t. Using a raw_ptr
// would force the allocator to quarantine the allocation and delay its reuse.
uintptr_t last_watch_to_block_arming_ = 0;
};
} // namespace core
} // namespace mojo
#endif // MOJO_CORE_WATCHER_DISPATCHER_H_