void actor_registry::put(actor_id key, const actor_ptr& value) { bool add_attachable = false; if (value != nullptr) { shared_guard guard(m_instances_mtx); auto i = m_entries.find(key); if (i == m_entries.end()) { auto entry = std::make_pair(key, value_type(value, exit_reason::not_exited)); upgrade_guard uguard(guard); add_attachable = m_entries.insert(entry).second; } } if (add_attachable) { CPPA_LOG_INFO("added " << key); struct eraser : attachable { actor_id m_id; actor_registry* m_registry; eraser(actor_id id, actor_registry* s) : m_id(id), m_registry(s) { } void actor_exited(std::uint32_t reason) { m_registry->erase(m_id, reason); } bool matches(const token&) { return false; } }; value->attach(new eraser(key, this)); } }
void actor_registry::erase(actor_id key, std::uint32_t reason) { exclusive_guard guard(m_instances_mtx); auto i = m_entries.find(key); if (i != m_entries.end()) { auto& entry = i->second; CPPA_LOG_INFO("erased " << key << ", reason = " << std::hex << reason); entry.first = nullptr; entry.second = reason; } }
resumable::resume_result resume(detail::cs_thread*, execution_unit* host) override { auto d = static_cast<Derived*>(this); d->m_host = host; CPPA_LOG_TRACE("id = " << d->id()); auto done_cb = [&]() -> bool { CPPA_LOG_TRACE(""); d->bhvr_stack().clear(); d->bhvr_stack().cleanup(); d->on_exit(); if (!d->bhvr_stack().empty()) { CPPA_LOG_DEBUG("on_exit did set a new behavior in on_exit"); d->planned_exit_reason(exit_reason::not_exited); return false; // on_exit did set a new behavior } auto rsn = d->planned_exit_reason(); if (rsn == exit_reason::not_exited) { rsn = exit_reason::normal; d->planned_exit_reason(rsn); } d->cleanup(rsn); return true; }; auto actor_done = [&] { return d->bhvr_stack().empty() || d->planned_exit_reason() != exit_reason::not_exited; }; // actors without behavior or that have already defined // an exit reason must not be resumed CPPA_REQUIRE(!d->m_initialized || !actor_done()); if (!d->m_initialized) { d->m_initialized = true; auto bhvr = d->make_behavior(); if (bhvr) d->become(std::move(bhvr)); // else: make_behavior() might have just called become() if (actor_done() && done_cb()) return resume_result::done; // else: enter resume loop } try { for (;;) { auto ptr = d->next_message(); if (ptr) { if (d->invoke_message(ptr)) { if (actor_done() && done_cb()) { CPPA_LOG_DEBUG("actor exited"); return resume_result::done; } // continue from cache if current message was // handled, because the actor might have changed // its behavior to match 'old' messages now while (d->invoke_message_from_cache()) { if (actor_done() && done_cb()) { CPPA_LOG_DEBUG("actor exited"); return resume_result::done; } } } // add ptr to cache if invoke_message // did not reset it (i.e. skipped, but not dropped) if (ptr) { CPPA_LOG_DEBUG("add message to cache"); d->push_to_cache(std::move(ptr)); } } else { CPPA_LOG_DEBUG("no more element in mailbox; " "going to block"); if (d->mailbox().try_block()) { return resumable::resume_later; } // else: try again } } } catch (actor_exited& what) { CPPA_LOG_INFO("actor died because of exception: actor_exited, " "reason = " << what.reason()); if (d->exit_reason() == exit_reason::not_exited) { d->quit(what.reason()); } } catch (std::exception& e) { CPPA_LOG_WARNING("actor died because of exception: " << detail::demangle(typeid(e)) << ", what() = " << e.what()); if (d->exit_reason() == exit_reason::not_exited) { d->quit(exit_reason::unhandled_exception); } } catch (...) { CPPA_LOG_WARNING("actor died because of an unknown exception"); if (d->exit_reason() == exit_reason::not_exited) { d->quit(exit_reason::unhandled_exception); } } done_cb(); return resumable::done; }