blob: ae6d956d85e04eb8b1bf55f9c2b158d54e5808dd [file] [log] [blame]
// Copyright 2022 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.
#ifndef SRC_DEVICES_MISC_DRIVERS_COMPAT_SIMPLE_BINDING_H_
#define SRC_DEVICES_MISC_DRIVERS_COMPAT_SIMPLE_BINDING_H_
#include <lib/async/wait.h>
#include <lib/fidl/cpp/wire/server.h>
#include <lib/fidl/cpp/wire/transaction.h>
#include <lib/fit/function.h>
#include <lib/zx/channel.h>
#include <zircon/fidl.h>
#include <utility>
namespace devfs {
class SimpleBinding;
// A basic implementation of |fidl::Transaction|. Designed to work with
// |fidl::BindSingleInFlightOnly|, which pauses message dispatching when an asynchronous transaction
// is in-flight. The channel is owned by |SimpleBinding|. |SimpleBinding| ownership ping-pongs
// between this transaction and the async dispatcher.
class ChannelTransaction final : public fidl::Transaction {
public:
ChannelTransaction(zx_txid_t txid, std::unique_ptr<SimpleBinding> binding)
: Transaction(), txid_(txid), binding_(std::move(binding)) {}
~ChannelTransaction() final;
ChannelTransaction(ChannelTransaction&& other) noexcept : Transaction(std::move(other)) {
if (this != &other) {
MoveImpl(std::move(other));
}
}
ChannelTransaction& operator=(ChannelTransaction&& other) noexcept {
Transaction::operator=(std::move(other));
if (this != &other) {
MoveImpl(std::move(other));
}
return *this;
}
zx_status_t Reply(fidl::OutgoingMessage* message, fidl::WriteOptions write_options) final;
void Close(zx_status_t epitaph) final;
std::unique_ptr<fidl::Transaction> TakeOwnership() final;
private:
friend SimpleBinding;
void Dispatch(fidl::IncomingHeaderAndMessage& msg);
std::unique_ptr<SimpleBinding> TakeBinding() { return std::move(binding_); }
void MoveImpl(ChannelTransaction&& other) noexcept {
txid_ = other.txid_;
other.txid_ = 0;
binding_ = std::move(other.binding_);
}
zx_txid_t txid_ = 0;
std::unique_ptr<SimpleBinding> binding_ = {};
};
using AnyOnChannelClosedFn = fit::callback<void(fidl::internal::IncomingMessageDispatcher*)>;
class SimpleBinding : private async_wait_t {
public:
SimpleBinding(async_dispatcher_t* dispatcher, zx::channel channel,
fidl::internal::IncomingMessageDispatcher* interface,
AnyOnChannelClosedFn on_channel_closed_fn);
~SimpleBinding();
static void MessageHandler(async_dispatcher_t* dispatcher, async_wait_t* wait, zx_status_t status,
const zx_packet_signal_t* signal);
private:
friend ChannelTransaction;
friend zx_status_t BeginWait(std::unique_ptr<SimpleBinding>* unique_binding);
zx::unowned_channel channel() const { return zx::unowned_channel(async_wait_t::object); }
async_dispatcher_t* dispatcher_;
fidl::internal::IncomingMessageDispatcher* interface_;
AnyOnChannelClosedFn on_channel_closed_fn_;
};
zx_status_t BeginWait(std::unique_ptr<SimpleBinding>* unique_binding);
} // namespace devfs
#endif // SRC_DEVICES_MISC_DRIVERS_COMPAT_SIMPLE_BINDING_H_