Commit 7e1cf972 authored by Dominik Charousset's avatar Dominik Charousset

Use intrusive singly-linked attachables

By replacing the vector in `local_actor` with singly-linked attachables, we
save 16 Bytes on 64 bit machines. Relates #180.
parent d2ca6275
...@@ -263,6 +263,16 @@ class abstract_actor : public abstract_channel { ...@@ -263,6 +263,16 @@ class abstract_actor : public abstract_channel {
m_host = new_host; m_host = new_host;
} }
inline void attach_impl(attachable_ptr& ptr) {
ptr->next.swap(m_attachables_head);
m_attachables_head.swap(ptr);
}
static size_t detach_impl(const attachable::token& what,
attachable_ptr& ptr,
bool stop_on_first_hit = false,
bool dry_run = false);
// cannot be changed after construction // cannot be changed after construction
const actor_id m_id; const actor_id m_id;
...@@ -273,7 +283,7 @@ class abstract_actor : public abstract_channel { ...@@ -273,7 +283,7 @@ class abstract_actor : public abstract_channel {
mutable std::mutex m_mtx; mutable std::mutex m_mtx;
// attached functors that are executed on cleanup (for monitors, links, etc) // attached functors that are executed on cleanup (for monitors, links, etc)
std::vector<attachable_ptr> m_attachables; attachable_ptr m_attachables_head;
// identifies the execution unit this actor is currently executed by // identifies the execution unit this actor is currently executed by
execution_unit* m_host; execution_unit* m_host;
......
...@@ -41,6 +41,11 @@ class attachable { ...@@ -41,6 +41,11 @@ class attachable {
* Represents a pointer to a value with its RTTI. * Represents a pointer to a value with its RTTI.
*/ */
struct token { struct token {
template <class T>
token(const T& tk) : subtype(typeid(T)), ptr(&tk) {
// nop
}
/** /**
* Denotes the type of ptr. * Denotes the type of ptr.
*/ */
...@@ -74,6 +79,8 @@ class attachable { ...@@ -74,6 +79,8 @@ class attachable {
bool matches(const T& what) { bool matches(const T& what) {
return matches(token{typeid(T), &what}); return matches(token{typeid(T), &what});
} }
std::unique_ptr<attachable> next;
}; };
/** /**
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <atomic> #include <atomic>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include <forward_list>
#include "caf/actor.hpp" #include "caf/actor.hpp"
#include "caf/extend.hpp" #include "caf/extend.hpp"
...@@ -534,9 +535,6 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> { ...@@ -534,9 +535,6 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
// points to the node under processing otherwise // points to the node under processing otherwise
mailbox_element* m_current_node; mailbox_element* m_current_node;
// {group => subscription} map of all joined groups
// std::map<group, abstract_group::subscription> m_subscriptions;
// set by quit // set by quit
uint32_t m_planned_exit_reason; uint32_t m_planned_exit_reason;
......
...@@ -75,8 +75,7 @@ void abstract_actor::attach(attachable_ptr ptr) { ...@@ -75,8 +75,7 @@ void abstract_actor::attach(attachable_ptr ptr) {
guard_type guard{m_mtx}; guard_type guard{m_mtx};
reason = m_exit_reason; reason = m_exit_reason;
if (reason == exit_reason::not_exited) { if (reason == exit_reason::not_exited) {
m_attachables.push_back(std::move(ptr)); attach_impl(ptr);
CAF_LOG_DEBUG("actor has now " << m_attachables.size() << " attachables");
return; return;
} }
} }
...@@ -84,19 +83,27 @@ void abstract_actor::attach(attachable_ptr ptr) { ...@@ -84,19 +83,27 @@ void abstract_actor::attach(attachable_ptr ptr) {
ptr->actor_exited(this, reason); ptr->actor_exited(this, reason);
} }
void abstract_actor::detach(const attachable::token& what) { size_t abstract_actor::detach_impl(const attachable::token& what,
attachable_ptr ptr; attachable_ptr& ptr,
{ // lifetime scope of guard bool stop_on_hit,
guard_type guard{m_mtx}; bool dry_run) {
auto end = m_attachables.end(); if (!ptr) {
auto i = std::find_if(m_attachables.begin(), end, return 0;
[&](attachable_ptr& p) { return p->matches(what); });
if (i != end) {
ptr.swap(*i);
m_attachables.erase(i);
} }
if (ptr->matches(what)) {
if (!dry_run) {
attachable_ptr next;
next.swap(ptr->next);
ptr.swap(next);
} }
// ptr will be destroyed here, without locked mutex return stop_on_hit ? 1 : 1 + detach_impl(what, ptr, stop_on_hit, dry_run);
}
return detach_impl(what, ptr->next, stop_on_hit, dry_run);
}
void abstract_actor::detach(const attachable::token& what) {
guard_type guard{m_mtx};
detach_impl(what, m_attachables_head);
} }
bool abstract_actor::link_impl(linking_operation op, const actor_addr& other) { bool abstract_actor::link_impl(linking_operation op, const actor_addr& other) {
...@@ -121,11 +128,11 @@ bool abstract_actor::establish_link_impl(const actor_addr& other) { ...@@ -121,11 +128,11 @@ bool abstract_actor::establish_link_impl(const actor_addr& other) {
if (exited()) { if (exited()) {
ptr->enqueue(address(), message_id::invalid, ptr->enqueue(address(), message_id::invalid,
make_message(exit_msg{address(), exit_reason()}), m_host); make_message(exit_msg{address(), exit_reason()}), m_host);
} } else if (ptr->establish_backlink(address())) {
// add link if not already linked to other // add link if not already linked to other
// (checked by establish_backlink) // (checked by establish_backlink)
else if (ptr->establish_backlink(address())) { auto tmp = default_attachable::make_link(other);
m_attachables.push_back(default_attachable::make_link(other)); attach_impl(tmp);
return true; return true;
} }
} }
...@@ -134,14 +141,14 @@ bool abstract_actor::establish_link_impl(const actor_addr& other) { ...@@ -134,14 +141,14 @@ bool abstract_actor::establish_link_impl(const actor_addr& other) {
bool abstract_actor::establish_backlink_impl(const actor_addr& other) { bool abstract_actor::establish_backlink_impl(const actor_addr& other) {
uint32_t reason = exit_reason::not_exited; uint32_t reason = exit_reason::not_exited;
default_attachable::predicate pred(other, default_attachable::link); default_attachable::observe_token tk{other, default_attachable::link};
if (other && other != this) { if (other && other != this) {
guard_type guard{m_mtx}; guard_type guard{m_mtx};
reason = m_exit_reason; reason = m_exit_reason;
if (reason == exit_reason::not_exited) { if (reason == exit_reason::not_exited) {
auto i = std::find_if(m_attachables.begin(), m_attachables.end(), pred); if (detach_impl(tk, m_attachables_head, true, true) == 0) {
if (i == m_attachables.end()) { auto tmp = default_attachable::make_link(other);
m_attachables.push_back(default_attachable::make_link(other)); attach_impl(tmp);
return true; return true;
} }
} }
...@@ -159,28 +166,22 @@ bool abstract_actor::remove_link_impl(const actor_addr& other) { ...@@ -159,28 +166,22 @@ bool abstract_actor::remove_link_impl(const actor_addr& other) {
if (!other) { if (!other) {
return false; return false;
} }
default_attachable::predicate pred(other, default_attachable::link); default_attachable::observe_token tk{other, default_attachable::link};
guard_type guard{m_mtx}; guard_type guard{m_mtx};
// remove_backlink returns true if this actor is linked to other // remove_backlink returns true if this actor is linked to other
auto ptr = actor_cast<abstract_actor_ptr>(other); auto ptr = actor_cast<abstract_actor_ptr>(other);
if (!exited() && ptr->remove_backlink(address())) { if (!exited() && ptr->remove_backlink(address())) {
auto i = std::find_if(m_attachables.begin(), m_attachables.end(), pred); detach_impl(tk, m_attachables_head, true);
CAF_REQUIRE(i != m_attachables.end());
m_attachables.erase(i);
return true; return true;
} }
return false; return false;
} }
bool abstract_actor::remove_backlink_impl(const actor_addr& other) { bool abstract_actor::remove_backlink_impl(const actor_addr& other) {
default_attachable::predicate pred(other, default_attachable::link); default_attachable::observe_token tk{other, default_attachable::link};
if (other && other != this) { if (other && other != this) {
guard_type guard{m_mtx}; guard_type guard{m_mtx};
auto i = std::find_if(m_attachables.begin(), m_attachables.end(), pred); return detach_impl(tk, m_attachables_head, true) > 0;
if (i != m_attachables.end()) {
m_attachables.erase(i);
return true;
}
} }
return false; return false;
} }
...@@ -194,7 +195,7 @@ void abstract_actor::cleanup(uint32_t reason) { ...@@ -194,7 +195,7 @@ void abstract_actor::cleanup(uint32_t reason) {
CAF_LOGM_TRACE("caf::actor", CAF_ARG(m_id) << ", " << CAF_ARG(reason)); CAF_LOGM_TRACE("caf::actor", CAF_ARG(m_id) << ", " << CAF_ARG(reason));
CAF_REQUIRE(reason != exit_reason::not_exited); CAF_REQUIRE(reason != exit_reason::not_exited);
// move everyhting out of the critical section before processing it // move everyhting out of the critical section before processing it
decltype(m_attachables) mattachables; attachable_ptr head;
{ // lifetime scope of guard { // lifetime scope of guard
guard_type guard{m_mtx}; guard_type guard{m_mtx};
if (m_exit_reason != exit_reason::not_exited) { if (m_exit_reason != exit_reason::not_exited) {
...@@ -202,17 +203,15 @@ void abstract_actor::cleanup(uint32_t reason) { ...@@ -202,17 +203,15 @@ void abstract_actor::cleanup(uint32_t reason) {
return; return;
} }
m_exit_reason = reason; m_exit_reason = reason;
mattachables.swap(m_attachables); m_attachables_head.swap(head);
} }
CAF_LOG_INFO_IF(!is_remote(), "actor with ID " CAF_LOG_INFO_IF(!is_remote(), "cleanup actor with ID "
<< m_id << " had " << mattachables.size() << m_id << "; exit reason = "
<< " attachables; exit reason = "
<< reason << ", class = " << reason << ", class = "
<< detail::demangle(typeid(*this))); << detail::demangle(typeid(*this)));
// send exit messages // send exit messages
CAF_LOGM_DEBUG("caf::actor", "run " << mattachables.size() << " attachables"); for (attachable* i = head.get(); i != nullptr; i = i->next.get()) {
for (attachable_ptr& ptr : mattachables) { i->actor_exited(this, reason);
ptr->actor_exited(this, reason);
} }
} }
......
...@@ -66,14 +66,12 @@ void local_actor::join(const group& what) { ...@@ -66,14 +66,12 @@ void local_actor::join(const group& what) {
if (what == invalid_group) { if (what == invalid_group) {
return; return;
} }
abstract_group::subscription_predicate pred{what.ptr()}; abstract_group::subscription_token tk{what.ptr()};
std::unique_lock<std::mutex> guard{m_mtx}; std::unique_lock<std::mutex> guard{m_mtx};
auto last = m_attachables.end(); if (detach_impl(tk, m_attachables_head, true, true) == 0) {
auto i = std::find_if(m_attachables.begin(), last, pred);
if (i == last) {
auto ptr = what->subscribe(address()); auto ptr = what->subscribe(address());
if (ptr) { if (ptr) {
m_attachables.emplace_back(std::move(ptr)); attach_impl(ptr);
} }
} }
} }
...@@ -87,9 +85,10 @@ void local_actor::leave(const group& what) { ...@@ -87,9 +85,10 @@ void local_actor::leave(const group& what) {
std::vector<group> local_actor::joined_groups() const { std::vector<group> local_actor::joined_groups() const {
std::vector<group> result; std::vector<group> result;
result.reserve(20);
std::unique_lock<std::mutex> guard{m_mtx}; std::unique_lock<std::mutex> guard{m_mtx};
for (auto& ptr : m_attachables) { for (attachable* i = m_attachables_head.get(); i != 0; i = i->next.get()) {
auto sptr = dynamic_cast<abstract_group::subscription*>(ptr.get()); auto sptr = dynamic_cast<abstract_group::subscription*>(i);
if (sptr) { if (sptr) {
result.emplace_back(sptr->group()); result.emplace_back(sptr->group());
} }
......
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