Commit 0cf245c8 authored by neverlord's avatar neverlord

maintenance

parent a86ae7a4
......@@ -106,6 +106,7 @@ nobase_library_include_HEADERS = \
cppa/detail/default_uniform_type_info_impl.hpp \
cppa/detail/delegate.hpp \
cppa/detail/demangle.hpp \
cppa/detail/disablable_delete.hpp \
cppa/detail/empty_tuple.hpp \
cppa/detail/get_behavior.hpp \
cppa/detail/group_manager.hpp \
......
......@@ -260,3 +260,4 @@ benchmarks/theron_mixed_case.cpp
cppa/util/static_foreach.hpp
cppa/type_value_pair.hpp
examples/dining_philosophers.cpp
cppa/detail/disablable_delete.hpp
......@@ -60,18 +60,16 @@ class abstract_actor : public Base
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exited, m_subscriptions and m_links
//std::mutex m_mtx;
detail::mutex m_mtx;
// manages actor links
std::list<actor_ptr> m_links;
// links to other actors
std::vector<actor_ptr> m_links;
// code that is executed on cleanup
std::vector<attachable_ptr> m_attachables;
public:
class queue_node_ptr;
struct queue_node
{
friend class abstract_actor;
......@@ -106,36 +104,6 @@ class abstract_actor : public Base
return m_exit_reason.load() != exit_reason::not_exited;
}
template<class List, typename Element>
bool unique_insert(List& lst, Element const& e)
{
auto end = lst.end();
auto i = std::find(lst.begin(), end, e);
if (i == end)
{
lst.push_back(e);
return true;
}
return false;
}
template<class List, typename Iterator, typename Element>
int erase_all(List& lst, Iterator begin, Iterator end, Element const& e)
{
auto i = std::find(begin, end, e);
if (i != end)
{
return 1 + erase_all(lst, lst.erase(i), end, e);
}
return 0;
}
template<class List, typename Element>
int erase_all(List& lst, Element const& e)
{
return erase_all(lst, lst.begin(), lst.end(), e);
}
protected:
template<typename T>
......@@ -170,14 +138,11 @@ class abstract_actor : public Base
m_links.clear();
m_attachables.clear();
}
if (!mlinks.empty())
{
// send exit messages
for (actor_ptr& aptr : mlinks)
{
aptr->enqueue(this, make_tuple(atom(":Exit"), reason));
}
}
for (attachable_ptr& ptr : mattachables)
{
ptr->actor_exited(reason);
......@@ -189,11 +154,14 @@ class abstract_actor : public Base
if (other && other != this)
{
guard_type guard(m_mtx);
// send exit message if already exited
if (exited())
{
other->enqueue(this, make_tuple(atom(":Exit"),
m_exit_reason.load()));
}
// add link if not already linked to other
// (checked by establish_backlink)
else if (other->establish_backlink(this))
{
m_links.push_back(other);
......@@ -206,9 +174,13 @@ class abstract_actor : public Base
bool unlink_from_impl(intrusive_ptr<actor>& other)
{
guard_type guard(m_mtx);
// remove_backlink returns true if this actor is linked to other
if (other && !exited() && other->remove_backlink(this))
{
return erase_all(m_links, other) > 0;
auto i = std::find(m_links.begin(), m_links.end(), other);
CPPA_REQUIRE(i != m_links.end());
m_links.erase(i);
return true;
}
return false;
}
......@@ -278,7 +250,12 @@ class abstract_actor : public Base
if (other && other != this)
{
guard_type guard(m_mtx);
return erase_all(m_links, other) > 0;
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i != m_links.end())
{
m_links.erase(i);
return true;
}
}
return false;
}
......@@ -292,7 +269,12 @@ class abstract_actor : public Base
reason = m_exit_reason.load();
if (reason == exit_reason::not_exited)
{
return unique_insert(m_links, other);
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i == m_links.end())
{
m_links.push_back(other);
return true;
}
}
}
// send exit message without lock
......
......@@ -39,6 +39,7 @@
#include "cppa/either.hpp"
#include "cppa/pattern.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/detail/disablable_delete.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp"
namespace cppa {
......@@ -95,69 +96,10 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
abstract_event_based_actor();
struct stack_element
{
stack_element() = delete;
stack_element(stack_element const&) = delete;
stack_element& operator=(stack_element const&) = delete;
either<invoke_rules*, timed_invoke_rules*> m_ptr;
bool m_ownership;
inline stack_element(invoke_rules* ptr, bool take_ownership)
: m_ptr(ptr), m_ownership(take_ownership)
{
}
inline stack_element(timed_invoke_rules* ptr, bool take_ownership)
: m_ptr(ptr), m_ownership(take_ownership)
{
}
inline stack_element(stack_element&& other)
: m_ptr(other.m_ptr), m_ownership(other.m_ownership)
{
other.m_ownership = false;
}
inline stack_element& operator=(stack_element&& other)
{
m_ptr = other.m_ptr;
m_ownership = other.m_ownership;
other.m_ownership = false;
return *this;
}
inline ~stack_element()
{
if (m_ownership)
{
if (m_ptr.is_left())
{
delete m_ptr.left();
}
else
{
delete m_ptr.right();
}
}
}
inline bool is_left() { return m_ptr.is_left(); }
inline bool is_right() { return m_ptr.is_right(); }
inline invoke_rules& left()
{
auto ptr = m_ptr.left();
CPPA_REQUIRE(ptr != nullptr);
return *(ptr);
}
inline timed_invoke_rules& right()
{
auto ptr = m_ptr.right();
CPPA_REQUIRE(ptr != nullptr);
return *(ptr);
}
};
// ownership flag + pointer
typedef either<std::unique_ptr<invoke_rules, detail::disablable_delete<invoke_rules>>,
std::unique_ptr<timed_invoke_rules, detail::disablable_delete<timed_invoke_rules>>>
stack_element;
queue_node_buffer m_buffer;
std::vector<stack_element> m_loop_stack;
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef DISABLABLE_DELETE_HPP
#define DISABLABLE_DELETE_HPP
namespace cppa { namespace detail {
template<typename T>
class disablable_delete
{
bool m_enabled;
public:
disablable_delete() : m_enabled(true) { }
inline void disable() { m_enabled = false; }
inline void operator()(T* ptr)
{
if (m_enabled) delete ptr;
}
};
} } // namespace cppa::detail
#endif // DISABLABLE_DELETE_HPP
......@@ -51,6 +51,9 @@ class either
public:
typedef Left left_type;
typedef Right right_type;
/**
* @brief Default constructor, creates a @p Left.
*/
......
......@@ -72,9 +72,10 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node,
// request next timeout if needed
if (!m_loop_stack.empty())
{
if (m_loop_stack.back().is_right())
auto& back = m_loop_stack.back();
if (back.is_right())
{
request_timeout(m_loop_stack.back().right().timeout());
request_timeout(back.right()->timeout());
}
}
break;
......@@ -88,11 +89,11 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node)
auto& bhvr = m_loop_stack.back();
if (bhvr.is_left())
{
handle_message(node, bhvr.left());
handle_message(node, *(bhvr.left()));
}
else
{
handle_message(node, bhvr.right());
handle_message(node, *(bhvr.right()));
}
}
......
......@@ -33,19 +33,19 @@
namespace {
template<class StackElement, class Vec, class What>
void push_to(Vec& vec, What* bhvr, bool has_ownership)
void push_to(Vec& vec, What&& bhvr)
{
// keep always the latest element in the stack to prevent subtle errors,
// e.g., the addresses of all variables in a lambda expression calling
// become() suddenly are invalid if we would pop the behavior!
if (vec.size() < 2)
{
vec.push_back(StackElement(bhvr, has_ownership));
vec.push_back(std::move(bhvr));
}
else
{
vec[0] = std::move(vec[1]);
vec[1] = StackElement(bhvr, has_ownership);
vec[1] = std::move(bhvr);
}
}
......@@ -73,13 +73,17 @@ void event_based_actor::do_become(behavior* bhvr)
void event_based_actor::do_become(invoke_rules* bhvr, bool has_ownership)
{
reset_timeout();
push_to<stack_element>(m_loop_stack, bhvr, has_ownership);
stack_element::left_type ptr(bhvr);
if (!has_ownership) ptr.get_deleter().disable();
push_to<stack_element>(m_loop_stack, std::move(ptr));
}
void event_based_actor::do_become(timed_invoke_rules* bhvr, bool has_ownership)
{
request_timeout(bhvr->timeout());
push_to<stack_element>(m_loop_stack, bhvr, has_ownership);
stack_element::right_type ptr(bhvr);
if (!has_ownership) ptr.get_deleter().disable();
push_to<stack_element>(m_loop_stack, std::move(ptr));
}
} // namespace cppa
......@@ -39,21 +39,28 @@ void stacked_event_based_actor::become_void()
void stacked_event_based_actor::unbecome()
{
if (!m_loop_stack.empty()) m_loop_stack.pop_back();
if (!m_loop_stack.empty())
{
m_loop_stack.pop_back();
}
}
void stacked_event_based_actor::do_become(invoke_rules* behavior,
bool has_ownership)
{
reset_timeout();
m_loop_stack.push_back(stack_element(behavior, has_ownership));
stack_element::left_type ptr(behavior);
if (!has_ownership) ptr.get_deleter().disable();
m_loop_stack.push_back(std::move(ptr));
}
void stacked_event_based_actor::do_become(timed_invoke_rules* behavior,
bool has_ownership)
{
request_timeout(behavior->timeout());
m_loop_stack.push_back(stack_element(behavior, has_ownership));
stack_element::right_type ptr(behavior);
if (!has_ownership) ptr.get_deleter().disable();
m_loop_stack.push_back(std::move(ptr));
}
} // namespace cppa
......@@ -30,9 +30,12 @@ size_t test__atom()
{
bool matched_pattern[3] = { false, false, false };
CPPA_TEST(test__atom);
// check if there are leading bits that distinguish "zzz" and "000 "
CPPA_CHECK_NOT_EQUAL(atom("zzz"), atom("000 "));
// 'illegal' characters are mapped to whitespaces
CPPA_CHECK_EQUAL(atom(" "), atom("@!?"));
CPPA_CHECK_NOT_EQUAL(atom("abc"), atom(" abc"));
// check to_string impl.
CPPA_CHECK_EQUAL(to_string(s_foo), "FooBar");
self << make_tuple(atom("foo"), static_cast<std::uint32_t>(42))
<< make_tuple(atom(":Attach"), atom(":Baz"), "cstring")
......
......@@ -48,6 +48,8 @@ class0_ptr get_test_ptr()
size_t test__intrusive_ptr()
{
// this test dosn't test thread-safety of intrusive_ptr
// however, it is thread safe since it uses atomic operations only
CPPA_TEST(test__intrusive_ptr);
......
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