void blocking_actor::dequeue(behavior& bhvr, message_id mid) { CAF_LOG_TRACE(CAF_MARG(mid, integer_value)); // try to dequeue from cache first if (invoke_from_cache(bhvr, mid)) { return; } // requesting an invalid timeout will reset our active timeout uint32_t timeout_id = 0; if (mid == invalid_message_id) { timeout_id = request_timeout(bhvr.timeout()); } else { request_sync_timeout_msg(bhvr.timeout(), mid); } // read incoming messages for (;;) { await_data(); auto msg = next_message(); switch (invoke_message(msg, bhvr, mid)) { case im_success: if (mid == invalid_message_id) { reset_timeout(timeout_id); } return; case im_skipped: if (msg) { push_to_cache(std::move(msg)); } break; default: // delete msg break; } } }
void remote_actor_proxy::forward_msg(const actor_addr& sender, message_id mid, message msg) { CAF_LOG_TRACE(CAF_ARG(id()) << ", " << CAF_TSARG(sender) << ", " << CAF_MARG(mid, integer_value) << ", " << CAF_TSARG(msg)); m_parent->enqueue( invalid_actor_addr, invalid_message_id, make_message(atom("_Dispatch"), sender, address(), mid, std::move(msg)), nullptr); }
void forwarding_actor_proxy::forward_msg(const actor_addr& sender, message_id mid, message msg) { CAF_LOG_TRACE(CAF_ARG(id()) << ", " << CAF_TSARG(sender) << ", " << CAF_MARG(mid, integer_value) << ", " << CAF_TSARG(msg)); shared_lock<detail::shared_spinlock> m_guard(m_manager_mtx); m_manager->enqueue(invalid_actor_addr, invalid_message_id, make_message(atom("_Dispatch"), sender, address(), mid, std::move(msg)), nullptr); }
handle_message_result handle_message(Actor* self, mailbox_element* node, Fun& fun, message_id awaited_response) { bool handle_sync_failure_on_mismatch = true; if (dptr()->hm_should_skip(node)) { return hm_skip_msg; } switch (this->filter_msg(self, node)) { case msg_type::normal_exit: CAF_LOG_DEBUG("dropped normal exit signal"); return hm_drop_msg; case msg_type::expired_sync_response: CAF_LOG_DEBUG("dropped expired sync response"); return hm_drop_msg; case msg_type::expired_timeout: CAF_LOG_DEBUG("dropped expired timeout message"); return hm_drop_msg; case msg_type::inactive_timeout: CAF_LOG_DEBUG("skipped inactive timeout message"); return hm_skip_msg; case msg_type::non_normal_exit: CAF_LOG_DEBUG("handled non-normal exit signal"); // this message was handled // by calling self->quit(...) return hm_msg_handled; case msg_type::timeout: { CAF_LOG_DEBUG("handle timeout message"); auto& tm = node->msg.get_as<timeout_msg>(0); self->handle_timeout(fun, tm.timeout_id); if (awaited_response.valid()) { self->mark_arrived(awaited_response); self->remove_handler(awaited_response); } return hm_msg_handled; } case msg_type::timeout_response: handle_sync_failure_on_mismatch = false; CAF_ANNOTATE_FALLTHROUGH; case msg_type::sync_response: CAF_LOG_DEBUG("handle as synchronous response: " << CAF_TARG(node->msg, to_string) << ", " << CAF_MARG(node->mid, integer_value) << ", " << CAF_MARG(awaited_response, integer_value)); if (awaited_response.valid() && node->mid == awaited_response) { auto previous_node = dptr()->hm_begin(self, node); auto res = invoke_fun(self, node->msg, node->mid, fun); if (!res && handle_sync_failure_on_mismatch) { CAF_LOG_WARNING("sync failure occured in actor " << "with ID " << self->id()); self->handle_sync_failure(); } self->mark_arrived(awaited_response); self->remove_handler(awaited_response); dptr()->hm_cleanup(self, previous_node); return hm_msg_handled; } return hm_cache_msg; case msg_type::ordinary: if (!awaited_response.valid()) { auto previous_node = dptr()->hm_begin(self, node); auto res = invoke_fun(self, node->msg, node->mid, fun); if (res) { dptr()->hm_cleanup(self, previous_node); return hm_msg_handled; } // no match (restore self members) dptr()->hm_revert(self, previous_node); } CAF_LOG_DEBUG_IF(awaited_response.valid(), "ignored message; await response: " << awaited_response.integer_value()); return hm_cache_msg; } // should be unreachable CAF_CRITICAL("invalid message type"); }
optional<message> invoke_fun(Actor* self, message& msg, message_id& mid, Fun& fun, MaybeResponseHdl hdl = MaybeResponseHdl{}) { # ifdef CAF_LOG_LEVEL auto msg_str = to_string(msg); # endif CAF_LOG_TRACE(CAF_MARG(mid, integer_value) << ", msg = " << msg_str); auto res = fun(msg); // might change mid CAF_LOG_DEBUG_IF(res, "actor did consume message: " << msg_str); CAF_LOG_DEBUG_IF(!res, "actor did ignore message: " << msg_str); if (!res) { return none; } if (res->empty()) { // make sure synchronous requests // always receive a response if (mid.is_request() && !mid.is_answered()) { CAF_LOG_WARNING("actor with ID " << self->id() << " did not reply to a synchronous request message"); auto fhdl = fetch_response_promise(self, hdl); if (fhdl) { fhdl.deliver(make_message(unit)); } } } else { CAF_LOGF_DEBUG("res = " << to_string(*res)); if (res->template has_types<atom_value, uint64_t>() && res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) { CAF_LOG_DEBUG("message handler returned a message id wrapper"); auto id = res->template get_as<uint64_t>(1); auto msg_id = message_id::from_integer_value(id); auto ref_opt = self->sync_handler(msg_id); // calls self->response_promise() if hdl is a dummy // argument, forwards hdl otherwise to reply to the // original request message auto fhdl = fetch_response_promise(self, hdl); if (ref_opt) { behavior cpy = *ref_opt; *ref_opt = cpy.add_continuation([=](message & intermediate) ->optional<message> { if (!intermediate.empty()) { // do no use lamba expresion type to // avoid recursive template instantiaton behavior::continuation_fun f2 = [=]( message & m)->optional<message> { return std::move(m); }; auto mutable_mid = mid; // recursively call invoke_fun on the // result to correctly handle stuff like // sync_send(...).then(...).then(...)... return this->invoke_fun(self, intermediate, mutable_mid, f2, fhdl); } return none; }); } // reset res to prevent "outer" invoke_fun // from handling the result again res->reset(); } else { // respond by using the result of 'fun' CAF_LOG_DEBUG("respond via response_promise"); auto fhdl = fetch_response_promise(self, hdl); if (fhdl) { fhdl.deliver(std::move(*res)); // inform caller about success return message{}; } } } return res; }