Commit 532c069d authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'Lingxi-Li-topic/refine_mem_order'

parents a481bdbf b88a6e13
......@@ -51,15 +51,25 @@ public:
size_t detach(const attachable::token& what) override;
/// Returns the exit reason of this actor or
/// `exit_reason::not_exited` if it is still alive.
inline exit_reason get_exit_reason() const {
return exit_reason_.load(std::memory_order_relaxed);
}
/// @cond PRIVATE
/// Called by the runtime system to perform cleanup actions for this actor.
/// Subtypes should always call this member function when overriding it.
/// This member function is thread-safe, and if the actor has already exited
/// upon invocation, nothing is done.
virtual void cleanup(exit_reason reason, execution_unit* host);
// Returns `exit_reason_ != exit_reason::not_exited`.
// returns `exit_reason_ != exit_reason::not_exited`;
// it's possible for user code to call this method
// without acquiring `mtx_`
inline bool exited() const {
return exit_reason_ != exit_reason::not_exited;
return get_exit_reason() != exit_reason::not_exited;
}
/// @endcond
......@@ -91,19 +101,25 @@ protected:
// tries to run a custom exception handler for `eptr`
maybe<exit_reason> handle(const std::exception_ptr& eptr);
// precondition: `mtx_` is acquired
inline void attach_impl(attachable_ptr& ptr) {
ptr->next.swap(attachables_head_);
attachables_head_.swap(ptr);
}
// precondition: `mtx_` is acquired
static size_t detach_impl(const attachable::token& what,
attachable_ptr& ptr,
bool stop_on_first_hit = false,
bool dry_run = false);
// handles only `exit_msg` and `sys_atom` messages;
// returns true if the message is handled
bool handle_system_message(mailbox_element& node, execution_unit* context,
bool trap_exit);
// handles `exit_msg`, `sys_atom` messages, and additionally `down_msg`
// with `down_msg_handler`; returns true if the message is handled
template <class F>
bool handle_system_message(mailbox_element& node, execution_unit* context,
bool trap_exit, F& down_msg_handler) {
......@@ -115,7 +131,9 @@ protected:
return handle_system_message(node, context, trap_exit);
}
// initially set to exit_reason::not_exited
// initially set to exit_reason::not_exited;
// can only be stored with `mtx_` acquired;
// may be read without acquiring `mtx_`
std::atomic<exit_reason> exit_reason_;
// guards access to exit_reason_, attachables_, links_,
......
......@@ -50,7 +50,7 @@ adapter::adapter(actor_addr decorated, message msg)
void adapter::enqueue(mailbox_element_ptr what, execution_unit* host) {
if (! what)
return; // not even an empty message
auto reason = exit_reason_.load();
auto reason = get_exit_reason();
if (reason != exit_reason::not_exited) {
// actor has exited
auto& mid = what->mid;
......
......@@ -69,7 +69,7 @@ local_actor::local_actor(actor_system* sys, actor_id aid,
local_actor::~local_actor() {
if (! mailbox_.closed()) {
detail::sync_request_bouncer f{exit_reason_};
detail::sync_request_bouncer f{get_exit_reason()};
mailbox_.close(f);
}
}
......
......@@ -39,7 +39,7 @@ void monitorable_actor::attach(attachable_ptr ptr) {
caf::exit_reason reason;
{ // lifetime scope of guard
std::unique_lock<std::mutex> guard{mtx_};
reason = exit_reason_;
reason = get_exit_reason();
if (reason == exit_reason::not_exited) {
attach_impl(ptr);
return;
......@@ -58,13 +58,13 @@ size_t monitorable_actor::detach(const attachable::token& what) {
void monitorable_actor::cleanup(exit_reason reason, execution_unit* host) {
CAF_LOG_TRACE(CAF_ARG(reason));
CAF_ASSERT(reason != exit_reason::not_exited);
// move everyhting out of the critical section before processing it
// move everything out of the critical section before processing it
attachable_ptr head;
{ // lifetime scope of guard
std::unique_lock<std::mutex> guard{mtx_};
if (exit_reason_ != exit_reason::not_exited)
if (get_exit_reason() != exit_reason::not_exited)
return;
exit_reason_ = reason;
exit_reason_.store(reason, std::memory_order_relaxed);
attachables_head_.swap(head);
}
CAF_LOG_INFO_IF(host && host->system().node() == node(),
......@@ -130,10 +130,12 @@ bool monitorable_actor::establish_link_impl(const actor_addr& other) {
if (other && other != this) {
std::unique_lock<std::mutex> guard{mtx_};
auto ptr = actor_cast<abstract_actor_ptr>(other);
auto reason = get_exit_reason();
// send exit message if already exited
if (exited()) {
if (reason != exit_reason::not_exited) {
guard.unlock();
ptr->enqueue(address(), invalid_message_id,
make_message(exit_msg{address(), exit_reason_}), nullptr);
make_message(exit_msg{address(), reason}), nullptr);
} else if (ptr->establish_backlink(address())) {
// add link if not already linked to other
// (checked by establish_backlink)
......@@ -151,7 +153,7 @@ bool monitorable_actor::establish_backlink_impl(const actor_addr& other) {
default_attachable::observe_token tk{other, default_attachable::link};
if (other && other != this) {
std::unique_lock<std::mutex> guard{mtx_};
reason = exit_reason_;
reason = get_exit_reason();
if (reason == exit_reason::not_exited) {
if (detach_impl(tk, attachables_head_, true, true) == 0) {
auto tmp = default_attachable::make_link(other);
......@@ -164,7 +166,7 @@ bool monitorable_actor::establish_backlink_impl(const actor_addr& other) {
if (reason != exit_reason::not_exited) {
auto ptr = actor_cast<abstract_actor_ptr>(other);
ptr->enqueue(address(), invalid_message_id,
make_message(exit_msg{address(), exit_reason_}), nullptr);
make_message(exit_msg{address(), reason}), nullptr);
}
return false;
}
......@@ -178,6 +180,7 @@ bool monitorable_actor::remove_link_impl(const actor_addr& other) {
// remove_backlink returns true if this actor is linked to other
auto ptr = actor_cast<abstract_actor_ptr>(other);
if (detach_impl(tk, attachables_head_, true) > 0) {
guard.unlock();
// tell remote side to remove link as well
ptr->remove_backlink(address());
return true;
......@@ -220,6 +223,7 @@ bool monitorable_actor::handle_system_message(mailbox_element& node,
bool trap_exit) {
auto& msg = node.msg;
if (! trap_exit && msg.size() == 1 && msg.match_element<exit_msg>(0)) {
// exits for non-normal exit reasons
auto& em = msg.get_as<exit_msg>(0);
CAF_ASSERT(em.reason != exit_reason::not_exited);
if (em.reason != exit_reason::normal)
......
......@@ -47,7 +47,7 @@ sequencer::sequencer(actor_addr f, actor_addr g, message_types_set msg_types)
void sequencer::enqueue(mailbox_element_ptr what, execution_unit* context) {
if (! what)
return; // not even an empty message
auto reason = exit_reason_.load();
auto reason = get_exit_reason();
if (reason != exit_reason::not_exited) {
// actor has exited
auto& mid = what->mid;
......
......@@ -83,7 +83,7 @@ splitter::splitter(std::vector<actor_addr> workers, message_types_set msg_types)
void splitter::enqueue(mailbox_element_ptr what, execution_unit* context) {
if (! what)
return; // not even an empty message
auto reason = exit_reason_.load();
auto reason = get_exit_reason();
if (reason != exit_reason::not_exited) {
// actor has exited
auto& mid = what->mid;
......
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