|  | // Copyright 2018 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 LIB_FIDL_CPP_THREAD_SAFE_BINDING_SET_H_ | 
|  | #define LIB_FIDL_CPP_THREAD_SAFE_BINDING_SET_H_ | 
|  |  | 
|  | #include <lib/async/dispatcher.h> | 
|  | #include <zircon/compiler.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <memory> | 
|  | #include <mutex> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "lib/fidl/cpp/binding.h" | 
|  |  | 
|  | namespace fidl { | 
|  |  | 
|  | // Manages a set of bindings to implemenations owned by the bound channels. | 
|  | // | 
|  | // The implementation pointer type of the binding is also parameterized, | 
|  | // allowing the use of smart pointer types such as |std::unique_ptr<>| to | 
|  | // reference the implementation. | 
|  | // | 
|  | // This class is thread-safe; bindings may be added or cleared from any thread. | 
|  | // | 
|  | // See also: | 
|  | // | 
|  | //  * |BindingSet|, which is the thread-hostile analog that offers more | 
|  | //    functionality. | 
|  | //  * |InterfacePtrSet|, which is the client analog of |BindingSet|. | 
|  | template <typename Interface, typename ImplPtr = Interface*> | 
|  | class DeprecatedBrokenBindingSet final { | 
|  | public: | 
|  | using Binding = ::fidl::Binding<Interface, ImplPtr>; | 
|  | using StorageType = std::vector<std::unique_ptr<Binding>>; | 
|  |  | 
|  | DeprecatedBrokenBindingSet() = default; | 
|  |  | 
|  | DeprecatedBrokenBindingSet(const DeprecatedBrokenBindingSet&) = delete; | 
|  | DeprecatedBrokenBindingSet& operator=(const DeprecatedBrokenBindingSet&) = delete; | 
|  |  | 
|  | // Adds a binding to the set. | 
|  | // | 
|  | // The given |ImplPtr| is bound to the channel underlying the | 
|  | // |InterfaceRequest|. The binding is removed (and the |~ImplPtr| called) | 
|  | // when the created binding has an error (e.g., if the remote endpoint of | 
|  | // the channel sends an invalid message). | 
|  | // | 
|  | // Whether this method takes ownership of |impl| depends on |ImplPtr|. If | 
|  | // |ImplPtr| is a raw pointer, then this method does not take ownership of | 
|  | // |impl|. If |ImplPtr| is a |unique_ptr|, then running |~ImplPtr| when the | 
|  | // binding generates an error will delete |impl| because |~ImplPtr| is | 
|  | // |~unique_ptr|, which deletes |impl|. | 
|  | // | 
|  | // The impl will use the given async_dispatcher_t in order to read messages | 
|  | // from the channel and to monitor the channel for |ZX_CHANNEL_PEER_CLOSED|. | 
|  | // It is not necessary to use the same async_dispatcher_t for each binding | 
|  | // added. | 
|  | void AddBinding(ImplPtr impl, InterfaceRequest<Interface> request, | 
|  | async_dispatcher_t* dispatcher) { | 
|  | std::lock_guard<std::mutex> guard(lock_); | 
|  | bindings_.push_back( | 
|  | std::make_unique<Binding>(std::forward<ImplPtr>(impl), std::move(request), dispatcher)); | 
|  | auto* binding = bindings_.back().get(); | 
|  | // Set the connection error handler for the newly added Binding to be a | 
|  | // function that will erase it from the vector. | 
|  | binding->set_error_handler( | 
|  | [binding, this](zx_status_t status) { this->RemoveOnError(binding); }); | 
|  | } | 
|  |  | 
|  | // Adds a binding to the set for the given implementation. | 
|  | // | 
|  | // Creates a channel for the binding and returns the client endpoint of | 
|  | // the channel as an |InterfaceHandle|. If |AddBinding| fails to create the | 
|  | // underlying channel, the returned |InterfaceHandle| will return false from | 
|  | // |is_valid()|. | 
|  | // | 
|  | // The given |ImplPtr| is bound to the newly created channel. The binding is | 
|  | // removed (and the |~ImplPtr| called) when the created binding has an error | 
|  | // (e.g., if the remote endpoint of the channel sends an invalid message). | 
|  | // | 
|  | // Whether this method takes ownership of |impl| depends on |ImplPtr|. If | 
|  | // |ImplPtr| is a raw pointer, then this method does not take ownership of | 
|  | // |impl|. If |ImplPtr| is a |unique_ptr|, then running |~ImplPtr| when the | 
|  | // binding generates an error will delete |impl| because |~ImplPtr| is | 
|  | // |~unique_ptr|, which deletes |impl|. | 
|  | InterfaceHandle<Interface> AddBinding(ImplPtr impl, async_dispatcher_t* dispatcher) { | 
|  | InterfaceHandle<Interface> handle; | 
|  | InterfaceRequest<Interface> request = handle.NewRequest(); | 
|  | if (!request) | 
|  | return nullptr; | 
|  | AddBinding(std::forward<ImplPtr>(impl), std::move(request), dispatcher); | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | // Removes all the bindings from the set. | 
|  | // | 
|  | // Closes all the channels associated with this |BindingSet|. | 
|  | void CloseAll() { | 
|  | std::lock_guard<std::mutex> guard(lock_); | 
|  | bindings_.clear(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Called when a binding has an error to remove the binding from the set. | 
|  | void RemoveOnError(Binding* binding) { | 
|  | std::lock_guard<std::mutex> guard(lock_); | 
|  | auto it = | 
|  | std::find_if(bindings_.begin(), bindings_.end(), | 
|  | [binding](const std::unique_ptr<Binding>& b) { return b.get() == binding; }); | 
|  | ZX_DEBUG_ASSERT(it != bindings_.end()); | 
|  | (*it)->set_error_handler(nullptr); | 
|  | bindings_.erase(it); | 
|  | } | 
|  |  | 
|  | std::mutex lock_; | 
|  | StorageType bindings_ __TA_GUARDED(lock_); | 
|  | }; | 
|  |  | 
|  | }  // namespace fidl | 
|  |  | 
|  | #endif  // LIB_FIDL_CPP_THREAD_SAFE_BINDING_SET_H_ |