| // 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_ |