blob: fc54be53051ec1c56a6bca3caf83f855b6f124b2 [file] [log] [blame]
// 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_