Commit 6f24e37a authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/actor-registry-deadlock'

parents 7c8d47af cb9fb971
......@@ -81,8 +81,19 @@ void actor_registry::put_impl(actor_id key, strong_actor_ptr val) {
}
void actor_registry::erase(actor_id key) {
exclusive_guard guard{instances_mtx_};
entries_.erase(key);
// Stores a reference to the actor we're going to remove. This guarantees
// that we aren't releasing the last reference to an actor while erasing it.
// Releasing the final ref can trigger the actor to call its cleanup function
// that in turn calls this function and we can end up in a deadlock.
strong_actor_ptr ref;
{ // Lifetime scope of guard.
exclusive_guard guard{instances_mtx_};
auto i = entries_.find(key);
if (i != entries_.end()) {
ref.swap(i->second);
entries_.erase(i);
}
}
}
void actor_registry::inc_running() {
......@@ -126,17 +137,26 @@ strong_actor_ptr actor_registry::get_impl(atom_value key) const {
}
void actor_registry::put_impl(atom_value key, strong_actor_ptr value) {
if (value)
value->get()->attach_functor([=] {
system_.registry().put_impl(key, nullptr);
});
if (value == nullptr) {
erase(key);
return;
}
exclusive_guard guard{named_entries_mtx_};
named_entries_.emplace(key, std::move(value));
}
void actor_registry::erase(atom_value key) {
exclusive_guard guard{named_entries_mtx_};
named_entries_.erase(key);
// Stores a reference to the actor we're going to remove for the same
// reasoning as in erase(actor_id).
strong_actor_ptr ref;
{ // Lifetime scope of guard.
exclusive_guard guard{named_entries_mtx_};
auto i = named_entries_.find(key);
if (i != named_entries_.end()) {
ref.swap(i->second);
named_entries_.erase(i);
}
}
}
auto actor_registry::named_actors() const -> name_map {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE actor_registry
#include "caf/actor_registry.hpp"
#include "caf/test/dsl.hpp"
using namespace caf;
namespace {
behavior dummy() {
return {
[](int i) {
return i;
}
};
}
using foo_atom = atom_constant<atom("foo")>;
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(actor_registry_tests, test_coordinator_fixture<>)
CAF_TEST(erase) {
// CAF registers a few actors by itself.
auto baseline = sys.registry().named_actors().size();
sys.registry().put(foo_atom::value, sys.spawn(dummy));
CAF_CHECK_EQUAL(sys.registry().named_actors().size(), baseline + 1u);
self->send(sys.registry().get<actor>(foo_atom::value), 42);
run();
expect((int), from(_).to(self).with(42));
sys.registry().erase(foo_atom::value);
CAF_CHECK_EQUAL(sys.registry().named_actors().size(), baseline);
}
CAF_TEST_FIXTURE_SCOPE_END()
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