Commit 767ab3f4 authored by neverlord's avatar neverlord

shared spinlock, some implementation work

parent 1d3cce57
......@@ -135,7 +135,7 @@
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{23902c37-f07e-47cd-bb19-c366b9f708db}</value>
<value type="QString">{07fcd197-092d-45a0-8500-3be614e6ae31}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
......
......@@ -143,3 +143,7 @@ src/binary_deserializer.cpp
src/actor.cpp
cppa/announce.hpp
src/abstract_type_list.cpp
src/message.cpp
cppa/util/shared_spinlock.hpp
src/shared_spinlock.cpp
cppa/util/shared_lock_guard.hpp
......@@ -22,6 +22,8 @@ class actor : public channel
public:
~actor();
virtual void join(group_ptr& what) = 0;
virtual void leave(const group_ptr& what) = 0;
virtual void link(intrusive_ptr<actor>& other) = 0;
......
......@@ -18,9 +18,9 @@ struct abstract_tuple : ref_counted
virtual std::size_t size() const = 0;
virtual abstract_tuple* copy() const = 0;
virtual const void* at(std::size_t pos) const = 0;
virtual const uniform_type_info* utype_at(std::size_t pos) const = 0;
virtual const util::abstract_type_list& types() const = 0;
virtual bool equal_to(const abstract_tuple& other) const = 0;
virtual const uniform_type_info* utype_at(std::size_t pos) const = 0;
};
......
......@@ -136,18 +136,6 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T>, T*>,
return compare(other.get());
}
/*
inline bool equal_to(const T* ptr) const
{
return get() == ptr;
}
inline bool equal_to(const intrusive_ptr& other) const
{
return get() == other.get();
}
*/
};
template<typename X, typename Y>
......
......@@ -14,54 +14,67 @@ namespace cppa {
class message
{
public:
struct content : ref_counted
{
const actor_ptr sender;
const channel_ptr receiver;
const untyped_tuple data;
content(const actor_ptr& s, const channel_ptr& r,
inline content(const actor_ptr& s,
const channel_ptr& r,
const untyped_tuple& ut)
: ref_counted(), sender(s), receiver(r), data(ut)
{
}
};
private:
intrusive_ptr<content> m_content;
public:
template<typename... Args>
message(const actor_ptr& from, const channel_ptr& to, const Args&... args)
: m_content(new content(from, to, tuple<Args...>(args...))) { }
: m_content(new content(from, to, tuple<Args...>(args...)))
{
}
message(const actor_ptr& from,
const channel_ptr& to,
const untyped_tuple& ut);
message(const actor_ptr& from, const channel_ptr& to, const untyped_tuple& ut)
: m_content(new content(from, to, ut)) { }
message();
// message(const actor_ptr& from, const channel_ptr& to, untyped_tuple&& ut)
// : m_content(new content(from, to, std::move(ut))) { }
message& operator=(const message&) = default;
message() : m_content(new content(0, 0, tuple<int>(0))) { }
message& operator=(message&&) = default;
const actor_ptr& sender() const
message(const message&) = default;
message(message&&) = default;
inline const actor_ptr& sender() const
{
return m_content->sender;
}
const channel_ptr& receiver() const
inline const channel_ptr& receiver() const
{
return m_content->receiver;
}
const untyped_tuple& data() const
inline const untyped_tuple& data() const
{
return m_content->data;
}
};
bool operator==(const message& lhs, const message& rhs);
inline bool operator!=(const message& lhs, const message& rhs)
{
return !(lhs == rhs);
}
} // namespace cppa
#endif // MESSAGE_HPP
......@@ -12,6 +12,7 @@
namespace cppa { namespace detail {
// irb_helper is not thread safe
struct irb_helper : ref_counted_impl<std::size_t>
{
virtual ~irb_helper() { }
......
......@@ -12,7 +12,7 @@ namespace cppa {
* @brief (Thread safe) base class for reference counted objects
* with an atomic reference count.
*/
typedef detail::ref_counted_impl<std::atomic<std::size_t>> ref_counted;
typedef detail::ref_counted_impl< std::atomic<std::size_t> > ref_counted;
} // namespace cppa
......
......@@ -9,6 +9,9 @@ namespace cppa {
class context;
class actor_behavior;
/**
* @brief
*/
class scheduler
{
......@@ -44,6 +47,10 @@ class scheduler
};
/**
* @brief Gets the actual used scheduler implementation.
* @return The active scheduler or @c nullptr.
*/
scheduler* get_scheduler();
} // namespace cppa::detail
......
......@@ -22,22 +22,39 @@
namespace cppa { namespace detail {
template<typename T>
struct is_char_array
/**
* @brief <tt>is_array_of<T,U>::value == true</tt> if and only
* if T is an array of U.
*/
template<typename T, typename U>
struct is_array_of
{
typedef typename std::remove_all_extents<T>::type step1_type;
typedef typename std::remove_cv<step1_type>::type step2_type;
static const bool value = std::is_array<T>::value
&& std::is_same<step2_type, char>::value;
&& std::is_same<step2_type, U>::value;
};
template<typename T>
struct chars_to_string
{
typedef typename util::replace_type<T, std::string,
std::is_same<T, const char*>,
std::is_same<T, char*>,
is_char_array<T>>::type
is_array_of<T, char>>::type
subtype1;
typedef typename util::replace_type<subtype1, std::u16string,
std::is_same<subtype1, const char16_t*>,
std::is_same<subtype1, char16_t*>,
is_array_of<subtype1, char16_t>>::type
subtype2;
typedef typename util::replace_type<subtype2, std::u32string,
std::is_same<subtype2, const char32_t*>,
std::is_same<subtype2, char32_t*>,
is_array_of<subtype2, char32_t>>::type
type;
};
......
......@@ -26,7 +26,9 @@ class untyped_tuple
std::size_t size() const { return m_vals->size(); }
const void* at(std::size_t p) const { return m_vals->at(p); }
void* mutable_at(size_t p) { return m_vals->mutable_at(p); }
const void* at(size_t p) const { return m_vals->at(p); }
const uniform_type_info* utype_at(std::size_t p) const { return m_vals->utype_at(p); }
......
......@@ -26,7 +26,7 @@ namespace cppa { namespace util {
template<typename What, typename With, typename... IfStmt>
struct replace_type
{
static const bool do_replace = disjunction<IfStmt...>::value;
static constexpr bool do_replace = disjunction<IfStmt...>::value;
typedef typename detail::replace_type<do_replace, What, With>::type
type;
};
......
#ifndef SHARED_LOCK_GUARD_HPP
#define SHARED_LOCK_GUARD_HPP
namespace cppa { namespace util {
template<typename SharedLockable>
class shared_lock_guard
{
SharedLockable& m_lockable;
public:
shared_lock_guard(SharedLockable& lockable) : m_lockable(lockable)
{
m_lockable.lock_shared();
}
~shared_lock_guard()
{
m_lockable.unlock_shared();
}
};
} } // namespace cppa::util
#endif // SHARED_LOCK_GUARD_HPP
#ifndef SHARED_SPINLOCK_HPP
#define SHARED_SPINLOCK_HPP
#include <atomic>
#include <cstddef>
namespace cppa { namespace util {
class shared_spinlock
{
std::atomic<long> m_flag;
public:
shared_spinlock();
void lock();
void unlock();
bool try_lock();
void lock_shared();
void unlock_shared();
bool try_lock_shared();
};
} } // namespace cppa::util
#endif // SHARED_SPINLOCK_HPP
......@@ -59,8 +59,13 @@ HEADERS = cppa/actor.hpp \
cppa/util/is_comparable.hpp \
cppa/util/is_copyable.hpp \
cppa/util/is_one_of.hpp \
cppa/util/is_primitive.hpp \
cppa/util/pt_token.hpp \
cppa/util/remove_const_reference.hpp \
cppa/util/replace_type.hpp \
cppa/util/reverse_type_list.hpp \
cppa/util/rm_ref.hpp \
cppa/util/shared_spinlock.hpp \
cppa/util/single_reader_queue.hpp \
cppa/util/type_at.hpp \
cppa/util/type_list.hpp \
......@@ -80,11 +85,13 @@ SOURCES = src/abstract_type_list.cpp \
src/demangle.cpp \
src/deserializer.cpp \
src/group.cpp \
src/message.cpp \
src/mock_scheduler.cpp \
src/object.cpp \
src/primitive_variant.cpp \
src/scheduler.cpp \
src/serializer.cpp \
src/shared_spinlock.cpp \
src/to_uniform_name.cpp \
src/uniform_type_info.cpp \
src/untyped_tuple.cpp
......
#include "cppa/config.hpp"
#include <map>
#include <mutex>
#include <atomic>
#include "cppa/actor.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
namespace {
std::atomic<std::uint32_t> s_ids(1);
std::map<std::uint32_t, cppa::actor*> s_instances;
cppa::util::shared_spinlock s_instances_mtx;
} // namespace <anonmyous>
namespace cppa {
actor::actor() : m_id(0)
actor::actor() : m_id(s_ids.fetch_add(1))
{
std::lock_guard<util::shared_spinlock> guard(s_instances_mtx);
s_instances.insert(std::make_pair(m_id, this));
}
actor::~actor()
{
std::lock_guard<util::shared_spinlock> guard(s_instances_mtx);
s_instances.erase(m_id);
}
intrusive_ptr<actor> actor::by_id(std::uint32_t)
intrusive_ptr<actor> actor::by_id(std::uint32_t actor_id)
{
util::shared_lock_guard<util::shared_spinlock> guard(s_instances_mtx);
auto i = s_instances.find(actor_id);
if (i != s_instances.end())
{
return i->second;
}
return nullptr;
}
......
#include "cppa/message.hpp"
namespace cppa {
message::message(const actor_ptr& from,
const channel_ptr& to,
const untyped_tuple& ut)
: m_content(new content(from, to, ut))
{
}
message::message() : m_content(new content(0, 0, tuple<int>(0)))
{
}
bool operator==(const message& lhs, const message& rhs)
{
return lhs.sender() == rhs.sender()
&& lhs.receiver() == rhs.receiver()
&& lhs.data().vals()->equal_to(*(rhs.data().vals()));
}
} // namespace cppa
#include "cppa/config.hpp"
#include <limits>
#include <thread>
#include "cppa/util/shared_spinlock.hpp"
namespace {
constexpr long min_long = std::numeric_limits<long>::min();
} // namespace <anonymous>
namespace cppa { namespace util {
shared_spinlock::shared_spinlock() : m_flag(0)
{
}
void shared_spinlock::lock()
{
long v = m_flag.load();
for (;;)
{
if (v != 0)
{
//std::this_thread::yield();
v = m_flag.load();
}
else if (m_flag.compare_exchange_weak(v, min_long))
{
return;
}
// else: next iteration
}
}
void shared_spinlock::unlock()
{
m_flag.store(0);
}
bool shared_spinlock::try_lock()
{
long v = m_flag.load();
return (v == 0) ? m_flag.compare_exchange_weak(v, min_long) : false;
}
void shared_spinlock::lock_shared()
{
long v = m_flag.load();
for (;;)
{
if (v < 0)
{
//std::this_thread::yield();
v = m_flag.load();
}
else if (m_flag.compare_exchange_weak(v, v + 1))
{
return;
}
// else: next iteration
}
}
void shared_spinlock::unlock_shared()
{
m_flag.fetch_sub(1);
}
bool shared_spinlock::try_lock_shared()
{
long v = m_flag.load();
return (v >= 0) ? m_flag.compare_exchange_weak(v, v + 1) : false;
}
} } // namespace cppa::util
......@@ -101,7 +101,8 @@ class actor_ptr_type_info_impl : public util::uniform_type_info_base<actor_ptr>
void serialize(const void* ptr, serializer* sink) const
{
sink->begin_object(name());
sink->write_value((*reinterpret_cast<const actor_ptr*>(ptr))->id());
auto id = (*reinterpret_cast<const actor_ptr*>(ptr))->id();
sink->write_value(id);
sink->end_object();
}
......
......@@ -23,6 +23,7 @@
#include "cppa/match.hpp"
#include "cppa/tuple.hpp"
#include "cppa/message.hpp"
#include "cppa/announce.hpp"
#include "cppa/serializer.hpp"
#include "cppa/ref_counted.hpp"
......@@ -37,10 +38,11 @@
#include "cppa/util/pt_token.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/if_else_type.hpp"
#include "cppa/util/wrapped_type.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/uniform_type_info_base.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/ptype_to_type.hpp"
......@@ -370,21 +372,54 @@ class string_deserializer : public deserializer
};
class message_uti : public util::uniform_type_info_base<message>
{
public:
virtual void serialize(const void* instance, serializer* sink) const
{
const message& msg = *reinterpret_cast<const message*>(instance);
const untyped_tuple& data = msg.data();
sink->begin_object("cppa::message");
sink->begin_sequence(data.size());
for (size_t i = 0; i < data.size(); ++i)
{
const uniform_type_info* ut = data.utype_at(i);
ut->serialize(data.at(i), sink);
}
sink->end_sequence();
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const
{
}
};
template<typename T>
std::string to_string(const T& what)
{
std::string tname = detail::to_uniform_name(typeid(T));
auto mobj = uniform_typeid<T>();
if (!mobj) throw std::logic_error(tname + " not found");
auto utype = uniform_typeid<T>();
if (!utype)
{
throw std::logic_error( detail::to_uniform_name(typeid(T))
+ " not found");
}
std::ostringstream osstr;
string_serializer strs(osstr);
mobj->serialize(&what, &strs);
utype->serialize(&what, &strs);
return osstr.str();
}
std::size_t test__serialization()
{
CPPA_TEST(test__serialization);
announce(typeid(message), new message_uti);
//message msg(0, 0, 42, std::string("Hello World"), 23.32);
//cout << to_string(msg) << endl;
CPPA_CHECK_EQUAL((is_iterable<int>::value), false);
// std::string is primitive and thus not identified by is_iterable
......
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