Commit 656499e5 authored by Dominik Charousset's avatar Dominik Charousset

Simplify calls to CAF_AFTER_PROCESSING

parent e608ad30
......@@ -594,6 +594,14 @@ bool operator==(const logger::field& x, const logger::field& y);
#define CAF_LOG_FINALIZE_EVENT() \
CAF_LOG_IMPL(CAF_LOG_FLOW_COMPONENT, CAF_LOG_LEVEL_DEBUG, "FINALIZE")
#define CAF_LOG_SKIP_OR_FINALIZE_EVENT(invoke_result) \
do { \
if (invoke_result == caf::invoke_message_result::skipped) \
CAF_LOG_SKIP_EVENT(); \
else \
CAF_LOG_FINALIZE_EVENT(); \
} while (false)
#define CAF_LOG_TERMINATE_EVENT(thisptr, rsn) \
CAF_LOG_IMPL(CAF_LOG_FLOW_COMPONENT, CAF_LOG_LEVEL_DEBUG, \
"TERMINATE ; ID =" << thisptr->id() \
......@@ -616,6 +624,8 @@ bool operator==(const logger::field& x, const logger::field& y);
#define CAF_LOG_SKIP_EVENT() CAF_VOID_STMT
#define CAF_LOG_SKIP_OR_FINALIZE_EVENT(unused) CAF_VOID_STMT
#define CAF_LOG_FINALIZE_EVENT() CAF_VOID_STMT
#define CAF_LOG_TERMINATE_EVENT(thisptr, rsn) CAF_VOID_STMT
......
......@@ -157,74 +157,75 @@ void blocking_actor::fail_state(error err) {
}
intrusive::task_result
blocking_actor::mailbox_visitor:: operator()(mailbox_element& x) {
blocking_actor::mailbox_visitor::operator()(mailbox_element& x) {
CAF_LOG_TRACE(CAF_ARG(x));
CAF_LOG_RECEIVE_EVENT((&x));
CAF_BEFORE_PROCESSING(self, x);
auto check_if_done = [&]() -> intrusive::task_result {
// Stop consuming items when reaching the end of the user-defined receive
// loop either via post or pre condition.
if (rcc.post() && rcc.pre())
return intrusive::task_result::resume;
done = true;
return intrusive::task_result::stop;
};
// Skip messages that don't match our message ID.
if (mid.is_response()) {
if (mid != x.mid) {
CAF_AFTER_PROCESSING(self, invoke_message_result::skipped);
CAF_LOG_SKIP_EVENT();
// Wrap the actual body for the function.
auto body = [this, &x] {
auto check_if_done = [&]() -> intrusive::task_result {
// Stop consuming items when reaching the end of the user-defined receive
// loop either via post or pre condition.
if (rcc.post() && rcc.pre())
return intrusive::task_result::resume;
done = true;
return intrusive::task_result::stop;
};
// Skip messages that don't match our message ID.
if (mid.is_response()) {
if (mid != x.mid) {
return intrusive::task_result::skip;
}
} else if (x.mid.is_response()) {
return intrusive::task_result::skip;
}
} else if (x.mid.is_response()) {
CAF_AFTER_PROCESSING(self, invoke_message_result::skipped);
CAF_LOG_SKIP_EVENT();
return intrusive::task_result::skip;
}
// Automatically unlink from actors after receiving an exit.
if (x.content().match_elements<exit_msg>())
self->unlink_from(x.content().get_as<exit_msg>(0).source);
// Blocking actors can nest receives => push/pop `current_element_`
auto prev_element = self->current_element_;
self->current_element_ = &x;
auto g = detail::make_scope_guard([&] {
self->current_element_ = prev_element;
});
// Dispatch on x.
detail::default_invoke_result_visitor<blocking_actor> visitor{self};
switch (bhvr.nested(visitor, x.content())) {
default:
CAF_AFTER_PROCESSING(self, invoke_message_result::consumed);
return check_if_done();
case match_case::no_match:
{ // Blocking actors can have fallback handlers for catch-all rules.
// Automatically unlink from actors after receiving an exit.
if (x.content().match_elements<exit_msg>())
self->unlink_from(x.content().get_as<exit_msg>(0).source);
// Blocking actors can nest receives => push/pop `current_element_`
auto prev_element = self->current_element_;
self->current_element_ = &x;
auto g = detail::make_scope_guard(
[&] { self->current_element_ = prev_element; });
// Dispatch on x.
detail::default_invoke_result_visitor<blocking_actor> visitor{self};
switch (bhvr.nested(visitor, x.content())) {
default:
return check_if_done();
case match_case::no_match: { // Blocking actors can have fallback handlers
// for catch-all rules.
auto sres = bhvr.fallback(*self->current_element_);
if (sres.flag != rt_skip) {
CAF_AFTER_PROCESSING(self, invoke_message_result::consumed);
visitor.visit(sres);
CAF_LOG_FINALIZE_EVENT();
return check_if_done();
}
}
// Response handlers must get re-invoked with an error when receiving an
// unexpected message.
if (mid.is_response()) {
auto err = make_error(sec::unexpected_response,
x.move_content_to_message());
mailbox_element_view<error> tmp{std::move(x.sender), x.mid,
std::move(x.stages), err};
self->current_element_ = &tmp;
bhvr.nested(tmp.content());
CAF_AFTER_PROCESSING(self, invoke_message_result::consumed);
CAF_LOG_FINALIZE_EVENT();
return check_if_done();
}
CAF_ANNOTATE_FALLTHROUGH;
case match_case::skip:
CAF_AFTER_PROCESSING(self, invoke_message_result::skipped);
CAF_LOG_SKIP_EVENT();
return intrusive::task_result::skip;
// Response handlers must get re-invoked with an error when receiving an
// unexpected message.
if (mid.is_response()) {
auto err = make_error(sec::unexpected_response,
x.move_content_to_message());
mailbox_element_view<error> tmp{std::move(x.sender), x.mid,
std::move(x.stages), err};
self->current_element_ = &tmp;
bhvr.nested(tmp.content());
return check_if_done();
}
CAF_ANNOTATE_FALLTHROUGH;
case match_case::skip:
return intrusive::task_result::skip;
}
};
// Post-process the returned value from the function body.
auto result = body();
if (result == intrusive::task_result::skip) {
CAF_AFTER_PROCESSING(self, invoke_message_result::skipped);
CAF_LOG_SKIP_EVENT();
} else {
CAF_AFTER_PROCESSING(self, invoke_message_result::consumed);
CAF_LOG_FINALIZE_EVENT();
}
return result;
}
void blocking_actor::receive_impl(receive_cond& rcc,
......
......@@ -32,104 +32,100 @@ invoke_message_result raw_event_based_actor::consume(mailbox_element& x) {
current_element_ = &x;
CAF_LOG_RECEIVE_EVENT(current_element_);
CAF_BEFORE_PROCESSING(this, x);
// short-circuit awaited responses
if (!awaited_responses_.empty()) {
auto& pr = awaited_responses_.front();
// skip all messages until we receive the currently awaited response
if (x.mid != pr.first)
return invoke_message_result::skipped;
if (!pr.second(x.content())) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
pr.second(msg);
}
awaited_responses_.pop_front();
CAF_AFTER_PROCESSING(this, invoke_message_result::consumed);
return invoke_message_result::consumed;
}
// handle multiplexed responses
if (x.mid.is_response()) {
auto mrh = multiplexed_responses_.find(x.mid);
// neither awaited nor multiplexed, probably an expired timeout
if (mrh == multiplexed_responses_.end()) {
CAF_AFTER_PROCESSING(this, invoke_message_result::dropped);
return invoke_message_result::dropped;
}
if (!mrh->second(x.content())) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
mrh->second(msg);
// Wrap the actual body for the function.
auto body = [this, &x] {
// short-circuit awaited responses
if (!awaited_responses_.empty()) {
auto& pr = awaited_responses_.front();
// skip all messages until we receive the currently awaited response
if (x.mid != pr.first)
return invoke_message_result::skipped;
if (!pr.second(x.content())) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
pr.second(msg);
}
awaited_responses_.pop_front();
return invoke_message_result::consumed;
}
multiplexed_responses_.erase(mrh);
CAF_AFTER_PROCESSING(this, invoke_message_result::consumed);
return invoke_message_result::consumed;
}
auto& content = x.content();
// handle timeout messages
if (x.content().type_token() == make_type_token<timeout_msg>()) {
auto& tm = content.get_as<timeout_msg>(0);
auto tid = tm.timeout_id;
CAF_ASSERT(x.mid.is_async());
if (is_active_receive_timeout(tid)) {
CAF_LOG_DEBUG("handle timeout message");
if (bhvr_stack_.empty()) {
CAF_AFTER_PROCESSING(this, invoke_message_result::dropped);
// handle multiplexed responses
if (x.mid.is_response()) {
auto mrh = multiplexed_responses_.find(x.mid);
// neither awaited nor multiplexed, probably an expired timeout
if (mrh == multiplexed_responses_.end())
return invoke_message_result::dropped;
if (!mrh->second(x.content())) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
mrh->second(msg);
}
bhvr_stack_.back().handle_timeout();
CAF_AFTER_PROCESSING(this, invoke_message_result::consumed);
multiplexed_responses_.erase(mrh);
return invoke_message_result::consumed;
}
CAF_LOG_DEBUG("dropped expired timeout message");
CAF_AFTER_PROCESSING(this, invoke_message_result::dropped);
return invoke_message_result::dropped;
}
// handle everything else as ordinary message
detail::default_invoke_result_visitor<event_based_actor> visitor{this};
bool skipped = false;
auto had_timeout = getf(has_timeout_flag);
if (had_timeout)
unsetf(has_timeout_flag);
// restore timeout at scope exit if message was skipped
auto timeout_guard = detail::make_scope_guard([&] {
if (skipped && had_timeout)
setf(has_timeout_flag);
});
auto call_default_handler = [&] {
auto sres = call_handler(default_handler_, this, x);
switch (sres.flag) {
auto& content = x.content();
// handle timeout messages
if (x.content().type_token() == make_type_token<timeout_msg>()) {
auto& tm = content.get_as<timeout_msg>(0);
auto tid = tm.timeout_id;
CAF_ASSERT(x.mid.is_async());
if (is_active_receive_timeout(tid)) {
CAF_LOG_DEBUG("handle timeout message");
if (bhvr_stack_.empty())
return invoke_message_result::dropped;
bhvr_stack_.back().handle_timeout();
return invoke_message_result::consumed;
}
CAF_LOG_DEBUG("dropped expired timeout message");
return invoke_message_result::dropped;
}
// handle everything else as ordinary message
detail::default_invoke_result_visitor<event_based_actor> visitor{this};
bool skipped = false;
auto had_timeout = getf(has_timeout_flag);
if (had_timeout)
unsetf(has_timeout_flag);
// restore timeout at scope exit if message was skipped
auto timeout_guard = detail::make_scope_guard([&] {
if (skipped && had_timeout)
setf(has_timeout_flag);
});
auto call_default_handler = [&] {
auto sres = call_handler(default_handler_, this, x);
switch (sres.flag) {
default:
break;
case rt_error:
case rt_value:
visitor.visit(sres);
break;
case rt_skip:
skipped = true;
}
};
if (bhvr_stack_.empty()) {
call_default_handler();
return !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
}
auto& bhvr = bhvr_stack_.back();
switch (bhvr(visitor, x.content())) {
default:
break;
case rt_error:
case rt_value:
visitor.visit(sres);
break;
case rt_skip:
case match_case::skip:
skipped = true;
break;
case match_case::no_match:
call_default_handler();
}
return !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
};
if (bhvr_stack_.empty()) {
call_default_handler();
auto result = !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
CAF_AFTER_PROCESSING(this, result);
return result;
}
auto& bhvr = bhvr_stack_.back();
switch (bhvr(visitor, x.content())) {
default:
break;
case match_case::skip:
skipped = true;
break;
case match_case::no_match:
call_default_handler();
}
auto result = !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
// Post-process the returned value from the function body.
auto result = body();
CAF_AFTER_PROCESSING(this, result);
CAF_LOG_SKIP_OR_FINALIZE_EVENT(result);
return result;
}
......
......@@ -630,111 +630,107 @@ invoke_message_result scheduled_actor::consume(mailbox_element& x) {
current_element_ = &x;
CAF_LOG_RECEIVE_EVENT(current_element_);
CAF_BEFORE_PROCESSING(this, x);
// Helper function for dispatching a message to a response handler.
using ptr_t = scheduled_actor*;
using fun_t = bool (*)(ptr_t, behavior&, mailbox_element&);
auto ordinary_invoke = [](ptr_t, behavior& f, mailbox_element& in) -> bool {
return f(in.content()) != none;
};
auto select_invoke_fun = [&]() -> fun_t { return ordinary_invoke; };
// Short-circuit awaited responses.
if (!awaited_responses_.empty()) {
auto invoke = select_invoke_fun();
auto& pr = awaited_responses_.front();
// skip all messages until we receive the currently awaited response
if (x.mid != pr.first) {
CAF_AFTER_PROCESSING(this, invoke_message_result::skipped);
return invoke_message_result::skipped;
}
auto f = std::move(pr.second);
awaited_responses_.pop_front();
if (!invoke(this, f, x)) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
f(msg);
}
CAF_AFTER_PROCESSING(this, invoke_message_result::consumed);
return invoke_message_result::consumed;
}
// Handle multiplexed responses.
if (x.mid.is_response()) {
auto invoke = select_invoke_fun();
auto mrh = multiplexed_responses_.find(x.mid);
// neither awaited nor multiplexed, probably an expired timeout
if (mrh == multiplexed_responses_.end()) {
CAF_AFTER_PROCESSING(this, invoke_message_result::dropped);
return invoke_message_result::dropped;
}
auto bhvr = std::move(mrh->second);
multiplexed_responses_.erase(mrh);
if (!invoke(this, bhvr, x)) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
bhvr(msg);
// Wrap the actual body for the function.
auto body = [this, &x] {
// Helper function for dispatching a message to a response handler.
using ptr_t = scheduled_actor*;
using fun_t = bool (*)(ptr_t, behavior&, mailbox_element&);
auto ordinary_invoke = [](ptr_t, behavior& f, mailbox_element& in) -> bool {
return f(in.content()) != none;
};
auto select_invoke_fun = [&]() -> fun_t { return ordinary_invoke; };
// Short-circuit awaited responses.
if (!awaited_responses_.empty()) {
auto invoke = select_invoke_fun();
auto& pr = awaited_responses_.front();
// skip all messages until we receive the currently awaited response
if (x.mid != pr.first)
return invoke_message_result::skipped;
auto f = std::move(pr.second);
awaited_responses_.pop_front();
if (!invoke(this, f, x)) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
f(msg);
}
return invoke_message_result::consumed;
}
CAF_AFTER_PROCESSING(this, invoke_message_result::consumed);
return invoke_message_result::consumed;
}
// Dispatch on the content of x.
switch (categorize(x)) {
case message_category::skipped:
CAF_AFTER_PROCESSING(this, invoke_message_result::skipped);
return invoke_message_result::skipped;
case message_category::internal:
CAF_LOG_DEBUG("handled system message");
CAF_AFTER_PROCESSING(this, invoke_message_result::consumed);
// Handle multiplexed responses.
if (x.mid.is_response()) {
auto invoke = select_invoke_fun();
auto mrh = multiplexed_responses_.find(x.mid);
// neither awaited nor multiplexed, probably an expired timeout
if (mrh == multiplexed_responses_.end())
return invoke_message_result::dropped;
auto bhvr = std::move(mrh->second);
multiplexed_responses_.erase(mrh);
if (!invoke(this, bhvr, x)) {
// try again with error if first attempt failed
auto msg = make_message(
make_error(sec::unexpected_response, x.move_content_to_message()));
bhvr(msg);
}
return invoke_message_result::consumed;
case message_category::ordinary: {
detail::default_invoke_result_visitor<scheduled_actor> visitor{this};
bool skipped = false;
auto had_timeout = getf(has_timeout_flag);
if (had_timeout)
unsetf(has_timeout_flag);
// restore timeout at scope exit if message was skipped
auto timeout_guard = detail::make_scope_guard([&] {
if (skipped && had_timeout)
setf(has_timeout_flag);
});
auto call_default_handler = [&] {
auto sres = call_handler(default_handler_, this, x);
switch (sres.flag) {
}
// Dispatch on the content of x.
switch (categorize(x)) {
case message_category::skipped:
return invoke_message_result::skipped;
case message_category::internal:
CAF_LOG_DEBUG("handled system message");
return invoke_message_result::consumed;
case message_category::ordinary: {
detail::default_invoke_result_visitor<scheduled_actor> visitor{this};
bool skipped = false;
auto had_timeout = getf(has_timeout_flag);
if (had_timeout)
unsetf(has_timeout_flag);
// restore timeout at scope exit if message was skipped
auto timeout_guard = detail::make_scope_guard([&] {
if (skipped && had_timeout)
setf(has_timeout_flag);
});
auto call_default_handler = [&] {
auto sres = call_handler(default_handler_, this, x);
switch (sres.flag) {
default:
break;
case rt_error:
case rt_value:
visitor.visit(sres);
break;
case rt_skip:
skipped = true;
}
};
if (bhvr_stack_.empty()) {
call_default_handler();
return !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
}
auto& bhvr = bhvr_stack_.back();
switch (bhvr(visitor, x.content())) {
default:
break;
case rt_error:
case rt_value:
visitor.visit(sres);
break;
case rt_skip:
case match_case::skip:
skipped = true;
break;
case match_case::no_match:
call_default_handler();
}
};
if (bhvr_stack_.empty()) {
call_default_handler();
auto result = !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
CAF_AFTER_PROCESSING(this, result);
return result;
return !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
}
auto& bhvr = bhvr_stack_.back();
switch (bhvr(visitor, x.content())) {
default:
break;
case match_case::skip:
skipped = true;
break;
case match_case::no_match:
call_default_handler();
}
auto result = !skipped ? invoke_message_result::consumed
: invoke_message_result::skipped;
CAF_AFTER_PROCESSING(this, result);
return result;
}
}
// Unreachable.
CAF_CRITICAL("invalid message type");
// Unreachable.
CAF_CRITICAL("invalid message type");
};
// Post-process the returned value from the function body.
auto result = body();
CAF_AFTER_PROCESSING(this, result);
CAF_LOG_SKIP_OR_FINALIZE_EVENT(result);
return result;
}
/// Tries to consume `x`.
......
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