1 // Copyright 2017 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <fbl/function.h> 8 #include <lib/async/receiver.h> 9 10 #include <utility> 11 12 namespace async { 13 14 // Holds content for a packet receiver and its handler. 15 // 16 // After successfully queuing packets to the receiver, the client is responsible 17 // for retaining the structure in memory (and unmodified) until all packets have 18 // been received by the handler or the dispatcher shuts down. There is no way 19 // to cancel a packet which has been queued. 20 // 21 // Multiple packets may be delivered to the same receiver concurrently. 22 // 23 // Concrete implementations: |async::Receiver|, |async::ReceiverMethod|. 24 // Please do not create subclasses of ReceiverBase outside of this library. 25 class ReceiverBase { 26 protected: 27 explicit ReceiverBase(async_receiver_handler_t* handler); 28 ~ReceiverBase(); 29 30 ReceiverBase(const ReceiverBase&) = delete; 31 ReceiverBase(ReceiverBase&&) = delete; 32 ReceiverBase& operator=(const ReceiverBase&) = delete; 33 ReceiverBase& operator=(ReceiverBase&&) = delete; 34 35 public: 36 // Enqueues a packet of data for delivery to a receiver. 37 // 38 // The |data| will be copied into the packet. May be NULL to create a 39 // zero-initialized packet payload. 40 // 41 // Returns |ZX_OK| if the packet was successfully enqueued. 42 // Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down. 43 // Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher. 44 zx_status_t QueuePacket(async_dispatcher_t* dispatcher, const zx_packet_user_t* data = nullptr); 45 46 protected: 47 template <typename T> Dispatch(async_receiver_t * receiver)48 static T* Dispatch(async_receiver_t* receiver) { 49 static_assert(offsetof(ReceiverBase, receiver_) == 0, ""); 50 auto self = reinterpret_cast<ReceiverBase*>(receiver); 51 return static_cast<T*>(self); 52 } 53 54 private: 55 async_receiver_t receiver_; 56 }; 57 58 // A receiver whose handler is bound to a |async::Task::Handler| function. 59 // 60 // Prefer using |async::ReceiverMethod| instead for binding to a fixed class member 61 // function since it is more efficient to dispatch. 62 class Receiver final : public ReceiverBase { 63 public: 64 // Handles receipt of packets containing user supplied data. 65 // 66 // The |status| is |ZX_OK| if the packet was successfully delivered and |data| 67 // contains the information from the packet, otherwise |data| is null. 68 using Handler = fbl::Function<void(async_dispatcher_t* dispatcher, 69 async::Receiver* receiver, 70 zx_status_t status, 71 const zx_packet_user_t* data)>; 72 73 explicit Receiver(Handler handler = nullptr); 74 ~Receiver(); 75 set_handler(Handler handler)76 void set_handler(Handler handler) { handler_ = std::move(handler); } has_handler()77 bool has_handler() const { return !!handler_; } 78 79 private: 80 static void CallHandler(async_dispatcher_t* dispatcher, async_receiver_t* receiver, 81 zx_status_t status, const zx_packet_user_t* data); 82 83 Handler handler_; 84 }; 85 86 // A receiver whose handler is bound to a fixed class member function. 87 // 88 // Usage: 89 // 90 // class Foo { 91 // void Handle(async_dispatcher_t* dispatcher, async::ReceiverBase* receiver, zx_status_t status, 92 // const zx_packet_user_t* data) { ... } 93 // async::ReceiverMethod<Foo, &Foo::Handle> receiver_{this}; 94 // }; 95 template <class Class, 96 void (Class::*method)(async_dispatcher_t* dispatcher, async::ReceiverBase* receiver, 97 zx_status_t status, const zx_packet_user_t* data)> 98 class ReceiverMethod final : public ReceiverBase { 99 public: ReceiverMethod(Class * instance)100 explicit ReceiverMethod(Class* instance) 101 : ReceiverBase(&ReceiverMethod::CallHandler), instance_(instance) {} 102 103 private: CallHandler(async_dispatcher_t * dispatcher,async_receiver_t * receiver,zx_status_t status,const zx_packet_user_t * data)104 static void CallHandler(async_dispatcher_t* dispatcher, async_receiver_t* receiver, 105 zx_status_t status, const zx_packet_user_t* data) { 106 auto self = Dispatch<ReceiverMethod>(receiver); 107 (self->instance_->*method)(dispatcher, self, status, data); 108 } 109 110 Class* const instance_; 111 }; 112 113 } // namespace async 114