Unverified Commit a19cb8e6 authored by Samir Halilčević's avatar Samir Halilčević Committed by GitHub

Refactor multiplexer to be an interface

parent bb22e7fe
......@@ -29,7 +29,6 @@ caf_add_component(
${CAF_NET_HEADERS}
SOURCES
caf/detail/convert_ip_endpoint.cpp
caf/detail/pollset_updater.cpp
caf/detail/rfc6455.cpp
caf/detail/rfc6455.test.cpp
caf/net/abstract_actor_shell.cpp
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/detail/pollset_updater.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/action.hpp"
#include "caf/actor_system.hpp"
#include "caf/logger.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include <cstring>
namespace caf::detail {
// -- constructors, destructors, and assignment operators ----------------------
pollset_updater::pollset_updater(net::pipe_socket fd) : fd_(fd) {
// nop
}
// -- factories ----------------------------------------------------------------
std::unique_ptr<pollset_updater> pollset_updater::make(net::pipe_socket fd) {
return std::make_unique<pollset_updater>(fd);
}
// -- interface functions ------------------------------------------------------
error pollset_updater::start(net::socket_manager* owner) {
CAF_LOG_TRACE("");
owner_ = owner;
mpx_ = owner->mpx_ptr();
return net::nonblocking(fd_, true);
}
net::socket pollset_updater::handle() const {
return fd_;
}
void pollset_updater::handle_read_event() {
CAF_LOG_TRACE("");
auto as_mgr = [](intptr_t ptr) {
return intrusive_ptr{reinterpret_cast<net::socket_manager*>(ptr), false};
};
auto add_action = [this](intptr_t ptr) {
auto f = action{intrusive_ptr{reinterpret_cast<action::impl*>(ptr), false}};
mpx_->pending_actions_.push_back(std::move(f));
};
for (;;) {
CAF_ASSERT((buf_.size() - buf_size_) > 0);
auto num_bytes
= read(fd_, make_span(buf_.data() + buf_size_, buf_.size() - buf_size_));
if (num_bytes > 0) {
buf_size_ += static_cast<size_t>(num_bytes);
if (buf_.size() == buf_size_) {
buf_size_ = 0;
auto opcode = static_cast<uint8_t>(buf_[0]);
intptr_t ptr;
memcpy(&ptr, buf_.data() + 1, sizeof(intptr_t));
switch (static_cast<code>(opcode)) {
case code::start_manager:
mpx_->do_start(as_mgr(ptr));
break;
case code::run_action:
add_action(ptr);
break;
case code::shutdown:
CAF_ASSERT(ptr == 0);
mpx_->do_shutdown();
break;
default:
CAF_LOG_ERROR("opcode not recognized: " << CAF_ARG(opcode));
break;
}
}
} else if (num_bytes == 0) {
CAF_LOG_DEBUG("pipe closed, assume shutdown");
owner_->deregister();
return;
} else if (net::last_socket_error_is_temporary()) {
return;
} else {
CAF_LOG_ERROR("pollset updater failed to read from the pipe");
owner_->deregister();
return;
}
}
}
void pollset_updater::handle_write_event() {
owner_->deregister_writing();
}
void pollset_updater::abort(const error&) {
// nop
}
} // namespace caf::detail
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/net/pipe_socket.hpp"
#include "caf/net/socket_event_layer.hpp"
#include "caf/net/socket_manager.hpp"
#include "caf/detail/net_export.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <mutex>
namespace caf::detail {
class CAF_NET_EXPORT pollset_updater : public net::socket_event_layer {
public:
// -- member types -----------------------------------------------------------
using super = net::socket_manager;
using msg_buf = std::array<std::byte, sizeof(intptr_t) + 1>;
enum class code : uint8_t {
start_manager,
shutdown_reading,
shutdown_writing,
run_action,
shutdown,
};
// -- constructors, destructors, and assignment operators --------------------
explicit pollset_updater(net::pipe_socket fd);
// -- factories --------------------------------------------------------------
static std::unique_ptr<pollset_updater> make(net::pipe_socket fd);
// -- implementation of socket_event_layer -----------------------------------
error start(net::socket_manager* owner) override;
net::socket handle() const override;
void handle_read_event() override;
void handle_write_event() override;
void abort(const error& reason) override;
private:
net::pipe_socket fd_;
net::socket_manager* owner_ = nullptr;
net::multiplexer* mpx_ = nullptr;
msg_buf buf_;
size_t buf_size_ = 0;
};
} // namespace caf::detail
......@@ -90,12 +90,6 @@ enum class errc;
} // namespace caf::net::octet_stream
namespace caf::detail {
class pollset_updater;
} // namespace caf::detail
namespace caf::net::lp {
class client;
......
This diff is collapsed.
......@@ -5,54 +5,25 @@
#pragma once
#include "caf/net/fwd.hpp"
#include "caf/net/pipe_socket.hpp"
#include "caf/net/socket.hpp"
#include "caf/action.hpp"
#include "caf/async/execution_context.hpp"
#include "caf/detail/atomic_ref_counted.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/ref_counted.hpp"
#include "caf/unordered_flat_map.hpp"
#include <deque>
#include <memory>
#include <mutex>
#include <thread>
extern "C" {
struct pollfd;
} // extern "C"
namespace caf::net {
/// Multiplexes any number of ::socket_manager objects with a ::socket.
class CAF_NET_EXPORT multiplexer : public detail::atomic_ref_counted,
public async::execution_context {
class CAF_NET_EXPORT multiplexer : public async::execution_context {
public:
// -- member types -----------------------------------------------------------
struct poll_update {
short events = 0;
socket_manager_ptr mgr;
};
using poll_update_map = unordered_flat_map<socket, poll_update>;
using pollfd_list = std::vector<pollfd>;
using manager_list = std::vector<socket_manager_ptr>;
// -- friends ----------------------------------------------------------------
friend class detail::pollset_updater; // Needs access to the `do_*` functions.
// -- static utility functions -----------------------------------------------
/// Blocks the PIPE signal on the current thread when running on a POSIX
/// windows. Has no effect when running on Windows.
/// Blocks the PIPE signal on the current thread when running on Linux. Has no
/// effect otherwise.
static void block_sigpipe();
/// Returns a pointer to the multiplexer from the actor system.
......@@ -60,179 +31,79 @@ public:
// -- constructors, destructors, and assignment operators --------------------
~multiplexer();
~multiplexer() override;
// -- factories --------------------------------------------------------------
/// Creates a new multiplexer instance with the default implementation.
/// @param parent Points to the owning middleman instance. May be `nullptr`
/// only for the purpose of unit testing if no @ref
/// socket_manager requires access to the @ref middleman or the
/// @ref actor_system.
static multiplexer_ptr make(middleman* parent) {
auto ptr = new multiplexer(parent);
return multiplexer_ptr{ptr, false};
}
static multiplexer_ptr make(middleman* parent);
// -- initialization ---------------------------------------------------------
error init();
virtual error init() = 0;
// -- properties -------------------------------------------------------------
/// Returns the number of currently active socket managers.
size_t num_socket_managers() const noexcept;
/// Returns the index of `mgr` in the pollset or `-1`.
ptrdiff_t index_of(const socket_manager_ptr& mgr) const noexcept;
/// Returns the index of `fd` in the pollset or `-1`.
ptrdiff_t index_of(socket fd) const noexcept;
virtual size_t num_socket_managers() const noexcept = 0;
/// Returns the owning @ref middleman instance.
middleman& owner();
virtual middleman& owner() = 0;
/// Returns the enclosing @ref actor_system.
actor_system& system();
// -- implementation of execution_context ------------------------------------
void ref_execution_context() const noexcept override;
void deref_execution_context() const noexcept override;
void schedule(action what) override;
void watch(disposable what) override;
virtual actor_system& system() = 0;
// -- thread-safe signaling --------------------------------------------------
/// Registers `mgr` for initialization in the multiplexer's thread.
/// @thread-safe
void start(socket_manager_ptr mgr);
virtual void start(socket_manager_ptr mgr) = 0;
/// Signals the multiplexer to initiate shutdown.
/// @thread-safe
void shutdown();
virtual void shutdown() = 0;
// -- callbacks for socket managers ------------------------------------------
/// Registers `mgr` for read events.
void register_reading(socket_manager* mgr);
virtual void register_reading(socket_manager* mgr) = 0;
/// Registers `mgr` for write events.
void register_writing(socket_manager* mgr);
virtual void register_writing(socket_manager* mgr) = 0;
/// Deregisters `mgr` from read events.
void deregister_reading(socket_manager* mgr);
virtual void deregister_reading(socket_manager* mgr) = 0;
/// Deregisters `mgr` from write events.
void deregister_writing(socket_manager* mgr);
virtual void deregister_writing(socket_manager* mgr) = 0;
/// Deregisters @p mgr from read and write events.
void deregister(socket_manager* mgr);
virtual void deregister(socket_manager* mgr) = 0;
/// Queries whether `mgr` is currently registered for reading.
bool is_reading(const socket_manager* mgr) const noexcept;
virtual bool is_reading(const socket_manager* mgr) const noexcept = 0;
/// Queries whether `mgr` is currently registered for writing.
bool is_writing(const socket_manager* mgr) const noexcept;
virtual bool is_writing(const socket_manager* mgr) const noexcept = 0;
// -- control flow -----------------------------------------------------------
/// Polls I/O activity once and runs all socket event handlers that become
/// ready as a result.
bool poll_once(bool blocking);
/// Runs `poll_once(false)` until it returns `true`.`
void poll();
virtual bool poll_once(bool blocking) = 0;
/// Applies all pending updates.
void apply_updates();
/// Runs all pending actions.
void run_actions();
virtual void apply_updates() = 0;
/// Sets the thread ID to `std::this_thread::id()`.
void set_thread_id();
virtual void set_thread_id() = 0;
/// Runs the multiplexer until no socket event handler remains active.
void run();
protected:
// -- utility functions ------------------------------------------------------
/// Handles an I/O event on given manager.
void handle(const socket_manager_ptr& mgr, short events, short revents);
/// Returns a change entry for the socket at given index. Lazily creates a new
/// entry before returning if necessary.
poll_update& update_for(ptrdiff_t index);
/// Returns a change entry for the socket of the manager.
poll_update& update_for(socket_manager* mgr);
/// Writes `opcode` and pointer to `mgr` the the pipe for handling an event
/// later via the pollset updater.
/// @warning assumes ownership of @p ptr.
template <class T>
void write_to_pipe(uint8_t opcode, T* ptr);
/// @copydoc write_to_pipe
template <class Enum, class T>
std::enable_if_t<std::is_enum_v<Enum>> write_to_pipe(Enum opcode, T* ptr) {
write_to_pipe(static_cast<uint8_t>(opcode), ptr);
}
/// Queries the currently active event bitmask for `mgr`.
short active_mask_of(const socket_manager* mgr) const noexcept;
// -- member variables -------------------------------------------------------
/// Bookkeeping data for managed sockets.
pollfd_list pollset_;
/// Maps sockets to their owning managers by storing the managers in the same
/// order as their sockets appear in `pollset_`.
manager_list managers_;
/// Caches changes to the events mask of managed sockets until they can safely
/// take place.
poll_update_map updates_;
/// Stores the ID of the thread this multiplexer is running in. Set when
/// calling `init()`.
std::thread::id tid_;
/// Guards `write_handle_`.
std::mutex write_lock_;
/// Used for pushing updates to the multiplexer's thread.
pipe_socket write_handle_;
/// Points to the owning middleman.
middleman* owner_;
/// Signals whether shutdown has been requested.
bool shutting_down_ = false;
/// Pending actions via `schedule`.
std::deque<action> pending_actions_;
/// Keeps track of watched disposables.
std::vector<disposable> watched_;
private:
// -- constructors, destructors, and assignment operators --------------------
explicit multiplexer(middleman* parent);
// -- internal callbacks the pollset updater ---------------------------------
void do_shutdown();
void do_register_reading(const socket_manager_ptr& mgr);
void do_start(const socket_manager_ptr& mgr);
virtual void run() = 0;
};
} // namespace caf::net
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment