Commit 82939f63 authored by neverlord's avatar neverlord

unicast network

parent 178334ac
...@@ -162,5 +162,14 @@ src/process_information.cpp ...@@ -162,5 +162,14 @@ src/process_information.cpp
cppa/util/ripemd_160.hpp cppa/util/ripemd_160.hpp
src/ripemd_160.cpp src/ripemd_160.cpp
src/unicast_network.cpp src/unicast_network.cpp
cppa/actor_exited.hpp unit_testing/test__remote_actor.cpp
src/actor_exited.cpp unit_testing/ping_pong.hpp
unit_testing/ping_pong.cpp
cppa/exception.hpp
src/exception.cpp
cppa/actor_proxy.hpp
src/actor_proxy.cpp
cppa/detail/actor_proxy_cache.hpp
src/actor_proxy_cache.cpp
src/attachable.cpp
cppa/attachable.hpp
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
#include "cppa/group.hpp" #include "cppa/group.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/attachable.hpp"
#include "cppa/process_information.hpp" #include "cppa/process_information.hpp"
namespace cppa { namespace cppa {
class serializer; class serializer;
class actor_proxy;
class deserializer; class deserializer;
/** /**
...@@ -18,8 +20,13 @@ class deserializer; ...@@ -18,8 +20,13 @@ class deserializer;
class actor : public channel class actor : public channel
{ {
friend class actor_proxy;
bool m_is_proxy;
std::uint32_t m_id; std::uint32_t m_id;
actor(std::uint32_t aid);
protected: protected:
actor(); actor();
...@@ -28,6 +35,18 @@ class actor : public channel ...@@ -28,6 +35,18 @@ class actor : public channel
~actor(); ~actor();
/**
* @brief Attaches @p ptr to this actor.
*
* @p ptr will be deleted if actor finished execution of immediately
* if the actor already exited.
*
* @return @c true if @p ptr was successfully attached to the actor;
* otherwise (actor already exited) @p false.
*
*/
virtual bool attach(attachable* ptr) = 0;
/** /**
* @brief * @brief
*/ */
...@@ -41,12 +60,12 @@ class actor : public channel ...@@ -41,12 +60,12 @@ class actor : public channel
/** /**
* @brief * @brief
*/ */
virtual void link(intrusive_ptr<actor>& other) = 0; virtual void link_to(intrusive_ptr<actor>& other) = 0;
/** /**
* @brief * @brief
*/ */
virtual void unlink(intrusive_ptr<actor>& other) = 0; virtual void unlink_from(intrusive_ptr<actor>& other) = 0;
/** /**
* @brief * @brief
......
#ifndef ACTOR_EXITED_HPP
#define ACTOR_EXITED_HPP
#include <string>
#include <cstdint>
#include <exception>
namespace cppa {
class actor_exited : public std::exception
{
std::uint32_t m_reason;
std::string m_what;
public:
~actor_exited() throw();
actor_exited(std::uint32_t exit_reason);
std::uint32_t reason() const;
virtual const char* what() const throw();
};
} // namespace cppa
#endif // ACTOR_EXITED_HPP
#ifndef ACTOR_PROXY_HPP
#define ACTOR_PROXY_HPP
#include "cppa/actor.hpp"
namespace cppa {
class actor_proxy : public actor
{
process_information_ptr m_parent;
public:
actor_proxy(std::uint32_t mid, process_information_ptr&& parent);
actor_proxy(std::uint32_t mid, const process_information_ptr& parent);
bool attach(attachable* ptr);
void enqueue(const message& msg);
void join(group_ptr& what);
void leave(const group_ptr& what);
void link_to(intrusive_ptr<actor>& other);
void unlink_from(intrusive_ptr<actor>& other);
bool remove_backlink(const intrusive_ptr<actor>& to);
bool establish_backlink(const intrusive_ptr<actor>& to);
const process_information& parent_process() const;
process_information_ptr parent_process_ptr() const;
};
typedef intrusive_ptr<actor_proxy> actor_proxy_ptr;
} // namespace cppa
#endif // ACTOR_PROXY_HPP
#ifndef ATTACHABLE_HPP
#define ATTACHABLE_HPP
#include <cstdint>
namespace cppa {
// utilty class;
// provides a virtual destructor that's executed after an actor
// finished execution
/**
* @brief Callback utility class.
*/
class attachable
{
protected:
attachable() = default;
public:
virtual ~attachable();
/**
* @brief Executed if the actor finished execution
* with given @p reason.
*
* The default implementation does nothing.
*/
virtual void detach(std::uint32_t reason);
};
} // namespace cppa
#endif // ATTACHABLE_HPP
...@@ -25,11 +25,6 @@ class context : public actor ...@@ -25,11 +25,6 @@ class context : public actor
*/ */
virtual void quit(std::uint32_t reason) = 0; virtual void quit(std::uint32_t reason) = 0;
inline void quit(exit_reason reason)
{
quit(static_cast<std::uint32_t>(reason));
}
/** /**
* @brief * @brief
*/ */
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "cppa/on.hpp"
#include "cppa/tuple.hpp" #include "cppa/tuple.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/invoke.hpp" #include "cppa/invoke.hpp"
...@@ -58,7 +59,7 @@ namespace cppa { ...@@ -58,7 +59,7 @@ namespace cppa {
*/ */
inline void link(actor_ptr& other) inline void link(actor_ptr& other)
{ {
self()->link(other); self()->link_to(other);
} }
/** /**
...@@ -66,7 +67,7 @@ inline void link(actor_ptr& other) ...@@ -66,7 +67,7 @@ inline void link(actor_ptr& other)
*/ */
inline void link(actor_ptr&& other) inline void link(actor_ptr&& other)
{ {
self()->link(other); self()->link_to(other);
} }
inline void trap_exit(bool new_value) inline void trap_exit(bool new_value)
...@@ -103,14 +104,6 @@ inline void quit(std::uint32_t reason) ...@@ -103,14 +104,6 @@ inline void quit(std::uint32_t reason)
self()->quit(reason); self()->quit(reason);
} }
/**
* @brief Quits execution of the calling actor.
*/
inline void quit(exit_reason reason)
{
self()->quit(reason);
}
/** /**
* @brief Dequeues the next message from the mailbox. * @brief Dequeues the next message from the mailbox.
*/ */
...@@ -220,7 +213,9 @@ inline void await_all_others_done() ...@@ -220,7 +213,9 @@ inline void await_all_others_done()
/** /**
* @brief Publishes @p whom at given @p port. * @brief Publishes @p whom at given @p port.
*/ */
void publish(const actor_ptr& whom, std::uint16_t port); void publish(actor_ptr& whom, std::uint16_t port);
void publish(actor_ptr&& whom, std::uint16_t port);
/** /**
* @brief Establish a new connection to the actor at @p host on given @p port. * @brief Establish a new connection to the actor at @p host on given @p port.
......
#ifndef ACTOR_PROXY_CACHE_HPP
#define ACTOR_PROXY_CACHE_HPP
#include <string>
#include "cppa/actor_proxy.hpp"
#include "cppa/process_information.hpp"
namespace cppa { namespace detail {
class actor_proxy_cache
{
public:
typedef std::tuple<std::uint32_t, std::uint32_t,
process_information::node_id_type> key_tuple;
private:
std::map<key_tuple, process_information_ptr> m_pinfos;
std::map<key_tuple, actor_proxy_ptr> m_proxies;
process_information_ptr get_pinfo(const key_tuple& key);
public:
actor_proxy_ptr get(const key_tuple& key);
void add(const actor_proxy_ptr& pptr);
};
// get the thread-local cache object
actor_proxy_cache& get_actor_proxy_cache();
} } // namespace cppa::detail
#endif // ACTOR_PROXY_CACHE_HPP
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <map> #include <map>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <vector>
#include <memory>
#include "cppa/context.hpp" #include "cppa/context.hpp"
#include "cppa/detail/blocking_message_queue.hpp" #include "cppa/detail/blocking_message_queue.hpp"
...@@ -16,7 +18,7 @@ class converted_thread_context : public context ...@@ -16,7 +18,7 @@ class converted_thread_context : public context
{ {
// true if the associated thread has finished execution // true if the associated thread has finished execution
bool m_exited; std::uint32_t m_exit_reason;
// mailbox implementation // mailbox implementation
detail::blocking_message_queue m_mailbox; detail::blocking_message_queue m_mailbox;
...@@ -30,21 +32,34 @@ class converted_thread_context : public context ...@@ -30,21 +32,34 @@ class converted_thread_context : public context
// manages actor links // manages actor links
std::list<actor_ptr> m_links; std::list<actor_ptr> m_links;
std::vector<std::unique_ptr<attachable>> m_attachables;
// @pre m_mtx is locked
inline bool exited() const
{
return m_exit_reason != exit_reason::not_exited;
}
public: public:
converted_thread_context(); converted_thread_context();
message_queue& mailbox /*[[override]]*/ (); message_queue& mailbox /*[[override]]*/ ();
// called if the converted thread finished execution
void cleanup(std::uint32_t reason = exit_reason::normal);
bool attach /*[[override]]*/ (attachable* ptr);
void join /*[[override]]*/ (group_ptr& what); void join /*[[override]]*/ (group_ptr& what);
void quit /*[[override]]*/ (std::uint32_t reason); void quit /*[[override]]*/ (std::uint32_t reason);
void leave /*[[override]]*/ (const group_ptr& what); void leave /*[[override]]*/ (const group_ptr& what);
void link /*[[override]]*/ (intrusive_ptr<actor>& other); void link_to /*[[override]]*/ (intrusive_ptr<actor>& other);
void unlink /*[[override]]*/ (intrusive_ptr<actor>& other); void unlink_from /*[[override]]*/ (intrusive_ptr<actor>& other);
bool remove_backlink /*[[override]]*/ (const intrusive_ptr<actor>& to); bool remove_backlink /*[[override]]*/ (const intrusive_ptr<actor>& to);
......
#ifndef EXCEPTION_HPP
#define EXCEPTION_HPP
#include <string>
#include <cstdint>
#include <exception>
namespace cppa {
class exception : public std::exception
{
std::string m_what;
protected:
exception(std::string&& what_str);
exception(const std::string& what_str);
public:
~exception() throw();
const char* what() const throw();
};
class actor_exited : public exception
{
std::uint32_t m_reason;
public:
actor_exited(std::uint32_t exit_reason);
std::uint32_t reason() const throw();
};
class network_exception : public exception
{
public:
network_exception(std::string&& what_str);
network_exception(const std::string& what_str);
};
class bind_failure : public network_exception
{
int m_errno;
public:
bind_failure(int bind_errno);
int error_code() const throw();
};
} // namespace cppa
#endif // EXCEPTION_HPP
...@@ -5,45 +5,39 @@ ...@@ -5,45 +5,39 @@
namespace cppa { namespace cppa {
enum class exit_reason : std::uint32_t namespace exit_reason
{ {
/**
* @brief Indicates that the actor is still alive.
*/
static constexpr std::uint32_t not_exited = 0x00000;
/** /**
* @brief Indicates that an actor finished execution. * @brief Indicates that an actor finished execution.
*/ */
normal = 0x00000, static constexpr std::uint32_t normal = 0x00001;
/** /**
* @brief Indicates that an actor finished execution * @brief Indicates that an actor finished execution
* because of an unhandled exception. * because of an unhandled exception.
*/ */
unhandled_exception = 0x00001, static constexpr std::uint32_t unhandled_exception = 0x00002;
/** /**
* @brief Indicates that an actor finishied execution * @brief Indicates that an actor finishied execution
* because a connection to a remote link was * because a connection to a remote link was
* closed unexpectedly. * closed unexpectedly.
*/ */
remote_link_unreachable = 0x00101, static constexpr std::uint32_t remote_link_unreachable = 0x00101;
/** /**
* @brief Any user defined exit reason should have a * @brief Any user defined exit reason should have a
* value greater or equal to prevent collisions * value greater or equal to prevent collisions
* with default defined exit reasons. * with default defined exit reasons.
*/ */
user_defined = 0x10000 static constexpr std::uint32_t user_defined = 0x10000;
};
static constexpr std::uint32_t user_defined_exit_reason
= static_cast<std::uint32_t>(exit_reason::user_defined);
/**
* @brief Converts {@link exit_reason} to @c std::uint32_t.
*/
constexpr std::uint32_t to_uint(exit_reason r)
{
return static_cast<std::uint32_t>(r);
} }
class exit_signal class exit_signal
...@@ -59,13 +53,6 @@ class exit_signal ...@@ -59,13 +53,6 @@ class exit_signal
*/ */
exit_signal(); exit_signal();
/**
* @brief Creates an exit signal with
* <tt>reason() == @p r</tt>.
* @pre {@code r != exit_reason::user_defined}.
*/
exit_signal(exit_reason r);
/** /**
* @brief Creates an exit signal with * @brief Creates an exit signal with
* <tt>reason() == @p r</tt>. * <tt>reason() == @p r</tt>.
...@@ -81,19 +68,11 @@ class exit_signal ...@@ -81,19 +68,11 @@ class exit_signal
return m_reason; return m_reason;
} }
// an unambiguous member function
void set_uint_reason(std::uint32_t value);
/** /**
* @brief Sets the exit reason to @p value. * @brief Sets the exit reason to @p value.
*/ */
void set_reason(std::uint32_t value); void set_reason(std::uint32_t value);
/**
* @brief Sets the exit reason to @p value.
*/
void set_reason(exit_reason value);
}; };
inline bool operator==(const exit_signal& lhs, const exit_signal& rhs) inline bool operator==(const exit_signal& lhs, const exit_signal& rhs)
......
#ifndef PROCESS_INFORMATION_HPP #ifndef PROCESS_INFORMATION_HPP
#define PROCESS_INFORMATION_HPP #define PROCESS_INFORMATION_HPP
#include <array>
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/util/comparable.hpp" #include "cppa/util/comparable.hpp"
namespace cppa { namespace cppa {
...@@ -20,8 +22,12 @@ class process_information : public ref_counted, ...@@ -20,8 +22,12 @@ class process_information : public ref_counted,
static constexpr size_t node_id_size = 20; static constexpr size_t node_id_size = 20;
typedef std::array<std::uint8_t, node_id_size> node_id_type;
process_information(); process_information();
process_information(std::uint32_t process_id, const node_id_type& node_id);
process_information(const process_information& other); process_information(const process_information& other);
process_information& operator=(const process_information& other); process_information& operator=(const process_information& other);
...@@ -37,7 +43,8 @@ class process_information : public ref_counted, ...@@ -37,7 +43,8 @@ class process_information : public ref_counted,
* A hash build from the MAC address of the first network device * A hash build from the MAC address of the first network device
* and the serial number from the root HD (mounted in "/" or "C:"). * and the serial number from the root HD (mounted in "/" or "C:").
*/ */
std::uint8_t node_id[node_id_size]; node_id_type node_id;
//std::uint8_t node_id[node_id_size];
/** /**
* @brief Converts {@link node_id} to an hexadecimal string. * @brief Converts {@link node_id} to an hexadecimal string.
...@@ -50,11 +57,15 @@ class process_information : public ref_counted, ...@@ -50,11 +57,15 @@ class process_information : public ref_counted,
*/ */
static const process_information& get(); static const process_information& get();
static void node_id_from_string(const std::string& str, node_id_type& storage);
// "inherited" from comparable<process_information> // "inherited" from comparable<process_information>
int compare(const process_information& other) const; int compare(const process_information& other) const;
}; };
typedef intrusive_ptr<process_information> process_information_ptr;
} // namespace cppa } // namespace cppa
#endif // PROCESS_INFORMATION_HPP #endif // PROCESS_INFORMATION_HPP
...@@ -71,6 +71,9 @@ class single_reader_queue ...@@ -71,6 +71,9 @@ class single_reader_queue
} }
} }
/**
* @reentrant
*/
void push_back(element_type* new_element) void push_back(element_type* new_element)
{ {
element_type* e = m_tail.load(); element_type* e = m_tail.load();
......
...@@ -18,7 +18,11 @@ cppa::util::shared_spinlock s_instances_mtx; ...@@ -18,7 +18,11 @@ cppa::util::shared_spinlock s_instances_mtx;
namespace cppa { namespace cppa {
actor::actor() : m_id(s_ids.fetch_add(1)) actor::actor(std::uint32_t aid) : m_is_proxy(true), m_id(aid)
{
}
actor::actor() : m_is_proxy(false), m_id(s_ids.fetch_add(1))
{ {
std::lock_guard<util::shared_spinlock> guard(s_instances_mtx); std::lock_guard<util::shared_spinlock> guard(s_instances_mtx);
s_instances.insert(std::make_pair(m_id, this)); s_instances.insert(std::make_pair(m_id, this));
...@@ -26,8 +30,11 @@ actor::actor() : m_id(s_ids.fetch_add(1)) ...@@ -26,8 +30,11 @@ actor::actor() : m_id(s_ids.fetch_add(1))
actor::~actor() actor::~actor()
{ {
std::lock_guard<util::shared_spinlock> guard(s_instances_mtx); if (!m_is_proxy)
s_instances.erase(m_id); {
std::lock_guard<util::shared_spinlock> guard(s_instances_mtx);
s_instances.erase(m_id);
}
} }
intrusive_ptr<actor> actor::by_id(std::uint32_t actor_id) intrusive_ptr<actor> actor::by_id(std::uint32_t actor_id)
......
#include <sstream>
#include "cppa/actor_exited.hpp"
namespace cppa {
actor_exited::~actor_exited() throw()
{
}
actor_exited::actor_exited(std::uint32_t exit_reason) : m_reason(exit_reason)
{
std::ostringstream oss;
oss << "actor exited with reason " << exit_reason;
m_what = oss.str();
}
std::uint32_t actor_exited::reason() const
{
return m_reason;
}
const char* actor_exited::what() const throw()
{
return m_what.c_str();
}
} // namespace cppa
#include "cppa/actor_proxy.hpp"
namespace cppa {
actor_proxy::actor_proxy(std::uint32_t mid, const process_information_ptr& pptr)
: actor(mid), m_parent(pptr)
{
if (!m_parent) throw std::runtime_error("parent == nullptr");
}
actor_proxy::actor_proxy(std::uint32_t mid, process_information_ptr&& pptr)
: actor(mid), m_parent(std::move(pptr))
{
if (!m_parent) throw std::runtime_error("parent == nullptr");
}
//implemented in unicast_network.cpp
//void actor_proxy::enqueue(const message& msg)
//{
//}
bool actor_proxy::attach(attachable* ptr)
{
delete ptr;
return false;
}
void actor_proxy::join(group_ptr& what)
{
}
void actor_proxy::leave(const group_ptr& what)
{
}
void actor_proxy::link_to(intrusive_ptr<actor>& other)
{
}
void actor_proxy::unlink_from(intrusive_ptr<actor>& other)
{
}
bool actor_proxy::remove_backlink(const intrusive_ptr<actor>& to)
{
return true;
}
bool actor_proxy::establish_backlink(const intrusive_ptr<actor>& to)
{
return true;
}
const process_information& actor_proxy::parent_process() const
{
return *m_parent;
}
process_information_ptr actor_proxy::parent_process_ptr() const
{
return m_parent;
}
} // namespace cppa
#include <boost/thread.hpp>
#include "cppa/detail/actor_proxy_cache.hpp"
namespace {
boost::thread_specific_ptr<cppa::detail::actor_proxy_cache> t_proxy_cache;
} // namespace <anonymous>
namespace cppa { namespace detail {
process_information_ptr
actor_proxy_cache::get_pinfo(const actor_proxy_cache::key_tuple& key)
{
auto i = m_pinfos.find(key);
if (i != m_pinfos.end())
{
return i->second;
}
process_information_ptr tmp(new process_information(std::get<1>(key),
std::get<2>(key)));
m_pinfos.insert(std::make_pair(key, tmp));
return tmp;
}
actor_proxy_ptr actor_proxy_cache::get(const key_tuple& key)
{
auto i = m_proxies.find(key);
if (i != m_proxies.end())
{
return i->second;
}
return new actor_proxy(std::get<0>(key), get_pinfo(key));
}
void actor_proxy_cache::add(const actor_proxy_ptr& pptr)
{
auto pinfo = pptr->parent_process_ptr();
key_tuple key(pptr->id(), pinfo->process_id, pinfo->node_id);
m_pinfos.insert(std::make_pair(key, pinfo));
m_proxies.insert(std::make_pair(key, pptr));
}
actor_proxy_cache& get_actor_proxy_cache()
{
if (t_proxy_cache.get() == nullptr)
{
t_proxy_cache.reset(new actor_proxy_cache);
}
return *t_proxy_cache.get();
}
} } // namespace cppa::detail
#include "cppa/attachable.hpp"
namespace cppa {
attachable::~attachable()
{
}
void attachable::detach(std::uint32_t)
{
}
} // namespace cppa::detail
...@@ -6,13 +6,20 @@ ...@@ -6,13 +6,20 @@
#include "cppa/detail/converted_thread_context.hpp" #include "cppa/detail/converted_thread_context.hpp"
using cppa::detail::converted_thread_context;
namespace { namespace {
void cleanup_fun(cppa::context* what) void cleanup_fun(cppa::context* what)
{ {
if (what && !what->deref()) if (what)
{ {
delete what; auto converted = dynamic_cast<converted_thread_context*>(what);
if (converted)
{
converted->cleanup();
}
if (!what->deref()) delete what;
} }
} }
...@@ -42,7 +49,7 @@ context* self() ...@@ -42,7 +49,7 @@ context* self()
context* result = m_this_context.get(); context* result = m_this_context.get();
if (!result) if (!result)
{ {
result = new detail::converted_thread_context; result = new converted_thread_context;
result->ref(); result->ref();
get_scheduler()->register_converted_context(result); get_scheduler()->register_converted_context(result);
m_this_context.reset(result); m_this_context.reset(result);
......
#include <memory>
#include <algorithm> #include <algorithm>
#include "cppa/exception.hpp"
#include "cppa/exit_signal.hpp" #include "cppa/exit_signal.hpp"
#include "cppa/actor_exited.hpp"
#include "cppa/detail/converted_thread_context.hpp" #include "cppa/detail/converted_thread_context.hpp"
namespace { namespace {
...@@ -40,38 +41,77 @@ int erase_all(List& lst, const Element& e) ...@@ -40,38 +41,77 @@ int erase_all(List& lst, const Element& e)
namespace cppa { namespace detail { namespace cppa { namespace detail {
converted_thread_context::converted_thread_context() : m_exited(false) converted_thread_context::converted_thread_context()
: m_exit_reason(exit_reason::not_exited)
{ {
} }
void converted_thread_context::quit(std::uint32_t reason) bool converted_thread_context::attach(attachable* ptr)
{ {
std::unique_ptr<attachable> uptr(ptr);
if (!ptr)
{
std::lock_guard<std::mutex> guard(m_mtx);
return m_exit_reason == exit_reason::not_exited;
}
else
{
std::uint32_t reason;
// lifetime scope of guard
{
std::lock_guard<std::mutex> guard(m_mtx);
reason = m_exit_reason;
if (reason == exit_reason::not_exited)
{
m_attachables.push_back(std::move(uptr));
return true;
}
}
uptr->detach(reason);
return false;
}
}
void converted_thread_context::cleanup(std::uint32_t reason)
{
if (reason == exit_reason::not_exited) return;
decltype(m_links) mlinks; decltype(m_links) mlinks;
decltype(m_subscriptions) msubscriptions; decltype(m_subscriptions) msubscriptions;
decltype(m_attachables) mattachables;
// lifetime scope of guard // lifetime scope of guard
{ {
std::lock_guard<std::mutex> guard(m_mtx); std::lock_guard<std::mutex> guard(m_mtx);
m_exited = true; m_exit_reason = reason;
mlinks = std::move(m_links); mlinks = std::move(m_links);
msubscriptions = std::move(m_subscriptions); msubscriptions = std::move(m_subscriptions);
// make sure m_links and m_subscriptions definitely are empty mattachables = std::move(m_attachables);
// make sure lists are definitely empty
m_links.clear(); m_links.clear();
m_subscriptions.clear(); m_subscriptions.clear();
m_attachables.clear();
} }
actor_ptr mself = self(); actor_ptr mself = self();
// send exit messages // send exit messages
for (actor_ptr& aptr : mlinks) for (actor_ptr& aptr : mlinks)
{ {
aptr->enqueue(message(mself, aptr, exit_signal(reason))); aptr->enqueue(message(mself, aptr, exit_signal(reason)));
} }
for (std::unique_ptr<attachable>& ptr : mattachables)
{
ptr->detach(reason);
}
}
void converted_thread_context::quit(std::uint32_t reason)
{
cleanup(reason);
throw actor_exited(reason); throw actor_exited(reason);
} }
void converted_thread_context::link(intrusive_ptr<actor>& other) void converted_thread_context::link_to(intrusive_ptr<actor>& other)
{ {
std::lock_guard<std::mutex> guard(m_mtx); std::lock_guard<std::mutex> guard(m_mtx);
if (other && !m_exited && other->establish_backlink(this)) if (other && !exited() && other->establish_backlink(this))
{ {
m_links.push_back(other); m_links.push_back(other);
//m_links.insert(other); //m_links.insert(other);
...@@ -97,7 +137,7 @@ bool converted_thread_context::establish_backlink(const intrusive_ptr<actor>& ot ...@@ -97,7 +137,7 @@ bool converted_thread_context::establish_backlink(const intrusive_ptr<actor>& ot
// lifetime scope of guard // lifetime scope of guard
{ {
std::lock_guard<std::mutex> guard(m_mtx); std::lock_guard<std::mutex> guard(m_mtx);
if (!m_exited) if (!exited())
{ {
result = unique_insert(m_links, other); result = unique_insert(m_links, other);
//result = m_links.insert(other).second; //result = m_links.insert(other).second;
...@@ -115,10 +155,10 @@ bool converted_thread_context::establish_backlink(const intrusive_ptr<actor>& ot ...@@ -115,10 +155,10 @@ bool converted_thread_context::establish_backlink(const intrusive_ptr<actor>& ot
return result; return result;
} }
void converted_thread_context::unlink(intrusive_ptr<actor>& other) void converted_thread_context::unlink_from(intrusive_ptr<actor>& other)
{ {
std::lock_guard<std::mutex> guard(m_mtx); std::lock_guard<std::mutex> guard(m_mtx);
if (other && !m_exited && other->remove_backlink(this)) if (other && !exited() && other->remove_backlink(this))
{ {
erase_all(m_links, other); erase_all(m_links, other);
//m_links.erase(other); //m_links.erase(other);
...@@ -128,7 +168,7 @@ void converted_thread_context::unlink(intrusive_ptr<actor>& other) ...@@ -128,7 +168,7 @@ void converted_thread_context::unlink(intrusive_ptr<actor>& other)
void converted_thread_context::join(group_ptr& what) void converted_thread_context::join(group_ptr& what)
{ {
std::lock_guard<std::mutex> guard(m_mtx); std::lock_guard<std::mutex> guard(m_mtx);
if (!m_exited && m_subscriptions.count(what) == 0) if (!exited() && m_subscriptions.count(what) == 0)
{ {
auto s = what->subscribe(this); auto s = what->subscribe(this);
// insert only valid subscriptions // insert only valid subscriptions
......
#include <sstream>
#include "cppa/exception.hpp"
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
namespace cppa {
exception::exception(const std::string &what_str) : m_what(what_str)
{
}
exception::exception(std::string&& what_str) : m_what(std::move(what_str))
{
}
exception::~exception() throw()
{
}
const char* exception::what() const throw()
{
return m_what.c_str();
}
namespace // <anonymous>
{
std::string ae_what(std::uint32_t reason)
{
std::ostringstream oss;
oss << "actor exited with reason " << reason;
return oss.str();
}
} // namespace <anonymous>
actor_exited::actor_exited(std::uint32_t reason) : exception(ae_what(reason))
{
m_reason = reason;
}
std::uint32_t actor_exited::reason() const throw()
{
return m_reason;
}
network_exception::network_exception(const std::string& str) : exception(str)
{
}
network_exception::network_exception(std::string&& str)
: exception(std::move(str))
{
}
namespace // <anonymous>
{
std::string be_what(int err_code)
{
switch (err_code)
{
case EACCES: return "EACCES: address is protected; root access needed";
case EADDRINUSE: return "EADDRINUSE: address is already in use";
case EBADF: return "EBADF: no valid socket descriptor";
case EINVAL: return "EINVAL: socket already bound to an address";
case ENOTSOCK: return "ENOTSOCK: file descriptor given";
default: break;
}
std::stringstream oss;
oss << "an unknown error occurred (code: " << err_code << ")";
return oss.str();
}
} // namespace <anonymous>
bind_failure::bind_failure(int err_code) : network_exception(be_what(err_code))
{
m_errno = err_code;
}
int bind_failure::error_code() const throw()
{
return m_errno;
}
} // namespace cppa
...@@ -2,11 +2,7 @@ ...@@ -2,11 +2,7 @@
namespace cppa { namespace cppa {
exit_signal::exit_signal() : m_reason(to_uint(exit_reason::normal)) exit_signal::exit_signal() : m_reason(exit_reason::normal)
{
}
exit_signal::exit_signal(exit_reason r) : m_reason(to_uint(r))
{ {
} }
...@@ -19,14 +15,4 @@ void exit_signal::set_reason(std::uint32_t value) ...@@ -19,14 +15,4 @@ void exit_signal::set_reason(std::uint32_t value)
m_reason = value; m_reason = value;
} }
void exit_signal::set_reason(exit_reason value)
{
m_reason = to_uint(value);
}
void exit_signal::set_uint_reason(std::uint32_t value)
{
set_reason(value);
}
} // namespace cppa } // namespace cppa
...@@ -48,8 +48,8 @@ cppa::process_information compute_proc_info() ...@@ -48,8 +48,8 @@ cppa::process_information compute_proc_info()
} }
pclose(cmd); pclose(cmd);
erase_trailing_newline(first_mac_addr); erase_trailing_newline(first_mac_addr);
auto tmp = cppa::util::ripemd_160(first_mac_addr + hd_serial); result.node_id = cppa::util::ripemd_160(first_mac_addr + hd_serial);
memcpy(result.node_id, tmp.data(), cppa::process_information::node_id_size); //memcpy(result.node_id, tmp.data(), cppa::process_information::node_id_size);
return result; return result;
} }
...@@ -59,13 +59,18 @@ namespace cppa { ...@@ -59,13 +59,18 @@ namespace cppa {
process_information::process_information() : process_id(0) process_information::process_information() : process_id(0)
{ {
memset(node_id, 0, node_id_size); memset(node_id.data(), 0, node_id_size);
} }
process_information::process_information(const process_information& other) process_information::process_information(const process_information& other)
: ref_counted(), process_id(other.process_id) : ref_counted(), process_id(other.process_id), node_id(other.node_id)
{
//memcpy(node_id, other.node_id, node_id_size);
}
process_information::process_information(std::uint32_t a, const node_id_type& b)
: ref_counted(), process_id(a), node_id(b)
{ {
memcpy(node_id, other.node_id, node_id_size);
} }
process_information& process_information&
...@@ -75,7 +80,8 @@ process_information::operator=(const process_information& other) ...@@ -75,7 +80,8 @@ process_information::operator=(const process_information& other)
if (this != &other) if (this != &other)
{ {
process_id = other.process_id; process_id = other.process_id;
memcpy(node_id, other.node_id, node_id_size); node_id = other.node_id;
//memcpy(node_id, other.node_id, node_id_size);
} }
return *this; return *this;
} }
...@@ -102,8 +108,8 @@ const process_information& process_information::get() ...@@ -102,8 +108,8 @@ const process_information& process_information::get()
int process_information::compare(const process_information& other) const int process_information::compare(const process_information& other) const
{ {
int tmp = strncmp(reinterpret_cast<const char*>(node_id), int tmp = strncmp(reinterpret_cast<const char*>(node_id.data()),
reinterpret_cast<const char*>(other.node_id), reinterpret_cast<const char*>(other.node_id.data()),
node_id_size); node_id_size);
if (tmp == 0) if (tmp == 0)
{ {
...@@ -114,4 +120,51 @@ int process_information::compare(const process_information& other) const ...@@ -114,4 +120,51 @@ int process_information::compare(const process_information& other) const
return tmp; return tmp;
} }
void process_information::node_id_from_string(const std::string& str,
process_information::node_id_type& arr)
{
if (str.size() != (arr.size() * 2))
{
throw std::logic_error("str is not a node id hash");
}
auto j = str.begin();
for (size_t i = 0; i < arr.size(); ++i)
{
auto& val = arr[i];
val = 0;
for (int tmp = 0; tmp < 2; ++tmp)
{
char c = *j;
++j;
if (isdigit(c))
{
val |= static_cast<std::uint8_t>(c - '0');
}
else if (isalpha(c))
{
if (c >= 'a' && c <= 'f')
{
val |= static_cast<std::uint8_t>((c - 'a') + 10);
}
else if (c >= 'A' && c <= 'F')
{
val |= static_cast<std::uint8_t>((c - 'A') + 10);
}
else
{
throw std::logic_error(std::string("illegal character: ") + c);
}
}
else
{
throw std::logic_error(std::string("illegal character: ") + c);
}
if (tmp == 0)
{
val <<= 4;
}
}
}
}
} // namespace cppa } // namespace cppa
This diff is collapsed.
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <limits> #include <limits>
#include <cstdint> #include <cstdint>
#include <sstream> #include <sstream>
#include <iostream>
#include <type_traits> #include <type_traits>
#include "cppa/config.hpp" #include "cppa/config.hpp"
...@@ -25,8 +26,11 @@ ...@@ -25,8 +26,11 @@
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
#include "cppa/detail/object_array.hpp" #include "cppa/detail/object_array.hpp"
#include "cppa/detail/to_uniform_name.hpp" #include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/actor_proxy_cache.hpp"
#include "cppa/detail/default_uniform_type_info_impl.hpp" #include "cppa/detail/default_uniform_type_info_impl.hpp"
using std::cout;
using std::endl;
using cppa::util::void_type; using cppa::util::void_type;
namespace std { namespace std {
...@@ -126,8 +130,12 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> ...@@ -126,8 +130,12 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr>
} }
else else
{ {
primitive_variant ptup[3];
ptup[0] = ptr->id();
ptup[1] = ptr->parent_process().process_id;
ptup[2] = ptr->parent_process().node_id_as_string();
sink->begin_object(name); sink->begin_object(name);
sink->write_value(ptr->id()); sink->write_tuple(3, ptup);
sink->end_object(); sink->end_object();
} }
} }
...@@ -150,10 +158,27 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> ...@@ -150,10 +158,27 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr>
} }
else else
{ {
primitive_variant ptup[3];
primitive_type ptypes[] = { pt_uint32, pt_uint32, pt_u8string };
source->begin_object(cname); source->begin_object(cname);
auto id = get<std::uint32_t>(source->read_value(pt_uint32)); source->read_tuple(3, ptypes, ptup);
ptrref = actor::by_id(id);
source->end_object(); source->end_object();
const std::string& nstr = get<std::string>(ptup[2]);
// local actor?
auto& pinf = process_information::get();
if ( pinf.process_id == get<std::uint32_t>(ptup[1])
&& pinf.node_id_as_string() == nstr)
{
ptrref = actor::by_id(get<std::uint32_t>(ptup[0]));
}
else
{
actor_proxy_cache::key_tuple key;
std::get<0>(key) = get<std::uint32_t>(ptup[0]);
std::get<1>(key) = get<std::uint32_t>(ptup[1]);
process_information::node_id_from_string(nstr,std::get<2>(key));
ptrref = detail::get_actor_proxy_cache().get(key);
}
} }
} }
...@@ -505,7 +530,7 @@ class uniform_type_info_map ...@@ -505,7 +530,7 @@ class uniform_type_info_map
insert<std::u32string>(); insert<std::u32string>();
insert(new default_uniform_type_info_impl<exit_signal>( insert(new default_uniform_type_info_impl<exit_signal>(
std::make_pair(&exit_signal::reason, std::make_pair(&exit_signal::reason,
&exit_signal::set_uint_reason)), &exit_signal::set_reason)),
{ raw_name<exit_signal>() }); { raw_name<exit_signal>() });
insert(new any_tuple_tinfo, { raw_name<any_tuple>() }); insert(new any_tuple_tinfo, { raw_name<any_tuple>() });
insert(new actor_ptr_tinfo, { raw_name<actor_ptr>() }); insert(new actor_ptr_tinfo, { raw_name<actor_ptr>() });
......
...@@ -7,16 +7,19 @@ LIB_FLAGS = $(LIBS) -L../ -lcppa ...@@ -7,16 +7,19 @@ LIB_FLAGS = $(LIBS) -L../ -lcppa
EXECUTABLE = ../test EXECUTABLE = ../test
HEADERS = hash_of.hpp \ HEADERS = hash_of.hpp \
test.hpp test.hpp \
ping_pong.hpp
SOURCES = hash_of.cpp \ SOURCES = hash_of.cpp \
main.cpp \ main.cpp \
ping_pong.cpp \
test__a_matches_b.cpp \ test__a_matches_b.cpp \
test__atom.cpp \ test__atom.cpp \
test__intrusive_ptr.cpp \ test__intrusive_ptr.cpp \
test__local_group.cpp \ test__local_group.cpp \
test__primitive_variant.cpp \ test__primitive_variant.cpp \
test__queue_performance.cpp \ test__queue_performance.cpp \
test__remote_actor.cpp \
test__ripemd_160.cpp \ test__ripemd_160.cpp \
test__serialization.cpp \ test__serialization.cpp \
test__spawn.cpp \ test__spawn.cpp \
......
...@@ -25,6 +25,21 @@ std::cout << "run " << #fun_name << " ..." << std::endl; \ ...@@ -25,6 +25,21 @@ std::cout << "run " << #fun_name << " ..." << std::endl; \
errors += fun_name (); \ errors += fun_name (); \
std::cout << std::endl std::cout << std::endl
#define RUN_TEST_A1(fun_name, arg1) \
std::cout << "run " << #fun_name << " ..." << std::endl; \
errors += fun_name ((arg1)); \
std::cout << std::endl
#define RUN_TEST_A2(fun_name, arg1, arg2) \
std::cout << "run " << #fun_name << " ..." << std::endl; \
errors += fun_name ((arg1), (arg2)); \
std::cout << std::endl
#define RUN_TEST_A3(fun_name, arg1, arg2, arg3) \
std::cout << "run " << #fun_name << " ..." << std::endl; \
errors += fun_name ((arg1), (arg2), (arg3)); \
std::cout << std::endl
using std::cout; using std::cout;
using std::cerr; using std::cerr;
using std::endl; using std::endl;
...@@ -44,8 +59,6 @@ void print_node_id() ...@@ -44,8 +59,6 @@ void print_node_id()
int main(int argc, char** c_argv) int main(int argc, char** c_argv)
{ {
print_node_id();
cout << endl << endl;
//return 0; //return 0;
std::vector<std::string> argv; std::vector<std::string> argv;
...@@ -61,6 +74,12 @@ int main(int argc, char** c_argv) ...@@ -61,6 +74,12 @@ int main(int argc, char** c_argv)
test__queue_performance(); test__queue_performance();
return 0; return 0;
} }
else if (argv.size() == 2 && argv.front() == "test__remote_actor")
{
test__remote_actor(c_argv[0], true, argv);
cout << "BLABLUBB" << endl;
return 0;
}
else else
{ {
cerr << "usage: test [performance_test]" << endl; cerr << "usage: test [performance_test]" << endl;
...@@ -68,6 +87,8 @@ int main(int argc, char** c_argv) ...@@ -68,6 +87,8 @@ int main(int argc, char** c_argv)
} }
else else
{ {
print_node_id();
cout << endl << endl;
std::cout << std::boolalpha; std::cout << std::boolalpha;
size_t errors = 0; size_t errors = 0;
RUN_TEST(test__ripemd_160); RUN_TEST(test__ripemd_160);
...@@ -81,6 +102,7 @@ int main(int argc, char** c_argv) ...@@ -81,6 +102,7 @@ int main(int argc, char** c_argv)
RUN_TEST(test__spawn); RUN_TEST(test__spawn);
RUN_TEST(test__local_group); RUN_TEST(test__local_group);
RUN_TEST(test__atom); RUN_TEST(test__atom);
RUN_TEST_A3(test__remote_actor, c_argv[0], false, argv);
cout << endl cout << endl
<< "error(s) in all tests: " << errors << "error(s) in all tests: " << errors
<< endl; << endl;
......
#include "ping_pong.hpp"
#include "cppa/cppa.hpp"
namespace { int s_pongs = 0; }
using namespace cppa;
void pong(actor_ptr ping_actor)
{
link(ping_actor);
bool done = false;
// kickoff
ping_actor << make_tuple(0); // or: send(ping_actor, 0);
// invoke rules
auto rules = (on<std::int32_t>(9) >> [&]() { done = true; },
on<std::int32_t>() >> [](int v) { reply(v+1); });
// loop
while (!done) receive(rules);
// terminate with non-normal exit reason
// to force ping actor to quit
quit(exit_reason::user_defined);
}
void ping()
{
s_pongs = 0;
// invoke rule
auto rule = (on<std::int32_t>() >> [](std::int32_t v)
{
++s_pongs;
reply(v+1);
});
// loop
for (;;) receive(rule);
}
int pongs()
{
return s_pongs;
}
#ifndef PING_PONG_HPP
#define PING_PONG_HPP
#include "cppa/actor.hpp"
void ping();
void pong(cppa::actor_ptr ping_actor);
// returns the number of messages ping received
int pongs();
#endif // PING_PONG_HPP
#ifndef TEST_HPP #ifndef TEST_HPP
#define TEST_HPP #define TEST_HPP
#include <vector>
#include <string>
#include <cstddef> #include <cstddef>
#include <iostream> #include <iostream>
...@@ -46,6 +48,8 @@ std::cerr << err_msg << std::endl; \ ...@@ -46,6 +48,8 @@ std::cerr << err_msg << std::endl; \
#define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) CPPA_CHECK(((lhs_loc) == (rhs_loc))) #define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) CPPA_CHECK(((lhs_loc) == (rhs_loc)))
size_t test__remote_actor(const char* app_path, bool is_client,
const std::vector<std::string>& argv);
size_t test__ripemd_160(); size_t test__ripemd_160();
size_t test__uniform_type(); size_t test__uniform_type();
size_t test__type_list(); size_t test__type_list();
......
#include <string>
#include <boost/thread.hpp>
#include "test.hpp"
#include "ping_pong.hpp"
#include "cppa/cppa.hpp"
#include "cppa/exception.hpp"
using namespace cppa;
namespace {
void client_part(const std::vector<std::string>& argv)
{
if (argv.size() != 2) throw std::logic_error("argv.size() != 2");
std::istringstream iss(argv[1]);
std::uint16_t port;
iss >> port;
auto ping_actor = remote_actor("localhost", port);
try
{
pong(ping_actor);
}
catch (...)
{
}
}
} // namespace <anonymous>
size_t test__remote_actor(const char* app_path, bool is_client,
const std::vector<std::string>& argv)
{
CPPA_TEST(test__remote_actor);
if (is_client)
{
client_part(argv);
return 0;
}
auto ping_actor = spawn(ping);
std::uint16_t port = 4242;
bool success = false;
while (!success)
{
try
{
publish(ping_actor, port);
success = true;
}
catch (bind_failure&)
{
// try next port
++port;
}
}
std::string cmd;
{
std::ostringstream oss;
oss << app_path << " test__remote_actor " << port << " &>/dev/null";
cmd = oss.str();
}
// execute client_part() in a separate process,
// connected via localhost socket
boost::thread child([&cmd] () { system(cmd.c_str()); });
await_all_others_done();
CPPA_CHECK_EQUAL(pongs(), 5);
// wait until separate process (in sep. thread) finished execution
child.join();
return CPPA_TEST_RESULT;
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <functional> #include <functional>
#include "test.hpp" #include "test.hpp"
#include "ping_pong.hpp"
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
...@@ -11,59 +12,14 @@ ...@@ -11,59 +12,14 @@
using std::cout; using std::cout;
using std::endl; using std::endl;
namespace { int pings = 0; }
using namespace cppa; using namespace cppa;
void pong(actor_ptr ping_actor)
{
link(ping_actor);
bool done = false;
// kickoff
ping_actor << make_tuple(0); // or: send(ping_actor, 0);
// invoke rules
auto rules = (on<std::int32_t>(9) >> [&]() { done = true; },
on<std::int32_t>() >> [](int v) { reply(v+1); });
// loop
while (!done) receive(rules);
// terminate with non-normal exit reason
// to force ping actor to quit
quit(user_defined_exit_reason);
}
void ping()
{
// invoke rule
auto rule = (on<std::int32_t>() >> [](std::int32_t v)
{
++pings;
reply(v+1);
},
others() >> []()
{
cout << to_string(last_received())
<< endl;
});
// loop
for (;;) receive(rule);
}
void pong_example()
{
spawn(pong, spawn(ping));
await_all_others_done();
}
void echo(actor_ptr whom, int what)
{
send(whom, what);
}
size_t test__spawn() size_t test__spawn()
{ {
CPPA_TEST(test__spawn); CPPA_TEST(test__spawn);
pong_example(); spawn(pong, spawn(ping));
CPPA_CHECK_EQUAL(pings, 5); await_all_others_done();
CPPA_CHECK_EQUAL(pongs(), 5);
/* /*
actor_ptr self_ptr = self(); actor_ptr self_ptr = self();
{ {
......
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