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 {
* Tries to expire this anchor. Fails if reference
* count of the proxy is nonzero.
*/
bool try_expire();
bool try_expire(size_t) noexcept;
std::atomic<actor_proxy*> m_ptr;
detail::shared_spinlock m_lock;
};
......@@ -96,7 +96,7 @@ class actor_proxy : public abstract_actor {
*/
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() {
return m_anchor;
......
......@@ -28,7 +28,7 @@ namespace detail {
class disposer {
public:
inline void operator()(memory_managed* ptr) const {
ptr->request_deletion();
ptr->request_deletion(false);
}
};
......
......@@ -40,7 +40,7 @@ class embedded final : public Base {
// nop
}
void request_deletion() override {
void request_deletion(bool) noexcept override {
intrusive_ptr<ref_counted> guard;
guard.swap(m_storage);
// this code assumes that embedded is part of pair_storage<>,
......
......@@ -33,8 +33,12 @@ class memory_managed {
* Default implementations calls `delete this, but can
* be overriden in case deletion depends on some condition or
* 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:
virtual ~memory_managed();
......
......@@ -44,32 +44,28 @@ class ref_counted : public memory_managed {
/**
* Increases reference count by one.
*/
inline void ref() {
++m_rc;
inline void ref() noexcept {
m_rc.fetch_add(1, std::memory_order_relaxed);
}
/**
* Decreases reference count by one and calls `request_deletion`
* when it drops to zero.
*/
inline void deref() {
if (--m_rc == 0) {
request_deletion();
}
}
void deref() noexcept;
/**
* Queries whether there is exactly one reference.
*/
inline bool unique() const {
inline bool unique() const noexcept {
return m_rc == 1;
}
inline size_t get_reference_count() const {
inline size_t get_reference_count() const noexcept {
return m_rc;
}
private:
protected:
std::atomic<size_t> m_rc;
};
......
......@@ -55,10 +55,10 @@ actor_proxy_ptr actor_proxy::anchor::get() {
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};
// double-check reference count
if (m_ptr.load()->get_reference_count() == 0) {
if (m_ptr.load()->get_reference_count() == expected_rc) {
m_ptr = nullptr;
return true;
}
......@@ -75,8 +75,8 @@ actor_proxy::actor_proxy(actor_id aid, node_id nid)
// nop
}
void actor_proxy::request_deletion() {
if (m_anchor->try_expire()) {
void actor_proxy::request_deletion(bool decremented_rc) noexcept {
if (m_anchor->try_expire(decremented_rc ? 0 : 1)) {
delete this;
}
}
......
......@@ -25,7 +25,7 @@ memory_managed::~memory_managed() {
// nop
}
void memory_managed::request_deletion() {
void memory_managed::request_deletion(bool) noexcept {
delete this;
}
......
......@@ -38,4 +38,14 @@ ref_counted& ref_counted::operator=(const ref_counted&) {
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
......@@ -592,7 +592,7 @@ void default_multiplexer::wr_dispatch_request(runnable* ptr) {
# endif
if (res <= 0) {
// pipe closed, discard runnable
ptr->request_deletion();
ptr->request_deletion(false);
} else if (static_cast<size_t>(res) < sizeof(ptrval)) {
// must not happen: wrote invalid pointer to pipe
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,
CAF_LOG_DEBUG("read message from pipe");
auto cb = rd_dispatch_request();
cb->run();
cb->request_deletion();
cb->request_deletion(false);
}
}
if (mask & output_mask) {
......@@ -713,7 +713,7 @@ default_multiplexer::~default_multiplexer() {
nonblocking(m_pipe.first, true);
auto ptr = rd_dispatch_request();
while (ptr) {
ptr->request_deletion();
ptr->request_deletion(false);
ptr = rd_dispatch_request();
}
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