blob: a96895d775e45cba482e3ad229f79cdb965e1c25 [file] [log] [blame]
// Copyright 2021 The Fuchsia 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 <lib/async/cpp/wait.h>
#include <lib/zx/event.h>
#include <zircon/types.h>
#include <memory>
// Mixin for representing a type that represents an RPC handler and is owned
// by an async loop. The loop will own both the wrapped type and the RPC
// connection handle.
// Deriving classes should define and implement this function:
// static void HandleEvent(std::unique_ptr<T> event,
// async_dispatcher_t* dispatcher, async::WaitBase* wait,
// zx_status_t status, const zx_packet_signal_t* signal);
template <typename T>
class AsyncLoopOwnedEventHandler {
explicit AsyncLoopOwnedEventHandler(zx::event event)
: wait_(this, event.release(), ZX_USER_SIGNAL_0) {}
~AsyncLoopOwnedEventHandler() {
zx_status_t status = wait_.Cancel();
ZX_ASSERT(status == ZX_OK || status == ZX_ERR_NOT_FOUND);
std::unique_ptr<T> Cancel() {
zx_status_t wait = wait_.Cancel();
if (wait != ZX_OK) {
return nullptr;
return std::unique_ptr<T>(static_cast<T*>(this));
// Begins waiting in |dispatcher| on |event->wait|. This transfers ownership
// of |event| to the dispatcher. The dispatcher returns ownership when the
// handler is invoked.
static zx_status_t BeginWait(std::unique_ptr<T> event, async_dispatcher_t* dispatcher) {
zx_status_t status = event->wait_.Begin(dispatcher);
if (status == ZX_OK) {
[[maybe_unused]] auto ptr = event.release();
return status;
// Entrypoint for the event handler that captures the pointer ownership
// semantics.
void HandleEvent(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
std::unique_ptr<T> self(static_cast<T*>(this));
T::HandleEvent(std::move(self), dispatcher, wait, status, signal);
zx::unowned_event event() const { return zx::unowned_event(wait_.object()); }
// Sets the event to the given handle and returns the old value
zx::event set_event(zx::event h) {
zx::event old(wait_.object());
return old;
using WaitType =
async::WaitMethod<AsyncLoopOwnedEventHandler<T>, &AsyncLoopOwnedEventHandler<T>::HandleEvent>;
WaitType wait_{this, ZX_HANDLE_INVALID, ZX_USER_SIGNAL_0};