Skip to content

Commit e1d9102

Browse files
Merge pull request #12 from tenzir/topic/experimental-rp-fix
Fix delivering response promises in actor state destructors
2 parents 261a6b3 + bf88d1c commit e1d9102

File tree

2 files changed

+28
-13
lines changed

2 files changed

+28
-13
lines changed

libcaf_core/caf/actor_control_block.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ CAF_CORE_EXPORT void intrusive_ptr_release_weak(actor_control_block* x);
136136

137137
/// @relates actor_control_block
138138
inline void intrusive_ptr_add_ref(actor_control_block* x) {
139-
x->strong_refs.fetch_add(1, std::memory_order_relaxed);
139+
if (CAF_UNLIKELY(x->strong_refs.fetch_add(1, std::memory_order_relaxed) == 0)) {
140+
CAF_CRITICAL("increased the strong reference count of an expired actor");
141+
}
140142
}
141143

142144
/// @relates actor_control_block

libcaf_core/src/response_promise.cpp

+25-12
Original file line numberDiff line numberDiff line change
@@ -166,22 +166,35 @@ void response_promise::state::cancel() {
166166

167167
void response_promise::state::deliver_impl(message msg) {
168168
CAF_LOG_TRACE(CAF_ARG(msg));
169-
// Even though we are holding a weak pointer, we can access the pointer
170-
// without any additional check here because only the actor itself is allowed
171-
// to call this function.
172-
auto self = static_cast<local_actor*>(weak_self.get()->get());
169+
auto cancel_guard = detail::make_scope_guard([this] {
170+
cancel();
171+
});
173172
if (msg.empty() && id.is_async()) {
174173
CAF_LOG_DEBUG("drop response: empty response to asynchronous input");
175-
} else if (!stages.empty()) {
174+
return;
175+
}
176+
if (source == nullptr) {
177+
CAF_LOG_DEBUG("drop response: source is nullptr");
178+
return;
179+
}
180+
auto self = weak_self.lock();
181+
if (self == nullptr) {
182+
auto element = make_mailbox_element(self, id.response_id(),
183+
std::move(stages),
184+
std::move(msg));
185+
source->enqueue(std::move(element), nullptr);
186+
return;
187+
}
188+
auto local_self = static_cast<local_actor*>(self->get());
189+
if (!stages.empty()) {
176190
auto next = std::move(stages.back());
177191
stages.pop_back();
178-
detail::profiled_send(self, std::move(source), next, id, std::move(stages),
179-
self->context(), std::move(msg));
180-
} else if (source != nullptr) {
181-
detail::profiled_send(self, self->ctrl(), source, id.response_id(),
182-
forwarding_stack{}, self->context(), std::move(msg));
183-
}
184-
cancel();
192+
detail::profiled_send(local_self, std::move(source), next, id, std::move(stages),
193+
local_self->context(), std::move(msg));
194+
return;
195+
}
196+
detail::profiled_send(local_self, local_self->ctrl(), source, id.response_id(),
197+
forwarding_stack{}, local_self->context(), std::move(msg));
185198
}
186199

187200
void response_promise::state::delegate_impl(abstract_actor* receiver,

0 commit comments

Comments
 (0)