Commit cc13bb2d authored by Dominik Charousset's avatar Dominik Charousset

added actor_companion_mixin, refactored weak ptr

actor_companion_mixin is meant to give non-actor classes the possibility to send
and receive regular cppa messages without too much glue code (implement one
virtual member function and call set_message_handler rather than using receive
or become);
weak_ptr_anchor is a regular class now, get() is a template member function
casting the pointer to the correct derived type using static_cast
parent 425aa491
......@@ -81,7 +81,76 @@ if (DISABLE_CONTEXT_SWITCHING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCPPA_DISABLE_CONTEXT_SWITCHING")
endif ()
file(GLOB LIBCPPA_SRC "src/*.cpp")
#file(GLOB LIBCPPA_SRC "src/*.cpp")
set(LIBCPPA_SRC
src/abstract_scheduled_actor.cpp
src/abstract_tuple.cpp
src/actor.cpp
src/actor_addressing.cpp
src/actor_count.cpp
src/actor_proxy.cpp
src/actor_registry.cpp
src/addressed_message.cpp
src/any_tuple.cpp
src/atom.cpp
src/attachable.cpp
src/behavior_stack.cpp
src/binary_deserializer.cpp
src/binary_serializer.cpp
src/buffer.cpp
src/channel.cpp
src/context_switching_actor.cpp
src/continuable_reader.cpp
src/continuable_writer.cpp
src/decorated_names_map.cpp
src/default_actor_addressing.cpp
src/default_actor_proxy.cpp
src/default_peer.cpp
src/default_peer_acceptor.cpp
src/default_protocol.cpp
src/demangle.cpp
src/deserializer.cpp
src/duration.cpp
src/empty_tuple.cpp
src/event_based_actor.cpp
src/exception.cpp
src/factory.cpp
src/fd_util.cpp
src/fiber.cpp
src/group.cpp
src/group_manager.cpp
src/ipv4_acceptor.cpp
src/ipv4_io_stream.cpp
src/local_actor.cpp
src/logging.cpp
src/middleman.cpp
src/object.cpp
src/object_array.cpp
src/opt.cpp
src/partial_function.cpp
src/pattern.cpp
src/primitive_variant.cpp
src/process_information.cpp
src/protocol.cpp
src/receive.cpp
src/ref_counted.cpp
src/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp
src/self.cpp
src/serializer.cpp
src/shared_spinlock.cpp
src/singleton_manager.cpp
src/string_serialization.cpp
src/thread_mapped_actor.cpp
src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp
src/unicast_network.cpp
src/uniform_type_info.cpp
src/weak_ptr_anchor.cpp
src/yield_interface.cpp)
set(boost_context third_party/boost_context)
......
......@@ -291,3 +291,6 @@ cppa/network/continuable_writer.hpp
src/continuable_writer.cpp
cppa/network/middleman_event_handler_base.hpp
src/actor_addressing.cpp
cppa/weak_ptr_anchor.hpp
src/weak_ptr_anchor.cpp
cppa/actor_companion_mixin.hpp
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 CPPA_ACTOR_COMPANION_MIXIN_HPP
#define CPPA_ACTOR_COMPANION_MIXIN_HPP
#include <mutex> // std::lock_guard
#include <memory> // std::unique_ptr
#include "cppa/self.hpp"
#include "cppa/actor.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
#include "cppa/detail/abstract_actor.hpp"
namespace cppa {
template<typename Base>
class actor_companion_mixin : public Base {
typedef Base super;
public:
typedef std::unique_ptr<detail::recursive_queue_node> message_pointer;
template<typename... Args>
actor_companion_mixin(Args&&... args) : super(std::forward<Args>(args)...) {
m_self.reset(new companion(this));
}
~actor_companion_mixin() {
m_self->disconnect();
}
inline actor_ptr as_actor() const { return m_self; }
protected:
/**
* @warning Implementation has to be thread-safe.
*/
virtual void new_message(message_pointer ptr) = 0;
template<typename... Args>
void set_message_handler(Args&&... matchExpressions) {
m_message_handler = match_expr_concat(std::forward<Args>(matchExpressions)...);
}
void handle_message(const message_pointer& msg) {
if (!msg) return;
scoped_self_setter sss(m_self.get());
m_self->m_current_node = msg.get();
auto f = m_message_handler; // make sure ref count >= 2
f(msg->msg);
}
private:
class companion : public detail::abstract_actor<local_actor> {
friend class actor_companion_mixin;
typedef util::shared_spinlock lock_type;
typedef std::unique_ptr<detail::recursive_queue_node> node_ptr;
public:
companion(actor_companion_mixin* parent) : m_parent(parent) { }
void disconnect() {
{ // lifetime scope of guard
std::lock_guard<lock_type> guard(m_lock);
m_parent = nullptr;
}
cleanup(cppa::exit_reason::normal);
}
void enqueue(cppa::actor* sender, cppa::any_tuple msg) {
cppa::util::shared_lock_guard<lock_type> guard(m_lock);
if (m_parent) {
m_parent->new_message(new_node_ptr(sender, std::move(msg)));
}
}
void sync_enqueue(cppa::actor* sender, cppa::message_id_t id, cppa::any_tuple msg) {
cppa::util::shared_lock_guard<lock_type> guard(m_lock);
if (m_parent) {
m_parent->new_message(new_node_ptr(sender, std::move(msg), id));
}
}
bool initialized() { return true; }
void quit(std::uint32_t) {
throw std::runtime_error("ActorWidgetMixin::Gateway::exit "
"is forbidden, use Qt's widget "
"management instead!");
}
void dequeue(cppa::behavior&) { throw_no_recv(); }
void dequeue(cppa::partial_function&) { throw_no_recv(); }
void unbecome() { throw_no_become(); }
void dequeue_response(cppa::behavior&, cppa::message_id_t) {
throw_no_recv();
}
void become_waiting_for(cppa::behavior&&, cppa::message_id_t) {
throw_no_become();
}
protected:
void do_become(cppa::behavior&&, bool) { throw_no_become(); }
private:
template<typename... Args>
node_ptr new_node_ptr(Args&&... args) {
return node_ptr(new detail::recursive_queue_node(std::forward<Args>(args)...));
}
void throw_no_become() {
throw std::runtime_error("actor_companion_mixin::companion "
"does not support libcppa's "
"become() API");
}
void throw_no_recv() {
throw std::runtime_error("actor_companion_mixin::companion "
"does not support libcppa's "
"receive() API");
}
lock_type m_lock;
actor_companion_mixin* m_parent;
};
intrusive_ptr<companion> m_self;
partial_function m_message_handler;
};
} // namespace cppa
#endif // CPPA_ACTOR_COMPANION_MIXIN_HPP
......@@ -42,9 +42,9 @@ class actor_proxy_cache;
/**
* @brief Represents a remote actor.
*/
class actor_proxy : public enable_weak_ptr_mixin<actor_proxy,actor> {
class actor_proxy : public enable_weak_ptr_mixin<actor> {
typedef enable_weak_ptr_mixin<actor_proxy,actor> super;
typedef enable_weak_ptr_mixin<actor> super;
public:
......
......@@ -37,68 +37,37 @@
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/weak_ptr_anchor.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
namespace cppa {
template<class Derived, class Base>
template<class Base>
class enable_weak_ptr_mixin : public Base {
typedef Base super;
typedef Derived sub;
static_assert(std::is_base_of<ref_counted,Base>::value,
"Base needs to be derived from ref_counted");
public:
class weak_ptr_anchor : public ref_counted {
public:
weak_ptr_anchor(sub* ptr) : m_ptr(ptr) { }
intrusive_ptr<sub> get() {
intrusive_ptr<sub> result;
util::shared_lock_guard<util::shared_spinlock> guard(m_lock);
if (m_ptr) result.reset(m_ptr);
return result;
}
bool expired() const {
// no need for locking since pointer comparison is atomic
return m_ptr == nullptr;
}
bool try_expire() {
std::lock_guard<util::shared_spinlock> guard(m_lock);
// double-check reference count
if (m_ptr->get_reference_count() == 0) {
m_ptr = nullptr;
return true;
}
return false;
}
private:
sub* m_ptr;
util::shared_spinlock m_lock;
};
intrusive_ptr<weak_ptr_anchor> get_weak_ptr_anchor() const { return m_anchor; }
inline intrusive_ptr<weak_ptr_anchor> get_weak_ptr_anchor() const {
return m_anchor;
}
protected:
template<typename... Args>
enable_weak_ptr_mixin(Args&&... args)
: super(std::forward<Args>(args)...)
, m_anchor(new weak_ptr_anchor(static_cast<sub*>(this))) { }
, m_anchor(new weak_ptr_anchor(this)) { }
void request_deletion() { if (m_anchor->try_expire()) delete this; }
void request_deletion() {
if (m_anchor->try_expire()) delete this;
}
private:
......
......@@ -35,6 +35,7 @@
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/weak_ptr_anchor.hpp"
#include "cppa/util/comparable.hpp"
namespace cppa {
......@@ -42,8 +43,6 @@ namespace cppa {
template<typename T>
class weak_intrusive_ptr : util::comparable<weak_intrusive_ptr<T>> {
typedef typename T::weak_ptr_anchor anchor_type;
public:
weak_intrusive_ptr(const intrusive_ptr<T>& from) {
......@@ -59,7 +58,7 @@ class weak_intrusive_ptr : util::comparable<weak_intrusive_ptr<T>> {
* @warning Returns @p nullptr if expired.
*/
intrusive_ptr<T> promote() {
return (m_anchor) ? m_anchor->get() : nullptr;
return (m_anchor) ? m_anchor->get<T>() : nullptr;
}
/**
......@@ -83,7 +82,7 @@ class weak_intrusive_ptr : util::comparable<weak_intrusive_ptr<T>> {
private:
intrusive_ptr<anchor_type> m_anchor;
intrusive_ptr<weak_ptr_anchor> m_anchor;
};
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 CPPA_WEAK_PTR_ANCHOR_HPP
#define CPPA_WEAK_PTR_ANCHOR_HPP
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
namespace cppa {
class weak_ptr_anchor : public ref_counted {
public:
weak_ptr_anchor(ref_counted* ptr);
template<typename T>
intrusive_ptr<T> get() {
intrusive_ptr<T> result;
{ // lifetime scope of guard
util::shared_lock_guard<util::shared_spinlock> guard(m_lock);
if (m_ptr) result.reset(static_cast<T*>(m_ptr));
}
return result;
}
inline bool expired() const {
// no need for locking since pointer comparison is atomic
return m_ptr == nullptr;
}
bool try_expire();
private:
ref_counted* m_ptr;
util::shared_spinlock m_lock;
};
} // namespace cppa
#endif // CPPA_WEAK_PTR_ANCHOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include <mutex> // std::lock_guard
#include "cppa/weak_ptr_anchor.hpp"
namespace cppa {
weak_ptr_anchor::weak_ptr_anchor(ref_counted* ptr) : m_ptr(ptr) { }
bool weak_ptr_anchor::try_expire() {
std::lock_guard<util::shared_spinlock> guard(m_lock);
// double-check reference count
if (m_ptr->get_reference_count() == 0) {
m_ptr = nullptr;
return true;
}
return false;
}
} // namespace cppa
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