Commit daf900c1 authored by Dominik Charousset's avatar Dominik Charousset

Make sure on_exit is called when destroying actors

Also move virtual function calls out of destructors. Relates #454.
parent 406f2f1e
......@@ -64,6 +64,13 @@ public:
virtual ~abstract_actor();
/// Cleans up any remaining state before the destructor is called.
/// This function makes sure it is safe to call virtual functions
/// in sub classes before destroying the object, because calling
/// virtual function in the destructor itself is not safe. Any override
/// implementation is required to call `super::destroy()` at the end.
virtual void destroy();
void enqueue(strong_actor_ptr sender, message_id mid,
message content, execution_unit* host) override;
......
......@@ -26,6 +26,7 @@
#include <type_traits>
#include "caf/config.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#ifdef CAF_GCC
......@@ -75,6 +76,7 @@ public:
private:
static void data_dtor(abstract_actor* ptr) {
// safe due to static assert #3
ptr->destroy();
static_cast<T*>(ptr)->~T();
}
......
......@@ -129,6 +129,8 @@ public:
~local_actor();
void destroy() override;
// -- spawn functions --------------------------------------------------------
template <class T, spawn_options Os = no_spawn_options, class... Ts>
......
......@@ -52,12 +52,12 @@ public:
}
/// Destroys the state of this actor (no further overriding allowed).
void on_exit() override final {
void on_exit() final {
CAF_LOG_TRACE("");
state_.~State();
}
const char* name() const override final {
const char* name() const final {
return get_name(state_);
}
......
......@@ -54,6 +54,10 @@ abstract_actor::~abstract_actor() {
// nop
}
void abstract_actor::destroy() {
// nop
}
void abstract_actor::enqueue(strong_actor_ptr sender, message_id mid,
message msg, execution_unit* host) {
enqueue(mailbox_element::make(sender, mid, {}, std::move(msg)), host);
......
......@@ -99,9 +99,16 @@ local_actor::local_actor(int init_flags)
}
local_actor::~local_actor() {
// nop
}
void local_actor::destroy() {
CAF_LOG_TRACE(CAF_ARG(planned_exit_reason()));
if (planned_exit_reason() == exit_reason::not_exited)
if (planned_exit_reason() == exit_reason::not_exited) {
on_exit();
cleanup(exit_reason::unreachable, nullptr);
}
monitorable_actor::destroy();
}
void local_actor::intrusive_ptr_add_ref_impl() {
......
......@@ -43,9 +43,14 @@ public:
}
~testee() {
printf("%s %d\n", __FILE__, __LINE__);
--s_testees;
}
const char* name() const override {
return "testee";
}
void on_exit() override {
--s_pending_on_exits;
}
......@@ -105,6 +110,15 @@ struct fixture {
} // namespace <anonymous>
CAF_TEST(destructor_call) {
{ // lifetime scope of actor systme
actor_system system;
system.spawn<testee>();
}
CAF_CHECK_EQUAL(s_testees.load(), 0);
CAF_CHECK_EQUAL(s_pending_on_exits.load(), 0);
}
CAF_TEST_FIXTURE_SCOPE(actor_lifetime_tests, fixture)
CAF_TEST(no_spawn_options_and_exit_msg) {
......
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