Commit aaa7fecf authored by Dominik Charousset's avatar Dominik Charousset

Allow users to manually advance multiplexers

parent 75f4f39c
......@@ -287,6 +287,7 @@ public:
size_t middleman_max_consecutive_reads;
size_t middleman_heartbeat_interval;
bool middleman_detach_utility_actors;
bool middleman_detach_multiplexer;
// -- config parameters of the OpenCL module ---------------------------------
......
......@@ -133,6 +133,7 @@ actor_system_config::actor_system_config()
middleman_enable_automatic_connections = false;
middleman_max_consecutive_reads = 50;
middleman_heartbeat_interval = 0;
middleman_detach_multiplexer = true;
// fill our options vector for creating INI and CLI parsers
opt_group{options_, "scheduler"}
.add(scheduler_policy, "policy",
......@@ -193,7 +194,9 @@ actor_system_config::actor_system_config()
.add(middleman_heartbeat_interval, "heartbeat-interval",
"sets the interval (ms) of heartbeat, 0 (default) means disabling it")
.add(middleman_detach_utility_actors, "detach-utility-actors",
"enables or disables detaching of utility actors");
"enables or disables detaching of utility actors")
.add(middleman_detach_multiplexer, "detach-multiplexer",
"enables or disables background activity of the multiplexer");
opt_group(options_, "opencl")
.add(opencl_device_ids, "device-ids",
"restricts which OpenCL devices are accessed by CAF");
......
......@@ -80,6 +80,10 @@ public:
supervisor_ptr make_supervisor() override;
bool try_run_once() override;
void run_once() override;
void run() override;
boost::asio::io_service* pimpl() override;
......
......@@ -285,6 +285,21 @@ multiplexer::supervisor_ptr asio_multiplexer::make_supervisor() {
return std::unique_ptr<asio_supervisor>(new asio_supervisor(service()));
}
bool asio_multiplexer::try_run_once() {
boost::system::error_code ec;
auto num = service().poll(ec);
if (ec)
CAF_RAISE_ERROR(ec.message());
return num > 0;
}
void asio_multiplexer::run_once() {
boost::system::error_code ec;
service().run_one(ec);
if (ec)
CAF_RAISE_ERROR(ec.message());
}
void asio_multiplexer::run() {
CAF_LOG_TRACE("asio-based multiplexer");
boost::system::error_code ec;
......
......@@ -300,6 +300,12 @@ public:
supervisor_ptr make_supervisor() override;
bool poll_once(bool block);
bool try_run_once() override;
void run_once() override;
void run() override;
void add(operation op, native_socket fd, event_handler* ptr);
......
......@@ -96,7 +96,14 @@ public:
/// Creates an instance using the networking backend compiled with CAF.
static std::unique_ptr<multiplexer> make(actor_system& sys);
/// Runs the multiplexers event loop.
/// Exectutes all pending events without blocking.
/// @returns `true` if at least one event was called, `false` otherwise.
virtual bool try_run_once() = 0;
/// Runs at least one event and blocks if needed.
virtual void run_once() = 0;
/// Runs events until all connection are closed.
virtual void run() = 0;
/// Invokes @p fun in the multiplexer's event loop, calling `fun()`
......
......@@ -57,6 +57,10 @@ public:
supervisor_ptr make_supervisor() override;
bool try_run_once() override;
void run_once() override;
void run() override;
scribe_ptr new_scribe(connection_handle);
......
......@@ -308,14 +308,15 @@ namespace network {
}
}
void default_multiplexer::run() {
bool default_multiplexer::poll_once(bool block) {
CAF_LOG_TRACE("epoll()-based multiplexer");
while (shadow_ > 0) {
// Keep running in case of `EINTR`.
for (;;) {
int presult = epoll_wait(epollfd_, pollset_.data(),
static_cast<int>(pollset_.size()), -1);
CAF_LOG_DEBUG("epoll_wait() on " << CAF_ARG(shadow_)
<< " sockets reported " << CAF_ARG(presult)
<< " event(s)");
static_cast<int>(pollset_.size()),
block ? -1 : 0);
CAF_LOG_DEBUG("epoll_wait() on" << shadow_
<< "sockets reported" << presult << "event(s)");
if (presult < 0) {
switch (errno) {
case EINTR: {
......@@ -329,6 +330,8 @@ namespace network {
}
}
}
if (presult == 0)
return false;
auto iter = pollset_.begin();
auto last = iter + presult;
for (; iter != last; ++iter) {
......@@ -340,9 +343,24 @@ namespace network {
handle(me);
}
events_.clear();
return true;
}
}
bool default_multiplexer::try_run_once() {
return poll_once(false);
}
bool default_multiplexer::run_once() {
return poll_once(true);
}
void default_multiplexer::run() {
CAF_LOG_TRACE("epoll()-based multiplexer");
while (shadow_ > 0)
poll_once(true);
}
void default_multiplexer::handle(const default_multiplexer::event& e) {
CAF_LOG_TRACE("e.fd = " << CAF_ARG(e.fd) << ", mask = "
<< CAF_ARG(e.mask));
......@@ -439,9 +457,7 @@ namespace network {
shadow_.push_back(&pipe_reader_);
}
void default_multiplexer::run() {
CAF_LOG_TRACE("poll()-based multiplexer; " << CAF_ARG(input_mask)
<< CAF_ARG(output_mask) << CAF_ARG(error_mask));
bool default_multiplexer::poll_once(bool block) {
// we store the results of poll() in a separate vector , because
// altering the pollset while traversing it is not exactly a
// bright idea ...
......@@ -451,15 +467,15 @@ namespace network {
event_handler* ptr; // nullptr in case of a pipe event
};
std::vector<fd_event> poll_res;
while (!pollset_.empty()) {
for(;;) {
int presult;
CAF_LOG_DEBUG(CAF_ARG(pollset_.size()));
# ifdef CAF_WINDOWS
presult = ::WSAPoll(pollset_.data(),
static_cast<ULONG>(pollset_.size()), -1);
static_cast<ULONG>(pollset_.size()),
block ? -1 : 0);
# else
presult = ::poll(pollset_.data(),
static_cast<nfds_t>(pollset_.size()), -1);
static_cast<nfds_t>(pollset_.size()), block ? -1 : 0);
# endif
if (presult < 0) {
switch (last_socket_error()) {
......@@ -482,6 +498,8 @@ namespace network {
}
continue; // rince and repeat
}
if (presult == 0)
return false;
// scan pollset for events first, because we might alter pollset_
// while running callbacks (not a good idea while traversing it)
CAF_LOG_DEBUG("scan pollset for socket events");
......@@ -508,9 +526,25 @@ namespace network {
handle(me);
}
events_.clear();
return true;
}
}
bool default_multiplexer::try_run_once() {
return poll_once(false);
}
void default_multiplexer::run_once() {
poll_once(true);
}
void default_multiplexer::run() {
CAF_LOG_TRACE("poll()-based multiplexer:" << CAF_ARG(input_mask)
<< CAF_ARG(output_mask) << CAF_ARG(error_mask));
while (!pollset_.empty())
poll_once(true);
}
void default_multiplexer::handle(const default_multiplexer::event& e) {
CAF_ASSERT(e.fd != invalid_native_socket);
CAF_ASSERT(pollset_.size() == shadow_.size());
......
......@@ -257,10 +257,13 @@ void middleman::start() {
for (auto& f : system().config().hook_factories)
hooks_.emplace_back(f(system_));
// Launch backend.
backend_supervisor_ = backend().make_supervisor();
if (system_.config().middleman_detach_multiplexer)
backend_supervisor_ = backend().make_supervisor();
if (!backend_supervisor_) {
// The only backend that returns a `nullptr` is the `test_multiplexer`
// which does not have its own thread but uses the main thread instead.
// Other backends can set `middleman_detach_multiplexer` to false to
// suppress creation of the supervisor.
backend().thread_id(std::this_thread::get_id());
} else {
thread_ = std::thread{[this] {
......
......@@ -251,6 +251,14 @@ auto test_multiplexer::make_supervisor() -> supervisor_ptr {
return nullptr;
}
bool test_multiplexer::try_run_once() {
return try_exec_runnable() || try_read_data() || try_accept_connection();
}
void test_multiplexer::run_once() {
try_run_once();
}
void test_multiplexer::run() {
// nop
}
......
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