Commit 1b744245 authored by Dominik Charousset's avatar Dominik Charousset

Create actors with ref count 1, close #176

parent b76ec4b9
......@@ -227,12 +227,12 @@ class abstract_actor : public abstract_channel {
/**
* Creates a non-proxy instance.
*/
abstract_actor();
abstract_actor(size_t initial_ref_count = 0);
/**
* Creates a proxy instance for a proxy running on `nid`.
*/
abstract_actor(actor_id aid, node_id nid);
abstract_actor(actor_id aid, node_id nid, size_t initial_ref_count = 0);
virtual bool link_impl(linking_operation op, const actor_addr& other);
......
......@@ -56,9 +56,9 @@ class abstract_channel : public ref_counted {
protected:
abstract_channel();
abstract_channel(size_t initial_ref_count = 0);
abstract_channel(node_id nid);
abstract_channel(node_id nid, size_t initial_ref_count = 0);
private:
......
......@@ -46,13 +46,21 @@ class intrusive_ptr : detail::comparable<intrusive_ptr<T>>,
using reference = T& ;
using const_reference = const T&;
constexpr intrusive_ptr() : m_ptr(nullptr) { }
constexpr intrusive_ptr() : m_ptr(nullptr) {
// nop
}
intrusive_ptr(pointer raw_ptr) { set_ptr(raw_ptr); }
intrusive_ptr(pointer raw_ptr, bool add_ref = true) {
set_ptr(raw_ptr, add_ref);
}
intrusive_ptr(intrusive_ptr&& other) : m_ptr(other.release()) { }
intrusive_ptr(intrusive_ptr&& other) : m_ptr(other.release()) {
// nop
}
intrusive_ptr(const intrusive_ptr& other) { set_ptr(other.get()); }
intrusive_ptr(const intrusive_ptr& other) {
set_ptr(other.get(), true);
}
template <class Y>
intrusive_ptr(intrusive_ptr<Y> other) : m_ptr(other.release()) {
......@@ -60,7 +68,9 @@ class intrusive_ptr : detail::comparable<intrusive_ptr<T>>,
"Y* is not assignable to T*");
}
~intrusive_ptr() { if (m_ptr) m_ptr->deref(); }
~intrusive_ptr() {
if (m_ptr) m_ptr->deref();
}
inline void swap(intrusive_ptr& other) {
std::swap(m_ptr, other.m_ptr);
......@@ -76,17 +86,11 @@ class intrusive_ptr : detail::comparable<intrusive_ptr<T>>,
return result;
}
/**
* Sets this pointer to `ptr` without modifying reference count.
*/
void adopt(pointer ptr) {
reset();
m_ptr = ptr;
}
void reset(pointer new_value = nullptr) {
if (m_ptr) m_ptr->deref();
set_ptr(new_value);
void reset(pointer new_value = nullptr, bool add_ref = true) {
if (m_ptr) {
m_ptr->deref();
}
set_ptr(new_value, add_ref);
}
template <class... Ts>
......@@ -150,11 +154,12 @@ class intrusive_ptr : detail::comparable<intrusive_ptr<T>>,
pointer m_ptr;
inline void set_ptr(pointer raw_ptr) {
inline void set_ptr(pointer raw_ptr, bool add_ref) {
m_ptr = raw_ptr;
if (raw_ptr) raw_ptr->ref();
if (raw_ptr && add_ref) {
raw_ptr->ref();
}
}
};
/**
......
......@@ -57,7 +57,8 @@ namespace caf {
class sync_handle_helper;
/**
* Base class for local running Actors.
* Base class for local running actors.
* @warning Instances of `local_actor` start with a reference count of 1
* @extends abstract_actor
*/
class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
......
......@@ -34,33 +34,38 @@ namespace caf {
*/
class ref_counted : public memory_managed {
public:
ref_counted();
~ref_counted();
ref_counted(const ref_counted&);
ref_counted& operator=(const ref_counted&);
~ref_counted();
explicit ref_counted(size_t initial_count = 0);
/**
* Increases reference count by one.
*/
inline void ref() { ++m_rc; }
inline void ref() {
++m_rc;
}
/**
* Decreases reference count by one and calls `request_deletion`
* when it drops to zero.
*/
inline void deref() {
if (--m_rc == 0) request_deletion();
if (--m_rc == 0) {
request_deletion();
}
}
/**
* Queries whether there is exactly one reference.
*/
inline bool unique() const { return m_rc == 1; }
inline bool unique() const {
return m_rc == 1;
}
inline size_t get_reference_count() const { return m_rc; }
inline size_t get_reference_count() const {
return m_rc;
}
private:
std::atomic<size_t> m_rc;
......
......@@ -109,6 +109,9 @@ intrusive_ptr<C> spawn_impl(execution_unit* host,
detail::proper_actor<C, policy_token>
>::type;
auto ptr = detail::make_counted<actor_impl>(std::forward<Ts>(args)...);
// actors start with a reference count of 1, hence we need to deref ptr once
CAF_REQUIRE(!ptr->unique());
ptr->deref();
CAF_LOGF_DEBUG("spawned actor with ID " << ptr->id());
CAF_PUSH_AID(ptr->id());
before_launch_fun(ptr.get());
......
......@@ -47,8 +47,8 @@ using guard_type = std::unique_lock<std::mutex>;
// m_exit_reason is guaranteed to be set to 0, i.e., exit_reason::not_exited,
// by std::atomic<> constructor
abstract_actor::abstract_actor(actor_id aid, node_id nid)
: super(std::move(nid)),
abstract_actor::abstract_actor(actor_id aid, node_id nid, size_t initial_count)
: super(std::move(nid), initial_count),
m_id(aid),
m_exit_reason(exit_reason::not_exited),
m_host(nullptr),
......@@ -56,8 +56,8 @@ abstract_actor::abstract_actor(actor_id aid, node_id nid)
// nop
}
abstract_actor::abstract_actor()
: super(detail::singletons::get_node_id()),
abstract_actor::abstract_actor(size_t initial_count)
: super(detail::singletons::get_node_id(), initial_count),
m_id(detail::singletons::get_actor_registry()->next_id()),
m_exit_reason(exit_reason::not_exited),
m_host(nullptr),
......
......@@ -24,11 +24,15 @@ namespace caf {
using detail::singletons;
abstract_channel::abstract_channel() : m_node(singletons::get_node_id()) {
abstract_channel::abstract_channel(size_t initial_ref_count)
: ref_counted(initial_ref_count),
m_node(singletons::get_node_id()) {
// nop
}
abstract_channel::abstract_channel(node_id nid) : m_node(std::move(nid)) {
abstract_channel::abstract_channel(node_id nid, size_t initial_ref_count)
: ref_counted(initial_ref_count),
m_node(std::move(nid)) {
// nop
}
......
......@@ -29,8 +29,12 @@
namespace caf {
// local actors are created with a reference count of one that is adjusted
// later on in spawn(); this prevents subtle bugs that lead to segfaults,
// e.g., when calling address() in the ctor of a derived class
local_actor::local_actor()
: m_dummy_node(),
: super(1),
m_dummy_node(),
m_current_node(&m_dummy_node),
m_planned_exit_reason(exit_reason::not_exited) {
// nop
......
......@@ -21,10 +21,6 @@
namespace caf {
ref_counted::ref_counted() : m_rc(0) {
// nop
}
ref_counted::~ref_counted() {
// nop
}
......@@ -38,4 +34,8 @@ ref_counted& ref_counted::operator=(const ref_counted&) {
return *this;
}
ref_counted::ref_counted(size_t initial_count) : m_rc(initial_count) {
// nop
}
} // namespace caf
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