Commit 880c838d authored by neverlord's avatar neverlord

maintenance

parent c8cb7827
......@@ -22,7 +22,6 @@ cppa/detail/tuple_vals.hpp
cppa/match.hpp
cppa/detail/decorated_tuple.hpp
cppa/cow_ptr.hpp
cppa/util/detach.hpp
cppa/detail/ref_counted_impl.hpp
cppa/intrusive_ptr.hpp
unit_testing/test__spawn.cpp
......@@ -184,3 +183,7 @@ src/native_socket.cpp
cppa/detail/post_office.hpp
src/post_office.cpp
cppa/detail/buffer.hpp
cppa/detail/task_scheduler.hpp
src/task_scheduler.cpp
cppa/detail/actor_count.hpp
src/actor_count.cpp
......@@ -15,6 +15,9 @@ namespace cppa {
class attachable
{
attachable(const attachable&) = delete;
attachable& operator=(const attachable&) = delete;
protected:
attachable() = default;
......
......@@ -35,7 +35,7 @@ class context : public actor
*
* Calls <code>mailbox().enqueue(msg)</code>.
*/
virtual void enqueue /*[[override]]*/ (const message& msg);
virtual void enqueue(const message& msg) /*override*/;
void trap_exit(bool new_value);
......
......@@ -2,73 +2,109 @@
#define COW_PTR_HPP
#include <stdexcept>
#include "cppa/util/detach.hpp"
#include <type_traits>
#include "cppa/intrusive_ptr.hpp"
#include "cppa/util/is_copyable.hpp"
#include "cppa/util/has_copy_member_fun.hpp"
namespace cppa { namespace detail {
template<typename T>
constexpr int copy_method()
{
return util::has_copy_member_fun<T>::value
? 2
: (util::is_copyable<T>::value ? 1 : 0);
}
// is_copyable
template<typename T>
T* copy_of(const T* what, std::integral_constant<int, 1>)
{
return new T(*what);
}
// has_copy_member_fun
template<typename T>
T* copy_of(const T* what, std::integral_constant<int, 2>)
{
return what->copy();
}
} } // namespace cppa::detail
namespace cppa {
template<typename T>
class cow_ptr
{
intrusive_ptr<T> m_ptr;
T* do_detach()
{
T* ptr = m_ptr.get();
if (!ptr->unique())
{
T* new_ptr = util::detach(ptr);
cow_ptr tmp(new_ptr);
swap(tmp);
return new_ptr;
}
return ptr;
}
static_assert(detail::copy_method<T>() != 0, "T is not copyable");
typedef std::integral_constant<int, detail::copy_method<T>()> copy_of_token;
intrusive_ptr<T> m_ptr;
T* detach_ptr()
{
T* ptr = m_ptr.get();
if (!ptr->unique())
{
T* new_ptr = detail::copy_of(ptr, copy_of_token());
cow_ptr tmp(new_ptr);
swap(tmp);
return new_ptr;
}
return ptr;
}
public:
template<typename Y>
cow_ptr(Y* raw_ptr) : m_ptr(raw_ptr) { }
template<typename Y>
cow_ptr(Y* raw_ptr) : m_ptr(raw_ptr) { }
cow_ptr(T* raw_ptr) : m_ptr(raw_ptr) { }
cow_ptr(T* raw_ptr) : m_ptr(raw_ptr) { }
cow_ptr(const cow_ptr& other) : m_ptr(other.m_ptr) { }
cow_ptr(const cow_ptr& other) : m_ptr(other.m_ptr) { }
template<typename Y>
cow_ptr(const cow_ptr<Y>& other) : m_ptr(const_cast<Y*>(other.get())) { }
template<typename Y>
cow_ptr(const cow_ptr<Y>& other) : m_ptr(const_cast<Y*>(other.get())) { }
inline void swap(cow_ptr& other)
{
m_ptr.swap(other.m_ptr);
}
const T* get() const { return m_ptr.get(); }
cow_ptr& operator=(const cow_ptr& other)
{
cow_ptr tmp(other);
swap(tmp);
return *this;
}
inline void swap(cow_ptr& other)
{
m_ptr.swap(other.m_ptr);
}
template<typename Y>
cow_ptr& operator=(const cow_ptr<Y>& other)
{
cow_ptr tmp(other);
swap(tmp);
return *this;
}
cow_ptr& operator=(const cow_ptr& other)
{
cow_ptr tmp(other);
swap(tmp);
return *this;
}
inline T* get() { return detach_ptr(); }
template<typename Y>
cow_ptr& operator=(const cow_ptr<Y>& other)
{
cow_ptr tmp(other);
swap(tmp);
return *this;
}
inline const T* get() const { return m_ptr.get(); }
T* operator->() { return do_detach(); }
inline T* operator->() { return detach_ptr(); }
T& operator*() { return do_detach(); }
inline T& operator*() { return detach_ptr(); }
const T* operator->() const { return m_ptr.get(); }
inline const T* operator->() const { return m_ptr.get(); }
const T& operator*() const { return *m_ptr.get(); }
inline const T& operator*() const { return *m_ptr.get(); }
explicit operator bool() const { return m_ptr.get() != nullptr; }
inline explicit operator bool() const { return static_cast<bool>(m_ptr); }
};
......
......@@ -140,7 +140,7 @@ class abstract_actor /*[[base_check]]*/ : public Base
public:
bool attach /*[[override]]*/ (attachable* ptr)
bool attach(attachable* ptr) /*override*/
{
if (ptr == nullptr)
{
......@@ -166,7 +166,7 @@ class abstract_actor /*[[base_check]]*/ : public Base
}
}
void detach /*[[override]]*/ (const attachable::token& what)
void detach(const attachable::token& what) /*override*/
{
attachable_ptr uptr;
// lifetime scope of guard
......@@ -186,17 +186,17 @@ class abstract_actor /*[[base_check]]*/ : public Base
// uptr will be destroyed here, without locked mutex
}
void link_to /*[[override]]*/ (intrusive_ptr<actor>& other)
void link_to(intrusive_ptr<actor>& other) /*override*/
{
(void) link_to_impl(other);
}
void unlink_from /*[[override]]*/ (intrusive_ptr<actor>& other)
void unlink_from(intrusive_ptr<actor>& other) /*override*/
{
(void) unlink_from_impl(other);
}
bool remove_backlink /*[[override]]*/ (intrusive_ptr<actor>& other)
bool remove_backlink(intrusive_ptr<actor>& other) /*override*/
{
if (other && other != this)
{
......@@ -206,7 +206,7 @@ class abstract_actor /*[[base_check]]*/ : public Base
return false;
}
bool establish_backlink /*[[override]]*/ (intrusive_ptr<actor>& other)
bool establish_backlink(intrusive_ptr<actor>& other) /*override*/
{
bool result = false;
std::uint32_t reason = exit_reason::not_exited;
......
#ifndef ACTOR_COUNT_HPP
#define ACTOR_COUNT_HPP
namespace cppa { namespace detail {
void inc_actor_count();
void dec_actor_count();
// @pre expected <= 1
void actor_count_wait_until(size_t expected);
} } // namespace cppa::detail
#endif // ACTOR_COUNT_HPP
......@@ -28,17 +28,17 @@ class blocking_message_queue : public message_queue
virtual void trap_exit(bool new_value);
virtual void enqueue /*[[override]]*/ (const message& msg);
virtual void enqueue(const message& msg) /*override*/;
virtual const message& dequeue /*[[override]]*/ ();
virtual const message& dequeue() /*override*/;
virtual void dequeue /*[[override]]*/ (invoke_rules& rules);
virtual void dequeue(invoke_rules& rules) /*override*/;
virtual bool try_dequeue /*[[override]]*/ (message& msg);
virtual bool try_dequeue(message& msg) /*override*/;
virtual bool try_dequeue /*[[override]]*/ (invoke_rules& rules);
virtual bool try_dequeue(invoke_rules& rules) /*override*/;
virtual const message& last_dequeued /*[[override]]*/ ();
virtual const message& last_dequeued() /*override*/;
};
......
......@@ -28,12 +28,12 @@ class converted_thread_context : public abstract_actor<context>
public:
message_queue& mailbox /*[[override]]*/ ();
message_queue& mailbox() /*override*/;
// called if the converted thread finished execution
void cleanup(std::uint32_t reason = exit_reason::normal);
void quit /*[[override]]*/ (std::uint32_t reason);
void quit(std::uint32_t reason) /*override*/;
};
......
......@@ -35,7 +35,7 @@ class list_member : public util::abstract_uniform_type_info<List>
for (size_t i = 0; i < ls_size; ++i)
{
primitive_variant val = d->read_value(vptype);
ls.push_back(std::move(get<value_type>(val)));
ls.push_back(std::move(get_ref<value_type>(val)));
}
d->end_sequence();
}
......
#ifndef TASK_SCHEDULER_HPP
#define TASK_SCHEDULER_HPP
#include "cppa/scheduler.hpp"
namespace cppa { namespace detail {
class task_scheduler : public scheduler
{
public:
void await_others_done();
void register_converted_context(context*);
//void unregister_converted_context(context*);
actor_ptr spawn(actor_behavior*, scheduling_hint);
attachable* register_hidden_context();
};
} } // namespace cppa::detail
#endif // TASK_SCHEDULER_HPP
......@@ -10,6 +10,9 @@
namespace cppa {
/**
* @brief A multicast group.
*/
class group : public channel
{
......@@ -28,6 +31,7 @@ class group : public channel
class unsubscriber;
// needs access to unsubscribe()
friend class unsubscriber;
// unsubscribes its channel from the group on destruction
......@@ -39,15 +43,11 @@ class group : public channel
channel_ptr m_self;
intrusive_ptr<group> m_group;
unsubscriber() = delete;
unsubscriber(const unsubscriber&) = delete;
unsubscriber& operator=(const unsubscriber&) = delete;
public:
unsubscriber(const channel_ptr& s, const intrusive_ptr<group>& g);
// matches on group
// matches on m_group
bool matches(const attachable::token& what);
virtual ~unsubscriber();
......@@ -56,25 +56,69 @@ class group : public channel
typedef std::unique_ptr<unsubscriber> subscription;
/**
* @brief Module interface.
*/
class module
{
std::string m_name;
protected:
module(std::string&& module_name);
module(const std::string& module_name);
public:
virtual const std::string& name() = 0;
/**
* @brief Get the name of this module implementation.
* @return The name of this module implementation.
* @threadsafe
*/
const std::string& name();
/**
* @brief Get a pointer to the group associated with
* the name @p group_name.
* @threadsafe
*/
virtual intrusive_ptr<group> get(const std::string& group_name) = 0;
};
/**
* @brief A string representation of the group identifier.
* @return The group identifier as string (e.g. "224.0.0.1" for IPv4
* multicast or a user-defined string for local groups).
*/
const std::string& identifier() const;
/**
* @brief The name of the module.
* @return The module name of this group (e.g. "local").
*/
const std::string& module_name() const;
/**
* @brief Subscribe @p who to this group.
* @return A {@link subscription} object that unsubscribes @p who
* if the lifetime of @p who ends.
*/
virtual subscription subscribe(const channel_ptr& who) = 0;
/**
* @brief Get a pointer to the group associated with
* @p group_identifier from the module @p module_name.
* @threadsafe
*/
static intrusive_ptr<group> get(const std::string& module_name,
const std::string& group_name);
const std::string& group_identifier);
/**
* @brief Add a new group module to the libcppa group management.
* @threadsafe
*/
static void add_module(module*);
};
......
......@@ -61,9 +61,9 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T>, const T*>,
}
}
T* get() { return m_ptr; }
inline T* get() { return m_ptr; }
const T* get() const { return m_ptr; }
inline const T* get() const { return m_ptr; }
T* take()
{
......@@ -123,13 +123,13 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T>, const T*>,
return *this;
}
T* operator->() { return m_ptr; }
inline T* operator->() { return m_ptr; }
T& operator*() { return *m_ptr; }
inline T& operator*() { return *m_ptr; }
const T* operator->() const { return m_ptr; }
inline const T* operator->() const { return m_ptr; }
const T& operator*() const { return *m_ptr; }
inline const T& operator*() const { return *m_ptr; }
inline explicit operator bool() const { return m_ptr != nullptr; }
......@@ -166,9 +166,9 @@ bool operator==(const intrusive_ptr<X>& lhs, const intrusive_ptr<Y>& rhs)
}
template<typename X, typename Y>
bool operator!=(const intrusive_ptr<X>& lhs, const intrusive_ptr<Y>& rhs)
inline bool operator!=(const intrusive_ptr<X>& lhs, const intrusive_ptr<Y>& rhs)
{
return lhs.get() != rhs.get();
return !(lhs == rhs);
}
} // namespace cppa
......
......@@ -244,6 +244,20 @@ const typename detail::ptype_to_type<PT>::type& get(const primitive_variant& pv)
return pv.get_as<PT>();
}
template<typename T>
T& get_ref(primitive_variant& pv)
{
static const primitive_type ptype = detail::type_to_ptype<T>::ptype;
return pv.get_as<ptype>();
}
template<primitive_type PT>
typename detail::ptype_to_type<PT>::type& get_ref(primitive_variant& pv)
{
static_assert(PT != pt_null, "PT == pt_null");
return pv.get_as<PT>();
}
template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type
operator==(const T& lhs, const primitive_variant& rhs)
......
......@@ -39,6 +39,7 @@ class scheduler
/**
* @brief Informs the scheduler about a converted context
* (a thread that acts as actor).
* @note Calls <tt>what->attach(...)</tt>.
*/
virtual void register_converted_context(context* what) = 0;
......@@ -61,7 +62,7 @@ class scheduler
/**
* @brief Gets the actual used scheduler implementation.
* @return The active scheduler or @c nullptr.
* @return The active scheduler (default constructed).
*/
scheduler* get_scheduler();
......
......@@ -8,7 +8,6 @@
#include "cppa/util/compare_tuples.hpp"
#include "cppa/util/concat_type_lists.hpp"
#include "cppa/util/conjunction.hpp"
#include "cppa/util/detach.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/eval_first_n.hpp"
......
#ifndef DETACH_HPP
#define DETACH_HPP
#include "cppa/util/is_copyable.hpp"
#include "cppa/util/has_copy_member_fun.hpp"
namespace cppa { namespace detail {
template<bool IsCopyable, bool HasCpyMemFun>
struct detach_;
template<bool HasCpyMemFun>
struct detach_<true, HasCpyMemFun>
{
template<typename T>
inline static T* cpy(const T* what)
{
return new T(*what);
}
};
template<>
struct detach_<false, true>
{
template<typename T>
inline static T* cpy(const T* what)
{
return what->copy();
}
};
} } // namespace cppa::detail
namespace cppa { namespace util {
template<typename T>
inline T* detach(const T* what)
{
return detail::detach_<is_copyable<T>::value,
has_copy_member_fun<T>::value>::cpy(what);
}
} } // namespace cppa::util
#endif // DETACH_HPP
......@@ -43,13 +43,8 @@ class is_copyable_<true, T>
namespace cppa { namespace util {
template<typename T>
struct is_copyable
struct is_copyable : std::integral_constant<bool, detail::is_copyable_<std::is_abstract<T>::value, T>::value>
{
public:
static const bool value = detail::is_copyable_<std::is_abstract<T>::value, T>::value;
};
} } // namespace cppa::util
......
#include <limits>
#include <atomic>
#include <stdexcept>
#include <boost/thread.hpp>
#include "cppa/detail/actor_count.hpp"
namespace {
boost::mutex s_ra_mtx;
boost::condition_variable s_ra_cv;
std::atomic<size_t> s_running_actors(0);
typedef boost::unique_lock<boost::mutex> guard_type;
} // namespace <anonymous>
namespace cppa { namespace detail {
void inc_actor_count()
{
++s_running_actors;
}
void dec_actor_count()
{
size_t new_val = --s_running_actors;
if (new_val == std::numeric_limits<size_t>::max())
{
throw std::underflow_error("dec_actor_count()");
}
else if (new_val <= 1)
{
guard_type guard(s_ra_mtx);
s_ra_cv.notify_all();
}
}
void actor_count_wait_until(size_t expected)
{
guard_type lock(s_ra_mtx);
while (s_running_actors.load() != expected)
{
s_ra_cv.wait(lock);
}
}
} } // namespace cppa::detail
......@@ -18,19 +18,20 @@ namespace {
typedef std::map< std::string, std::unique_ptr<group::module> > modules_map;
typedef std::lock_guard<util::shared_spinlock> exclusive_guard;
typedef util::shared_lock_guard<util::shared_spinlock> shared_guard;
typedef util::upgrade_lock_guard<util::shared_spinlock> upgrade_guard;
typedef util::shared_spinlock shared_mutex_type;
typedef std::lock_guard<shared_mutex_type> exclusive_guard;
typedef util::shared_lock_guard<shared_mutex_type> shared_guard;
typedef util::upgrade_lock_guard<shared_mutex_type> upgrade_guard;
std::mutex s_mtx;
modules_map s_mmap;
std::mutex s_mmap_mtx;
class local_group : public group
{
friend class local_group_module;
util::shared_spinlock m_mtx;
shared_mutex_type m_shared_mtx;
std::set<channel_ptr> m_subscribers;
// allow access to local_group_module only
......@@ -42,7 +43,7 @@ class local_group : public group
virtual void enqueue(const message& msg)
{
shared_guard guard(m_mtx);
shared_guard guard(m_shared_mtx);
for (auto i = m_subscribers.begin(); i != m_subscribers.end(); ++i)
{
const_cast<channel_ptr&>(*i)->enqueue(msg);
......@@ -52,7 +53,7 @@ class local_group : public group
virtual group::subscription subscribe(const channel_ptr& who)
{
group::subscription result;
exclusive_guard guard(m_mtx);
exclusive_guard guard(m_shared_mtx);
if (m_subscribers.insert(who).second)
{
result.reset(new group::unsubscriber(who, this));
......@@ -62,7 +63,7 @@ class local_group : public group
virtual void unsubscribe(const channel_ptr& who)
{
exclusive_guard guard(m_mtx);
exclusive_guard guard(m_shared_mtx);
m_subscribers.erase(who);
}
......@@ -71,20 +72,16 @@ class local_group : public group
class local_group_module : public group::module
{
std::string m_name;
typedef group::module super;
util::shared_spinlock m_mtx;
std::map<std::string, group_ptr> m_instances;
public:
local_group_module() : m_name("local")
{
}
const std::string& name()
local_group_module() : super("local")
{
return m_name;
}
group_ptr get(const std::string& group_name)
......@@ -110,6 +107,7 @@ class local_group_module : public group::module
};
// @pre: s_mmap_mtx is locked
modules_map& mmap()
{
if (s_mmap.empty())
......@@ -128,7 +126,7 @@ intrusive_ptr<group> group::get(const std::string& module_name,
{
// lifetime scope of guard
{
std::lock_guard<std::mutex> guard(s_mtx);
std::lock_guard<std::mutex> guard(s_mmap_mtx);
auto& mmref = mmap();
auto i = mmref.find(module_name);
if (i != mmref.end())
......@@ -148,7 +146,7 @@ void group::add_module(group::module* ptr)
std::unique_ptr<group::module> mptr(ptr);
// lifetime scope of guard
{
std::lock_guard<std::mutex> guard(s_mtx);
std::lock_guard<std::mutex> guard(s_mmap_mtx);
if (mmap().insert(std::make_pair(mname, std::move(mptr))).second)
{
return; // success; don't throw exception
......@@ -172,6 +170,19 @@ group::unsubscriber::~unsubscriber()
if (m_group) m_group->unsubscribe(m_self);
}
group::module::module(const std::string& name) : m_name(name)
{
}
group::module::module(std::string&& name) : m_name(std::move(name))
{
}
const std::string& group::module::name()
{
return m_name;
}
bool group::unsubscriber::matches(const attachable::token& what)
{
if (what.subtype == typeid(group::unsubscriber))
......
......@@ -12,6 +12,7 @@
#include "cppa/attachable.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/actor_behavior.hpp"
#include "cppa/detail/actor_count.hpp"
#include "cppa/detail/mock_scheduler.hpp"
#include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/converted_thread_context.hpp"
......@@ -21,26 +22,6 @@ using std::endl;
namespace {
boost::mutex s_ra_mtx;
boost::condition_variable s_ra_cv;
std::atomic<int> s_running_actors(0);
typedef boost::unique_lock<boost::mutex> guard_type;
void inc_actor_count()
{
++s_running_actors;
}
void dec_actor_count()
{
if (--s_running_actors <= 1)
{
guard_type guard(s_ra_mtx);
s_ra_cv.notify_all();
}
}
void run_actor(cppa::intrusive_ptr<cppa::context> m_self,
cppa::actor_behavior* behavior)
{
......@@ -53,14 +34,14 @@ void run_actor(cppa::intrusive_ptr<cppa::context> m_self,
catch (...) { }
delete behavior;
}
dec_actor_count();
cppa::detail::dec_actor_count();
}
struct exit_observer : cppa::attachable
{
~exit_observer()
{
dec_actor_count();
cppa::detail::dec_actor_count();
}
};
......@@ -93,12 +74,7 @@ attachable* mock_scheduler::register_hidden_context()
void mock_scheduler::await_others_done()
{
auto expected = (unchecked_self() == nullptr) ? 0 : 1;
guard_type lock(s_ra_mtx);
while (s_running_actors.load() != expected)
{
s_ra_cv.wait(lock);
}
actor_count_wait_until((unchecked_self() == nullptr) ? 0 : 1);
}
} } // namespace detail
This diff is collapsed.
#include "cppa/detail/task_scheduler.hpp"
namespace cppa { namespace detail {
void task_scheduler::await_others_done()
{
}
void task_scheduler::register_converted_context(context*)
{
}
actor_ptr task_scheduler::spawn(actor_behavior*, scheduling_hint)
{
return nullptr;
}
attachable* task_scheduler::register_hidden_context()
{
return nullptr;
}
} } // namespace cppa::detail
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