Commit 3a24d16d authored by Dominik Charousset's avatar Dominik Charousset

Omit final decrement of ref count if possible

parent a62da779
...@@ -71,7 +71,7 @@ class actor_proxy : public abstract_actor { ...@@ -71,7 +71,7 @@ class actor_proxy : public abstract_actor {
* Tries to expire this anchor. Fails if reference * Tries to expire this anchor. Fails if reference
* count of the proxy is nonzero. * count of the proxy is nonzero.
*/ */
bool try_expire(); bool try_expire(size_t) noexcept;
std::atomic<actor_proxy*> m_ptr; std::atomic<actor_proxy*> m_ptr;
detail::shared_spinlock m_lock; detail::shared_spinlock m_lock;
}; };
...@@ -96,7 +96,7 @@ class actor_proxy : public abstract_actor { ...@@ -96,7 +96,7 @@ class actor_proxy : public abstract_actor {
*/ */
virtual void kill_proxy(uint32_t reason) = 0; virtual void kill_proxy(uint32_t reason) = 0;
void request_deletion() override; void request_deletion(bool decremented_ref_count) noexcept override;
inline anchor_ptr get_anchor() { inline anchor_ptr get_anchor() {
return m_anchor; return m_anchor;
......
...@@ -28,7 +28,7 @@ namespace detail { ...@@ -28,7 +28,7 @@ namespace detail {
class disposer { class disposer {
public: public:
inline void operator()(memory_managed* ptr) const { inline void operator()(memory_managed* ptr) const {
ptr->request_deletion(); ptr->request_deletion(false);
} }
}; };
......
...@@ -40,7 +40,7 @@ class embedded final : public Base { ...@@ -40,7 +40,7 @@ class embedded final : public Base {
// nop // nop
} }
void request_deletion() override { void request_deletion(bool) noexcept override {
intrusive_ptr<ref_counted> guard; intrusive_ptr<ref_counted> guard;
guard.swap(m_storage); guard.swap(m_storage);
// this code assumes that embedded is part of pair_storage<>, // this code assumes that embedded is part of pair_storage<>,
......
...@@ -33,8 +33,12 @@ class memory_managed { ...@@ -33,8 +33,12 @@ class memory_managed {
* Default implementations calls `delete this, but can * Default implementations calls `delete this, but can
* be overriden in case deletion depends on some condition or * be overriden in case deletion depends on some condition or
* the class doesn't use default new/delete. * the class doesn't use default new/delete.
* @param decremented_rc Indicates whether the caller did reduce the
* reference of this object before calling this member
* function. This information is important when
* implementing a type with support for weak pointers.
*/ */
virtual void request_deletion(); virtual void request_deletion(bool decremented_rc) noexcept;
protected: protected:
virtual ~memory_managed(); virtual ~memory_managed();
......
...@@ -44,32 +44,28 @@ class ref_counted : public memory_managed { ...@@ -44,32 +44,28 @@ class ref_counted : public memory_managed {
/** /**
* Increases reference count by one. * Increases reference count by one.
*/ */
inline void ref() { inline void ref() noexcept {
++m_rc; m_rc.fetch_add(1, std::memory_order_relaxed);
} }
/** /**
* Decreases reference count by one and calls `request_deletion` * Decreases reference count by one and calls `request_deletion`
* when it drops to zero. * when it drops to zero.
*/ */
inline void deref() { void deref() noexcept;
if (--m_rc == 0) {
request_deletion();
}
}
/** /**
* Queries whether there is exactly one reference. * Queries whether there is exactly one reference.
*/ */
inline bool unique() const { inline bool unique() const noexcept {
return m_rc == 1; return m_rc == 1;
} }
inline size_t get_reference_count() const { inline size_t get_reference_count() const noexcept {
return m_rc; return m_rc;
} }
private: protected:
std::atomic<size_t> m_rc; std::atomic<size_t> m_rc;
}; };
......
...@@ -55,10 +55,10 @@ actor_proxy_ptr actor_proxy::anchor::get() { ...@@ -55,10 +55,10 @@ actor_proxy_ptr actor_proxy::anchor::get() {
return result; return result;
} }
bool actor_proxy::anchor::try_expire() { bool actor_proxy::anchor::try_expire(size_t expected_rc) noexcept {
std::lock_guard<detail::shared_spinlock> guard{m_lock}; std::lock_guard<detail::shared_spinlock> guard{m_lock};
// double-check reference count // double-check reference count
if (m_ptr.load()->get_reference_count() == 0) { if (m_ptr.load()->get_reference_count() == expected_rc) {
m_ptr = nullptr; m_ptr = nullptr;
return true; return true;
} }
...@@ -75,8 +75,8 @@ actor_proxy::actor_proxy(actor_id aid, node_id nid) ...@@ -75,8 +75,8 @@ actor_proxy::actor_proxy(actor_id aid, node_id nid)
// nop // nop
} }
void actor_proxy::request_deletion() { void actor_proxy::request_deletion(bool decremented_rc) noexcept {
if (m_anchor->try_expire()) { if (m_anchor->try_expire(decremented_rc ? 0 : 1)) {
delete this; delete this;
} }
} }
......
...@@ -25,7 +25,7 @@ memory_managed::~memory_managed() { ...@@ -25,7 +25,7 @@ memory_managed::~memory_managed() {
// nop // nop
} }
void memory_managed::request_deletion() { void memory_managed::request_deletion(bool) noexcept {
delete this; delete this;
} }
......
...@@ -38,4 +38,14 @@ ref_counted& ref_counted::operator=(const ref_counted&) { ...@@ -38,4 +38,14 @@ ref_counted& ref_counted::operator=(const ref_counted&) {
return *this; return *this;
} }
void ref_counted::deref() noexcept {
if (unique()) {
request_deletion(false);
return;
}
if (m_rc.fetch_sub(1, std::memory_order_acq_rel) == 1) {
request_deletion(true);
}
}
} // namespace caf } // namespace caf
...@@ -592,7 +592,7 @@ void default_multiplexer::wr_dispatch_request(runnable* ptr) { ...@@ -592,7 +592,7 @@ void default_multiplexer::wr_dispatch_request(runnable* ptr) {
# endif # endif
if (res <= 0) { if (res <= 0) {
// pipe closed, discard runnable // pipe closed, discard runnable
ptr->request_deletion(); ptr->request_deletion(false);
} else if (static_cast<size_t>(res) < sizeof(ptrval)) { } else if (static_cast<size_t>(res) < sizeof(ptrval)) {
// must not happen: wrote invalid pointer to pipe // must not happen: wrote invalid pointer to pipe
std::cerr << "[CAF] Fatal error: wrote invalid data to pipe" << std::endl; std::cerr << "[CAF] Fatal error: wrote invalid data to pipe" << std::endl;
...@@ -666,7 +666,7 @@ void default_multiplexer::handle_socket_event(native_socket fd, int mask, ...@@ -666,7 +666,7 @@ void default_multiplexer::handle_socket_event(native_socket fd, int mask,
CAF_LOG_DEBUG("read message from pipe"); CAF_LOG_DEBUG("read message from pipe");
auto cb = rd_dispatch_request(); auto cb = rd_dispatch_request();
cb->run(); cb->run();
cb->request_deletion(); cb->request_deletion(false);
} }
} }
if (mask & output_mask) { if (mask & output_mask) {
...@@ -713,7 +713,7 @@ default_multiplexer::~default_multiplexer() { ...@@ -713,7 +713,7 @@ default_multiplexer::~default_multiplexer() {
nonblocking(m_pipe.first, true); nonblocking(m_pipe.first, true);
auto ptr = rd_dispatch_request(); auto ptr = rd_dispatch_request();
while (ptr) { while (ptr) {
ptr->request_deletion(); ptr->request_deletion(false);
ptr = rd_dispatch_request(); ptr = rd_dispatch_request();
} }
closesocket(m_pipe.first); closesocket(m_pipe.first);
......
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