Commit e893f505 authored by Joseph Noir's avatar Joseph Noir

Merge branch 'unstable' into topic/opencl

Conflicts:
	configure
	cppa/opencl/actor_facade.hpp
	cppa/opencl/command.hpp
parents 0fc8d66c ffed360f
......@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 2.8)
project(cppa C CXX)
set(LIBCPPA_VERSION_MAJOR 0)
set(LIBCPPA_VERSION_MINOR 8)
set(LIBCPPA_VERSION_PATCH 1)
set(LIBCPPA_VERSION_MINOR 9)
set(LIBCPPA_VERSION_PATCH 0)
# prohibit in-source builds
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
......@@ -57,7 +57,7 @@ endif (HAVE_VALGRIND_H)
# check for g++ >= 4.7 or clang++ > = 3.2
try_run(ProgramResult
CompilationSucceeded
${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/get_compiler_version.cpp
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/get_compiler_version.cpp
RUN_OUTPUT_VARIABLE CompilerVersion)
if (NOT CompilationSucceeded OR NOT ProgramResult EQUAL 0)
message(FATAL_ERROR "Cannot determine compiler version")
......@@ -77,7 +77,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
message(STATUS "NOTE: Automatically added -stdlib=libc++ flag, "
"you can override this by defining CMAKE_CXX_FLAGS "
"(see 'configure --help')")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif ()
else ()
message(FATAL_ERROR "Your C++ compiler does not support C++11 "
......@@ -88,12 +88,20 @@ endif ()
if (ENABLE_DEBUG)
set(CMAKE_BUILD_TYPE Debug)
add_definitions(-DCPPA_DEBUG_MODE)
message(STATUS "Enable libcppa's debug mode")
endif (ENABLE_DEBUG)
if (ENABLE_ADDRESS_SANITIZER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
message(STATUS "Enable address sanitizer")
endif (ENABLE_ADDRESS_SANITIZER)
if (CPPA_LOG_LEVEL)
add_definitions(-DCPPA_LOG_LEVEL=${CPPA_LOG_LEVEL})
endif(CPPA_LOG_LEVEL)
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
# set build default build type if not set
if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo)
......@@ -120,11 +128,16 @@ file(GLOB LIBCPPA_HDRS "cppa/*.hpp"
# list cpp files including platform-dependent files
set(LIBCPPA_SRC
${LIBCPPA_PLATFORM_SRC}
src/abstract_actor.cpp
src/abstract_channel.cpp
src/abstract_group.cpp
src/abstract_tuple.cpp
src/actor.cpp
src/actor_addr.cpp
src/actor_namespace.cpp
src/actor_proxy.cpp
src/actor_registry.cpp
src/actor_ostream.cpp
src/algorithm.cpp
src/any_tuple.cpp
src/atom.cpp
......@@ -135,9 +148,11 @@ set(LIBCPPA_SRC
src/binary_serializer.cpp
src/broker.cpp
src/buffer.cpp
src/blocking_actor.cpp
src/channel.cpp
src/context_switching_actor.cpp
src/context_switching_resume.cpp
src/continuable.cpp
src/continue_helper.cpp
src/decorated_tuple.cpp
src/actor_proxy.cpp
src/peer.cpp
......@@ -149,9 +164,10 @@ set(LIBCPPA_SRC
src/event_based_actor.cpp
src/exception.cpp
src/exit_reason.cpp
src/factory.cpp
src/fd_util.cpp
src/fiber.cpp
src/functor_based_actor.cpp
src/functor_based_blocking_actor.cpp
src/get_root_uuid.cpp
src/get_mac_addresses.cpp
src/group.cpp
......@@ -175,19 +191,17 @@ set(LIBCPPA_SRC
src/partial_function.cpp
src/primitive_variant.cpp
src/ref_counted.cpp
src/resumable.cpp
src/remote_actor_proxy.cpp
src/response_handle.cpp
src/response_promise.cpp
src/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp
src/send.cpp
src/self.cpp
src/scoped_actor.cpp
src/serializer.cpp
src/shared_spinlock.cpp
src/singleton_manager.cpp
src/string_serialization.cpp
src/thread_mapped_actor.cpp
src/sync_request_bouncer.cpp
src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp
src/type_lookup_table.cpp
......@@ -238,6 +252,18 @@ else (DISABLE_CONTEXT_SWITCHING)
set(DISABLE_CONTEXT_SWITCHING true)
else (NOT Boost_FOUND)
if (${Boost_VERSION} LESS 105400)
set(LD_FLAGS ${LD_FLAGS} ${Boost_CONTEXT_LIBRARY})
# nothing to do in this case
else ()
# for boost >= 1.54, we need coroutines as well
message(STATUS "Detected Boost >= 1.54.0, check for coroutines & system")
find_package(Boost 1.51.0 COMPONENTS system context coroutine)
if (Boost_FOUND)
set(LD_FLAGS ${LD_FLAGS} ${Boost_COROUTINE_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY})
endif ()
endif ()
# check again, as second find_package might set this to false
if (Boost_FOUND)
# This hack fixes a problem when the linker search path is the same as
# the one provided by the compiler. In this case, CMake replaces the absolute
# path (e.g., /path/to/lib.so) with -l<lib>, which may cause it to pick up the wrong
......@@ -247,10 +273,9 @@ else (DISABLE_CONTEXT_SWITCHING)
set(CMAKE_EXE_LINKER_FLAGS -L${Boost_LIBRARY_DIRS})
set(INCLUDE_DIRS ${INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
set(LD_DIRS ${LD_DIRS} ${Boost_LIBRARY_DIRS})
set(LD_FLAGS ${LD_FLAGS} ${Boost_CONTEXT_LIBRARY})
set(DISABLE_CONTEXT_SWITCHING false)
else ()
message(WARNING "Boost >= 1.54 is not supported due the unstable API of Boost.Coroutines")
# disable implicitly
set(DISABLE_CONTEXT_SWITCHING true)
endif ()
endif (NOT Boost_FOUND)
......@@ -348,7 +373,7 @@ endif ()
# check for doxygen and add custom "doc" target to Makefile
find_package(Doxygen)
if (DOXYGEN_FOUND)
configure_file(${CMAKE_SOURCE_DIR}/Doxyfile.in ${CMAKE_SOURCE_DIR}/Doxyfile
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile
@ONLY)
add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_HOME_DIRECTORY}/Doxyfile
WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY}
......
Version 0.9.0
-------------
__2014_XX_XX__
- Redesigned large parts of the library related to type-safe actors:
* No more thread-local `self`, because it can only return a type-erased handle
* New type `actor` replaces `actor_ptr`, can be used to send any message
* New type `actor_addr` can only be used for monitoring and identifying actors
* New type `exit_msg` is now used instead of messages using the atom `EXIT`
* New type `down_msg` is now used instead of messages using the atom `DOWN`
* New header `system_messages.hpp` for message types used by the runtime
Version 0.8.1
-------------
......
......@@ -31,7 +31,7 @@ PROJECT_NAME = libcppa
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = "Version 0.8.1"
PROJECT_NUMBER = "Version 0.9.0"
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
......
......@@ -45,6 +45,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--enable-debug compile in debugging mode
(always sets --build-type=Debug)
--enable-perftools use Google perftools
--enable-address-sanitizer use Clang's address sanitizer
--with-cppa-log-level=LVL sets the debugging output, possible values:
- ERROR
- WARNING
......@@ -123,7 +124,7 @@ configure ()
cd $workdir
if [ -n "$5" ]; then
cmake -G $5 $CMakeCacheEntries $sourcedir
cmake -G "$5" $CMakeCacheEntries $sourcedir
else
cmake $CMakeCacheEntries $sourcedir
fi
......@@ -136,7 +137,6 @@ configure ()
# Set defaults.
builddir="$sourcedir/build"
CMakeCacheEntries=""
append_cache_entry CMAKE_BUILD_TYPE STRING RelWithDebInfo
append_cache_entry CMAKE_INSTALL_PREFIX PATH /usr/local
append_cache_entry ENABLE_DEBUG BOOL false
append_cache_entry DISABLE_CONTEXT_SWITCHING BOOL false
......@@ -162,6 +162,9 @@ while [ $# -ne 0 ]; do
--enable-debug)
append_cache_entry ENABLE_DEBUG BOOL true
;;
--enable-address-sanitizer)
append_cache_entry ENABLE_ADDRESS_SANITIZER BOOL true
;;
--with-opencl)
append_cache_entry ENABLE_OPENCL BOOL true
;;
......
cppa/abstract_actor.hpp
cppa/abstract_channel.hpp
cppa/abstract_group.hpp
cppa/actor.hpp
cppa/actor_addressing.hpp
cppa/actor_companion_mixin.hpp
cppa/actor_addr.hpp
cppa/actor_namespace.hpp
cppa/actor_ostream.hpp
cppa/actor_proxy.hpp
cppa/actor_state.hpp
cppa/announce.hpp
cppa/any_tuple.hpp
cppa/anything.hpp
cppa/atom.hpp
cppa/attachable.hpp
cppa/behavior.hpp
cppa/behavior_policy.hpp
cppa/behavior_stack_based.hpp
cppa/binary_deserializer.hpp
cppa/binary_serializer.hpp
cppa/blocking_actor.hpp
cppa/channel.hpp
cppa/config.hpp
cppa/context_switching_actor.hpp
cppa/continue_helper.hpp
cppa/cow_ptr.hpp
cppa/cow_tuple.hpp
cppa/cppa.hpp
......@@ -30,10 +38,9 @@ cppa/detail/default_uniform_type_info_impl.hpp
cppa/detail/demangle.hpp
cppa/detail/disablable_delete.hpp
cppa/detail/empty_tuple.hpp
cppa/detail/event_based_actor_factory.hpp
cppa/detail/fd_util.hpp
cppa/detail/fwd.hpp
cppa/detail/get_behavior.hpp
cppa/detail/functor_based_actor.hpp
cppa/detail/functor_based_blocking_actor.hpp
cppa/detail/group_manager.hpp
cppa/detail/handle.hpp
cppa/detail/ieee_754.hpp
......@@ -46,11 +53,11 @@ cppa/detail/opt_impls.hpp
cppa/detail/optional_variant_data.hpp
cppa/detail/pair_member.hpp
cppa/detail/projection.hpp
cppa/detail/proper_actor.hpp
cppa/detail/pseudo_tuple.hpp
cppa/detail/ptype_to_type.hpp
cppa/detail/receive_loop_helper.hpp
cppa/detail/receive_policy.hpp
cppa/detail/scheduled_actor_dummy.hpp
cppa/detail/raw_access.hpp
cppa/detail/response_handle_util.hpp
cppa/detail/serialize_tuple.hpp
cppa/detail/singleton_manager.hpp
cppa/detail/singleton_mixin.hpp
......@@ -75,7 +82,6 @@ cppa/event_based_actor.hpp
cppa/exception.hpp
cppa/exit_reason.hpp
cppa/extend.hpp
cppa/factory.hpp
cppa/from_string.hpp
cppa/get.hpp
cppa/group.hpp
......@@ -89,12 +95,7 @@ cppa/io/broker.hpp
cppa/io/buffered_writing.hpp
cppa/io/connection_handle.hpp
cppa/io/continuable.hpp
cppa/io/default_actor_addressing.hpp
cppa/io/default_actor_proxy.hpp
cppa/io/default_message_queue.hpp
cppa/io/default_peer.hpp
cppa/io/default_peer_acceptor.hpp
cppa/io/default_protocol.hpp
cppa/io/event.hpp
cppa/io/input_stream.hpp
cppa/io/ipv4_acceptor.hpp
......@@ -102,7 +103,9 @@ cppa/io/ipv4_io_stream.hpp
cppa/io/middleman.hpp
cppa/io/middleman_event_handler.hpp
cppa/io/output_stream.hpp
cppa/io/protocol.hpp
cppa/io/peer.hpp
cppa/io/peer_acceptor.hpp
cppa/io/remote_actor_proxy.hpp
cppa/io/stream.hpp
cppa/local_actor.hpp
cppa/logging.hpp
......@@ -113,10 +116,10 @@ cppa/match_expr.hpp
cppa/match_hint.hpp
cppa/memory_cached.hpp
cppa/memory_managed.hpp
cppa/message_future.hpp
cppa/message_header.hpp
cppa/message_id.hpp
cppa/message_priority.hpp
cppa/node_id.hpp
cppa/none.hpp
cppa/object.hpp
cppa/on.hpp
......@@ -132,29 +135,41 @@ cppa/opt.hpp
cppa/optional.hpp
cppa/optional_variant.hpp
cppa/partial_function.hpp
cppa/policy.hpp
cppa/policy/context_switching_resume.hpp
cppa/policy/cooperative_scheduling.hpp
cppa/policy/event_based_resume.hpp
cppa/policy/invoke_policy.hpp
cppa/policy/middleman_scheduling.hpp
cppa/policy/nestable_invoke.hpp
cppa/policy/no_resume.hpp
cppa/policy/no_scheduling.hpp
cppa/policy/not_prioritizing.hpp
cppa/policy/policies.hpp
cppa/policy/prioritizing.hpp
cppa/policy/priority_policy.hpp
cppa/policy/resume_policy.hpp
cppa/policy/scheduling_policy.hpp
cppa/policy/sequential_invoke.hpp
cppa/primitive_type.hpp
cppa/primitive_variant.hpp
cppa/prioritizing.hpp
cppa/process_information.hpp
cppa/qtsupport/actor_widget_mixin.hpp
cppa/receive.hpp
cppa/ref_counted.hpp
cppa/replies_to.hpp
cppa/response_handle.hpp
cppa/response_promise.hpp
cppa/resumable.hpp
cppa/sb_actor.hpp
cppa/scheduled_actor.hpp
cppa/scheduler.hpp
cppa/self.hpp
cppa/send.hpp
cppa/scoped_actor.hpp
cppa/serializer.hpp
cppa/single_timeout.hpp
cppa/singletons.hpp
cppa/spawn.hpp
cppa/spawn_fwd.hpp
cppa/spawn_options.hpp
cppa/stacked.hpp
cppa/stackless.hpp
cppa/thread_mapped_actor.hpp
cppa/threaded.hpp
cppa/threadless.hpp
cppa/sync_sender.hpp
cppa/system_messages.hpp
cppa/timeout_definition.hpp
cppa/to_string.hpp
cppa/tpartial_function.hpp
......@@ -163,6 +178,8 @@ cppa/type_lookup_table.hpp
cppa/typed_actor.hpp
cppa/typed_actor_ptr.hpp
cppa/typed_behavior.hpp
cppa/typed_continue_helper.hpp
cppa/typed_event_based_actor.hpp
cppa/uniform_type_info.hpp
cppa/unit.hpp
cppa/util/abstract_uniform_type_info.hpp
......@@ -177,6 +194,7 @@ cppa/util/duration.hpp
cppa/util/fiber.hpp
cppa/util/get_mac_addresses.hpp
cppa/util/get_root_uuid.hpp
cppa/util/guard.hpp
cppa/util/int_list.hpp
cppa/util/left_or_right.hpp
cppa/util/limited_vector.hpp
......@@ -207,21 +225,24 @@ examples/opencl/proper_matrix.cpp
examples/opencl/simple_matrix.cpp
examples/qtsupport/chatwidget.cpp
examples/qtsupport/chatwidget.hpp
examples/qtsupport/chatwindow.ui
examples/qtsupport/qt_group_chat.cpp
examples/remote_actors/distributed_calculator.cpp
examples/remote_actors/group_chat.cpp
examples/remote_actors/group_server.cpp
examples/remote_actors/protobuf.scala
examples/remote_actors/protobuf_broker.cpp
examples/type_system/announce_1.cpp
examples/type_system/announce_2.cpp
examples/type_system/announce_3.cpp
examples/type_system/announce_4.cpp
examples/type_system/announce_5.cpp
src/abstract_actor.cpp
src/abstract_channel.cpp
src/abstract_group.cpp
src/abstract_tuple.cpp
src/actor.cpp
src/actor_addressing.cpp
src/actor_addr.cpp
src/actor_namespace.cpp
src/actor_ostream.cpp
src/actor_proxy.cpp
src/actor_registry.cpp
src/algorithm.cpp
......@@ -232,17 +253,14 @@ src/behavior.cpp
src/behavior_stack.cpp
src/binary_deserializer.cpp
src/binary_serializer.cpp
src/blocking_actor.cpp
src/broker.cpp
src/buffer.cpp
src/channel.cpp
src/context_switching_actor.cpp
src/context_switching_resume.cpp
src/continuable.cpp
src/continue_helper.cpp
src/decorated_tuple.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
......@@ -253,6 +271,8 @@ src/exit_reason.cpp
src/factory.cpp
src/fd_util.cpp
src/fiber.cpp
src/functor_based_actor.cpp
src/functor_based_blocking_actor.cpp
src/get_mac_addresses.cpp
src/get_root_uuid.cpp
src/group.cpp
......@@ -270,6 +290,7 @@ src/middleman.cpp
src/middleman_event_handler.cpp
src/middleman_event_handler_epoll.cpp
src/middleman_event_handler_poll.cpp
src/node_id.cpp
src/object.cpp
src/object_array.cpp
src/on.cpp
......@@ -279,22 +300,22 @@ src/opencl/opencl_metainfo.cpp
src/opencl/program.cpp
src/opt.cpp
src/partial_function.cpp
src/peer.cpp
src/peer_acceptor.cpp
src/primitive_variant.cpp
src/process_information.cpp
src/protocol.cpp
src/ref_counted.cpp
src/response_handle.cpp
src/remote_actor_proxy.cpp
src/response_promise.cpp
src/resumable.cpp
src/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp
src/self.cpp
src/send.cpp
src/scoped_actor.cpp
src/serializer.cpp
src/shared_spinlock.cpp
src/singleton_manager.cpp
src/string_serialization.cpp
src/thread_mapped_actor.cpp
src/sync_request_bouncer.cpp
src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp
src/type_lookup_table.cpp
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_ABSTRACT_ACTOR_HPP
#define CPPA_ABSTRACT_ACTOR_HPP
#include <set>
#include <mutex>
#include <atomic>
#include <memory>
#include <string>
#include <vector>
#include <cstdint>
#include <type_traits>
#include "cppa/node_id.hpp"
#include "cppa/cppa_fwd.hpp"
#include "cppa/attachable.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_channel.hpp"
#include "cppa/util/type_traits.hpp"
namespace cppa {
class actor_addr;
class serializer;
class deserializer;
/**
* @brief A unique actor ID.
* @relates abstract_actor
*/
typedef std::uint32_t actor_id;
class actor;
class abstract_actor;
typedef intrusive_ptr<abstract_actor> abstract_actor_ptr;
/**
* @brief Base class for all actor implementations.
*/
class abstract_actor : public abstract_channel {
public:
/**
* @brief Attaches @p ptr to this actor.
*
* The actor will call <tt>ptr->detach(...)</tt> on exit, or immediately
* if it already finished execution.
* @param ptr A callback object that's executed if the actor finishes
* execution.
* @returns @c true if @p ptr was successfully attached to the actor;
* otherwise (actor already exited) @p false.
* @warning The actor takes ownership of @p ptr.
*/
bool attach(attachable_ptr ptr);
/**
* @brief Convenience function that attaches the functor
* or function @p f to this actor.
*
* The actor executes <tt>f()</tt> on exit, or immediatley
* if it already finished execution.
* @param f A functor, function or lambda expression that's executed
* if the actor finishes execution.
* @returns @c true if @p f was successfully attached to the actor;
* otherwise (actor already exited) @p false.
*/
template<typename F>
bool attach_functor(F&& f);
/**
* @brief Returns the address of this actor.
*/
actor_addr address() const;
/**
* @brief Detaches the first attached object that matches @p what.
*/
void detach(const attachable::token& what);
/**
* @brief Links this actor to @p whom.
* @param other Actor instance that whose execution is coupled to the
* execution of this Actor.
*/
virtual void link_to(const actor_addr& whom);
/**
* @copydoc abstract_actor::link_to(const actor_addr&)
*/
template<typename ActorHandle>
void link_to(const ActorHandle& whom) {
link_to(whom.address());
}
/**
* @brief Unlinks this actor from @p whom.
* @param other Linked Actor.
* @note Links are automatically removed if the actor finishes execution.
*/
virtual void unlink_from(const actor_addr& whom);
/**
* @copydoc abstract_actor::unlink_from(const actor_addr&)
*/
template<class ActorHandle>
void unlink_from(const ActorHandle& whom) {
unlink_from(whom.address());
}
/**
* @brief Establishes a link relation between this actor and @p other.
* @param other Actor instance that wants to link against this Actor.
* @returns @c true if this actor is running and added @p other to its
* list of linked actors; otherwise @c false.
*/
virtual bool establish_backlink(const actor_addr& other);
/**
* @brief Removes a link relation between this actor and @p other.
* @param other Actor instance that wants to unlink from this Actor.
* @returns @c true if this actor is running and removed @p other
* from its list of linked actors; otherwise @c false.
*/
virtual bool remove_backlink(const actor_addr& other);
/**
* @brief Gets an integer value that uniquely identifies this Actor in
* the process it's executed in.
* @returns The unique identifier of this actor.
*/
inline actor_id id() const;
/**
* @brief Checks if this actor is running on a remote node.
* @returns @c true if this actor represents a remote actor;
* otherwise @c false.
*/
inline bool is_proxy() const;
/**
* @brief Returns the ID of the node this actor is running on.
*/
inline const node_id& node() const;
/**
* @brief Returns the actor's exit reason of
* <tt>exit_reason::not_exited</tt> if it's still alive.
*/
inline std::uint32_t exit_reason() const;
/**
* @brief Returns the type interface as set of strings.
* @note The returned set is empty for all untyped actors.
*/
virtual std::set<std::string> interface() const;
protected:
abstract_actor();
abstract_actor(actor_id aid);
/**
* @brief Should be overridden by subtypes and called upon termination.
* @note Default implementation sets 'exit_reason' accordingly.
* @note Overridden functions should always call super::cleanup().
*/
virtual void cleanup(std::uint32_t reason);
/**
* @brief The default implementation for {@link link_to()}.
*/
bool link_to_impl(const actor_addr& other);
/**
* @brief The default implementation for {@link unlink_from()}.
*/
bool unlink_from_impl(const actor_addr& other);
/**
* @brief Returns <tt>exit_reason() != exit_reason::not_exited</tt>.
*/
inline bool exited() const;
// cannot be changed after construction
const actor_id m_id;
// you're either a proxy or you're not
const bool m_is_proxy;
private:
// initially exit_reason::not_exited
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exit_reason, m_attachables, and m_links
std::mutex m_mtx;
// links to other actors
std::vector<abstract_actor_ptr> m_links;
// attached functors that are executed on cleanup
std::vector<attachable_ptr> m_attachables;
protected:
// identifies the node this actor is running on
node_id_ptr m_node;
};
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
inline std::uint32_t abstract_actor::id() const {
return m_id;
}
inline bool abstract_actor::is_proxy() const {
return m_is_proxy;
}
inline std::uint32_t abstract_actor::exit_reason() const {
return m_exit_reason;
}
inline bool abstract_actor::exited() const {
return exit_reason() != exit_reason::not_exited;
}
inline const node_id& abstract_actor::node() const {
return *m_node;
}
template<class F>
struct functor_attachable : attachable {
F m_functor;
template<typename T>
inline functor_attachable(T&& arg) : m_functor(std::forward<T>(arg)) { }
void actor_exited(std::uint32_t reason) { m_functor(reason); }
bool matches(const attachable::token&) { return false; }
};
template<typename F>
bool abstract_actor::attach_functor(F&& f) {
typedef typename util::rm_const_and_ref<F>::type f_type;
typedef functor_attachable<f_type> impl;
return attach(attachable_ptr{new impl(std::forward<F>(f))});
}
} // namespace cppa
#endif // CPPA_ABSTRACT_ACTOR_HPP
......@@ -28,26 +28,38 @@
\******************************************************************************/
#ifndef CPPA_SCHEDULED_ACTOR_DUMMY_HPP
#define CPPA_SCHEDULED_ACTOR_DUMMY_HPP
#include "cppa/scheduled_actor.hpp"
namespace cppa { namespace detail {
struct scheduled_actor_dummy : scheduled_actor {
scheduled_actor_dummy();
void enqueue(const message_header&, any_tuple) override;
resume_result resume(util::fiber*, actor_ptr&) override;
void quit(std::uint32_t) override;
void dequeue(behavior&) override;
void dequeue_response(behavior&, message_id) override;
void do_become(behavior&&, bool) override;
void become_waiting_for(behavior, message_id) override;
bool has_behavior() override;
scheduled_actor_type impl_type() override;
#ifndef CPPA_ABSTRACT_CHANNEL_HPP
#define CPPA_ABSTRACT_CHANNEL_HPP
#include "cppa/ref_counted.hpp"
namespace cppa {
// forward declarations
class any_tuple;
class message_header;
/**
* @brief Interface for all message receivers.
*
* This interface describes an entity that can receive messages
* and is implemented by {@link actor} and {@link group}.
*/
class abstract_channel : public ref_counted {
public:
/**
* @brief Enqueues @p msg to the list of received messages.
*/
virtual void enqueue(const message_header& hdr, any_tuple msg) = 0;
protected:
virtual ~abstract_channel();
};
} } // namespace cppa::detail
} // namespace cppa
#endif // CPPA_SCHEDULED_ACTOR_DUMMY_HPP
#endif // CPPA_ABSTRACT_CHANNEL_HPP
......@@ -28,132 +28,153 @@
\******************************************************************************/
#ifndef CPPA_SELF_HPP
#define CPPA_SELF_HPP
#ifndef CPPA_ABSTRACT_GROUP_HPP
#define CPPA_ABSTRACT_GROUP_HPP
#include "cppa/actor.hpp"
#include "cppa/intrusive_ptr.hpp"
#include <string>
#include <memory>
#include "cppa/channel.hpp"
#include "cppa/attachable.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/abstract_channel.hpp"
namespace cppa { namespace detail {
class group_manager;
class peer_connection;
} } // namespace cppa::detail
namespace cppa {
#ifdef CPPA_DOCUMENTATION
class group;
class serializer;
class deserializer;
/**
* @brief Always points to the current actor. Similar to @c this in
* an object-oriented context.
* @brief A multicast group.
*/
extern local_actor* self;
class abstract_group : public abstract_channel {
#else // CPPA_DOCUMENTATION
friend class detail::group_manager;
friend class detail::peer_connection; // needs access to remote_enqueue
class local_actor;
public:
// convertible<...> enables "actor_ptr this_actor = self;"
class self_type : public convertible<self_type, actor*>,
public convertible<self_type, channel*> {
class subscription;
self_type(const self_type&) = delete;
self_type& operator=(const self_type&) = delete;
// needs access to unsubscribe()
friend class subscription;
public:
// unsubscribes its channel from the group on destruction
class subscription {
typedef local_actor* pointer;
friend class abstract_group;
constexpr self_type() { }
subscription(const subscription&) = delete;
subscription& operator=(const subscription&) = delete;
// "inherited" from convertible<...>
inline actor* do_convert() const {
return convert_impl();
}
public:
inline pointer get() const {
return get_impl();
}
subscription() = default;
subscription(subscription&&) = default;
subscription(const channel& s, const intrusive_ptr<abstract_group>& g);
// allow "self" wherever an local_actor or actor pointer is expected
inline operator pointer() const {
return get_impl();
}
~subscription();
inline pointer operator->() const {
return get_impl();
}
inline bool valid() const { return (m_subscriber) && (m_group); }
// @pre get_unchecked() == nullptr
inline void set(pointer ptr) const {
set_impl(ptr);
}
private:
// @returns The current value without converting the calling context
// to an actor on-the-fly.
inline pointer unchecked() const {
return get_unchecked_impl();
}
channel m_subscriber;
intrusive_ptr<abstract_group> m_group;
inline pointer release() const {
return release_impl();
}
};
inline void adopt(pointer ptr) const {
adopt_impl(ptr);
}
/**
* @brief Module interface.
*/
class module {
static void cleanup_fun(pointer);
std::string m_name;
private:
protected:
static void set_impl(pointer);
module(std::string module_name);
static pointer get_unchecked_impl();
public:
static pointer get_impl();
/**
* @brief Get the name of this module implementation.
* @returns The name of this module implementation.
* @threadsafe
*/
const std::string& name();
static actor* convert_impl();
/**
* @brief Get a pointer to the group associated with
* the name @p group_name.
* @threadsafe
*/
virtual group get(const std::string& group_name) = 0;
static pointer release_impl();
virtual group deserialize(deserializer* source) = 0;
static void adopt_impl(pointer);
};
};
typedef module* module_ptr;
typedef std::unique_ptr<module> unique_module_ptr;
virtual void serialize(serializer* sink) = 0;
/*
* "self" emulates a new keyword. The object itself is useless, all it does
* is to provide syntactic sugar like "self->trap_exit(true)".
/**
* @brief A string representation of the group identifier.
* @returns The group identifier as string (e.g. "224.0.0.1" for IPv4
* multicast or a user-defined string for local groups).
*/
constexpr self_type self;
const std::string& identifier() const;
class scoped_self_setter {
module_ptr get_module() const;
scoped_self_setter(const scoped_self_setter&) = delete;
scoped_self_setter& operator=(const scoped_self_setter&) = delete;
/**
* @brief The name of the module.
* @returns The module name of this group (e.g. "local").
*/
const std::string& module_name() const;
public:
/**
* @brief Subscribe @p who to this group.
* @returns A {@link subscription} object that unsubscribes @p who
* if the lifetime of @p who ends.
*/
virtual subscription subscribe(const channel& who) = 0;
inline scoped_self_setter(local_actor* new_value) {
m_original_value = self.release();
self.adopt(new_value);
}
protected:
inline ~scoped_self_setter() {
// restore self
static_cast<void>(self.release());
self.adopt(m_original_value);
}
abstract_group(module_ptr module, std::string group_id);
private:
virtual void unsubscribe(const channel& who) = 0;
local_actor* m_original_value;
module_ptr m_module;
std::string m_identifier;
};
// disambiguation (compiler gets confused with cast operator otherwise)
bool operator==(const actor_ptr& lhs, const self_type& rhs);
bool operator==(const self_type& lhs, const actor_ptr& rhs);
bool operator!=(const actor_ptr& lhs, const self_type& rhs);
bool operator!=(const self_type& lhs, const actor_ptr& rhs);
/**
* @brief A smart pointer type that manages instances of {@link group}.
* @relates group
*/
typedef intrusive_ptr<abstract_group> abstract_group_ptr;
#endif // CPPA_DOCUMENTATION
/**
* @brief Makes *all* local groups accessible via network on address @p addr
* and @p port.
* @throws bind_failure
* @throws network_error
*/
void publish_local_groups(std::uint16_t port, const char* addr = nullptr);
} // namespace cppa
#endif // CPPA_SELF_HPP
#endif // CPPA_ABSTRACT_GROUP_HPP
......@@ -31,227 +31,165 @@
#ifndef CPPA_ACTOR_HPP
#define CPPA_ACTOR_HPP
#include <mutex>
#include <atomic>
#include <memory>
#include <vector>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <type_traits>
#include "cppa/group.hpp"
#include "cppa/channel.hpp"
#include "cppa/cppa_fwd.hpp"
#include "cppa/attachable.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/comparable.hpp"
#include "cppa/util/type_traits.hpp"
namespace cppa {
class actor;
class self_type;
class serializer;
class deserializer;
class actor_addr;
class actor_proxy;
class local_actor;
class blocking_actor;
class event_based_actor;
/**
* @brief A unique actor ID.
* @relates actor
*/
typedef std::uint32_t actor_id;
struct invalid_actor_addr_t;
/**
* @brief A smart pointer type that manages instances of {@link actor}.
* @relates actor
*/
typedef intrusive_ptr<actor> actor_ptr;
namespace io {
class broker;
} // namespace io
namespace opencl {
template <typename Signature>
class actor_facade;
} // namespace opencl
namespace detail {
class raw_access;
} // namespace detail
struct invalid_actor_t { constexpr invalid_actor_t() { } };
/**
* @brief Base class for all actor implementations.
* @brief Identifies an invalid {@link actor}.
* @relates actor
*/
class actor : public channel {
constexpr invalid_actor_t invalid_actor = invalid_actor_t{};
public:
template<typename T>
struct is_convertible_to_actor {
static constexpr bool value = std::is_base_of<io::broker, T>::value
|| std::is_base_of<actor_proxy, T>::value
|| std::is_base_of<blocking_actor, T>::value
|| std::is_base_of<event_based_actor, T>::value;
};
/**
* @brief Attaches @p ptr to this actor.
*
* The actor will call <tt>ptr->detach(...)</tt> on exit, or immediately
* if it already finished execution.
* @param ptr A callback object that's executed if the actor finishes
* execution.
* @returns @c true if @p ptr was successfully attached to the actor;
* otherwise (actor already exited) @p false.
* @warning The actor takes ownership of @p ptr.
*/
bool attach(attachable_ptr ptr);
template<typename T>
struct is_convertible_to_actor<opencl::actor_facade<T>> {
static constexpr bool value = true;
};
/**
* @brief Convenience function that attaches the functor
* or function @p f to this actor.
/**
* @brief Identifies an untyped actor.
*
* The actor executes <tt>f()</tt> on exit, or immediatley
* if it already finished execution.
* @param f A functor, function or lambda expression that's executed
* if the actor finishes execution.
* @returns @c true if @p f was successfully attached to the actor;
* otherwise (actor already exited) @p false.
* Can be used with derived types of {@link event_based_actor},
* {@link blocking_actor}, {@link actor_proxy}, or
* {@link io::broker}.
*/
template<typename F>
bool attach_functor(F&& f);
class actor : util::comparable<actor>
, util::comparable<actor, actor_addr>
, util::comparable<actor, invalid_actor_t>
, util::comparable<actor, invalid_actor_addr_t> {
/**
* @brief Detaches the first attached object that matches @p what.
*/
void detach(const attachable::token& what);
friend class local_actor;
friend class detail::raw_access;
/**
* @brief Links this actor to @p other.
* @param other Actor instance that whose execution is coupled to the
* execution of this Actor.
*/
virtual void link_to(const actor_ptr& other);
public:
/**
* @brief Unlinks this actor from @p other.
* @param other Linked Actor.
* @note Links are automatically removed if the actor finishes execution.
*/
virtual void unlink_from(const actor_ptr& other);
actor() = default;
/**
* @brief Establishes a link relation between this actor and @p other.
* @param other Actor instance that wants to link against this Actor.
* @returns @c true if this actor is running and added @p other to its
* list of linked actors; otherwise @c false.
*/
virtual bool establish_backlink(const actor_ptr& other);
actor(actor&&) = default;
/**
* @brief Removes a link relation between this actor and @p other.
* @param other Actor instance that wants to unlink from this Actor.
* @returns @c true if this actor is running and removed @p other
* from its list of linked actors; otherwise @c false.
*/
virtual bool remove_backlink(const actor_ptr& other);
actor(const actor&) = default;
/**
* @brief Gets an integer value that uniquely identifies this Actor in
* the process it's executed in.
* @returns The unique identifier of this actor.
*/
inline actor_id id() const;
template<typename T>
actor(intrusive_ptr<T> ptr,
typename std::enable_if<is_convertible_to_actor<T>::value>::type* = 0)
: m_ptr(std::move(ptr)) { }
/**
* @brief Checks if this actor is running on a remote node.
* @returns @c true if this actor represents a remote actor;
* otherwise @c false.
*/
inline bool is_proxy() const;
template<typename T>
actor(T* ptr,
typename std::enable_if<is_convertible_to_actor<T>::value>::type* = 0)
: m_ptr(ptr) { }
actor(const invalid_actor_t&);
protected:
actor& operator=(actor&&) = default;
actor();
actor& operator=(const actor&) = default;
actor(actor_id aid);
template<typename T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(intrusive_ptr<T> ptr) {
actor tmp{std::move(ptr)};
swap(tmp);
return *this;
}
/**
* @brief Should be overridden by subtypes and called upon termination.
* @note Default implementation sets 'exit_reason' accordingly.
* @note Overridden functions should always call super::cleanup().
*/
virtual void cleanup(std::uint32_t reason);
template<typename T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(T* ptr) {
actor tmp{ptr};
swap(tmp);
return *this;
}
/**
* @brief The default implementation for {@link link_to()}.
*/
bool link_to_impl(const actor_ptr& other);
actor& operator=(const invalid_actor_t&);
/**
* @brief The default implementation for {@link unlink_from()}.
*/
bool unlink_from_impl(const actor_ptr& other);
inline operator bool() const {
return static_cast<bool>(m_ptr);
}
/**
* @brief Returns the actor's exit reason of
* <tt>exit_reason::not_exited</tt> if it's still alive.
*/
inline std::uint32_t exit_reason() const;
inline bool operator!() const {
return !m_ptr;
}
/**
* @brief Returns <tt>exit_reason() != exit_reason::not_exited</tt>.
* @brief Returns a handle that grants access to
* actor operations such as enqueue.
*/
inline bool exited() const;
// cannot be changed after construction
const actor_id m_id;
inline abstract_actor* operator->() const {
return m_ptr.get();
}
// you're either a proxy or you're not
const bool m_is_proxy;
inline abstract_actor& operator*() const {
return *m_ptr;
}
private:
// initially exit_reason::not_exited
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exit_reason, m_attachables, and m_links
std::mutex m_mtx;
// links to other actors
std::vector<actor_ptr> m_links;
// attached functors that are executed on cleanup
std::vector<attachable_ptr> m_attachables;
};
// undocumented, because self_type is hidden in documentation
bool operator==(const actor_ptr&, const self_type&);
bool operator!=(const self_type&, const actor_ptr&);
intptr_t compare(const actor& other) const;
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
intptr_t compare(const actor_addr&) const;
inline std::uint32_t actor::id() const {
return m_id;
}
inline intptr_t compare(const invalid_actor_t&) const {
return m_ptr ? 1 : 0;
}
inline bool actor::is_proxy() const {
return m_is_proxy;
}
inline intptr_t compare(const invalid_actor_addr_t&) const {
return compare(invalid_actor);
}
inline std::uint32_t actor::exit_reason() const {
return m_exit_reason;
}
inline bool actor::exited() const {
return exit_reason() != exit_reason::not_exited;
}
template<class F>
struct functor_attachable : attachable {
/**
* @brief Queries the address of the stored actor.
*/
actor_addr address() const;
F m_functor;
private:
template<typename T>
inline functor_attachable(T&& arg) : m_functor(std::forward<T>(arg)) { }
void swap(actor& other);
void actor_exited(std::uint32_t reason) { m_functor(reason); }
actor(abstract_actor*);
bool matches(const attachable::token&) { return false; }
abstract_actor_ptr m_ptr;
};
template<typename F>
bool actor::attach_functor(F&& f) {
typedef typename util::rm_const_and_ref<F>::type f_type;
typedef functor_attachable<f_type> impl;
return attach(attachable_ptr{new impl(std::forward<F>(f))});
}
} // namespace cppa
#endif // CPPA_ACTOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_ADDR_HPP
#define CPPA_ACTOR_ADDR_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/comparable.hpp"
namespace cppa {
class actor;
class local_actor;
class actor_namespace;
namespace detail { class raw_access; }
/**
* @brief Identifies an invalid {@link actor_addr}.
* @relates actor_addr
*/
struct invalid_actor_addr_t { constexpr invalid_actor_addr_t() { } };
constexpr invalid_actor_addr_t invalid_actor_addr = invalid_actor_addr_t{};
/**
* @brief Stores the address of typed as well as untyped actors.
*/
class actor_addr : util::comparable<actor_addr>
, util::comparable<actor_addr, abstract_actor*>
, util::comparable<actor_addr, abstract_actor_ptr> {
friend class actor;
friend class abstract_actor;
friend class detail::raw_access;
public:
actor_addr() = default;
actor_addr(actor_addr&&) = default;
actor_addr(const actor_addr&) = default;
actor_addr& operator=(actor_addr&&) = default;
actor_addr& operator=(const actor_addr&) = default;
actor_addr(const invalid_actor_addr_t&);
actor_addr operator=(const invalid_actor_addr_t&);
inline explicit operator bool() const {
return static_cast<bool>(m_ptr);
}
inline bool operator!() const {
return !m_ptr;
}
intptr_t compare(const actor_addr& other) const;
intptr_t compare(const abstract_actor* other) const;
inline intptr_t compare(const abstract_actor_ptr& other) const {
return compare(other.get());
}
actor_id id() const;
const node_id& node() const;
/**
* @brief Returns whether this is an address of a
* remote actor.
*/
bool is_remote() const;
private:
explicit actor_addr(abstract_actor*);
abstract_actor_ptr m_ptr;
};
} // namespace cppa
#endif // CPPA_ACTOR_ADDR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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/extend.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
#include "cppa/detail/memory.hpp"
namespace cppa {
/**
* @brief Adds co-existing objects (companions) to a class,
* which serve as gateways, thereby enabling libcppa's message passing.
*/
template<typename Base>
class actor_companion_mixin : public Base {
typedef Base super;
public:
typedef std::unique_ptr<mailbox_element, detail::disposer> message_pointer;
template<typename... Ts>
actor_companion_mixin(Ts&&... args) : super(std::forward<Ts>(args)...) {
m_self.reset(detail::memory::create<companion>(this));
}
~actor_companion_mixin() {
m_self->disconnect();
}
/**
* @brief Returns a smart pointer to the companion object.
*/
inline actor_ptr as_actor() const { return m_self; }
protected:
/**
* @brief This callback is invoked by the companion object whenever a
* new messages arrives.
* @warning Implementation has to be thread-safe.
*/
virtual void new_message(message_pointer ptr) = 0;
/**
* @brief Defines the message handler.
* @note While the message handler is invoked, @p self will point
* to the companion object to enable function calls to send().
*/
template<typename... Ts>
void set_message_handler(Ts&&... args) {
m_message_handler = match_expr_convert(std::forward<Ts>(args)...);
}
/**
* @brief Invokes the message handler with @p msg.
* @note While the message handler is invoked, @p self will point
* to the companion object to enable function calls to send().
*/
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 local_actor {
friend class actor_companion_mixin;
typedef util::shared_spinlock lock_type;
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(exit_reason::normal);
}
void enqueue(const message_header& hdr, any_tuple msg) override {
using std::move;
util::shared_lock_guard<lock_type> guard(m_lock);
if (!m_parent) return;
message_pointer ptr;
ptr.reset(detail::memory::create<mailbox_element>(hdr, move(msg)));
m_parent->new_message(move(ptr));
}
bool initialized() const override { return true; }
void quit(std::uint32_t) override {
throw std::runtime_error("Using actor_companion_mixin::quit "
"is prohibited; use Qt's widget "
"management instead.");
}
void dequeue(behavior&) override {
throw_no_recv();
}
void dequeue_response(behavior&, message_id) override {
throw_no_recv();
}
void become_waiting_for(behavior, message_id) override {
throw_no_become();
}
protected:
void do_become(behavior&&, bool) override { throw_no_become(); }
private:
void throw_no_become() {
throw std::runtime_error("actor_companion_companion "
"does not support libcppa's "
"become() API");
}
void throw_no_recv() {
throw std::runtime_error("actor_companion_companion "
"does not support libcppa's "
"receive() API");
}
// guards access to m_parent
lock_type m_lock;
// set to nullptr if this companion became detached
actor_companion_mixin* m_parent;
};
// used as 'self' before calling message handler
intrusive_ptr<companion> m_self;
// user-defined message handler for incoming messages
partial_function m_message_handler;
};
} // namespace cppa
#endif // CPPA_ACTOR_COMPANION_MIXIN_HPP
......@@ -25,7 +25,7 @@
* *
* 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_NAMESPACE_HPP
......@@ -63,9 +63,9 @@ class actor_namespace {
inline void set_new_element_callback(new_element_callback fun);
void write(serializer* sink, const actor_ptr& ptr);
void write(serializer* sink, const actor_addr& ptr);
actor_ptr read(deserializer* source);
actor_addr read(deserializer* source);
/**
* @brief A map that stores weak actor proxy pointers by actor ids.
......@@ -81,13 +81,13 @@ class actor_namespace {
* @brief Returns the proxy instance identified by @p node and @p aid
* or @p nullptr if the actor is unknown.
*/
actor_ptr get(const node_id& node, actor_id aid);
actor_proxy_ptr get(const node_id& node, actor_id aid);
/**
* @brief Returns the proxy instance identified by @p node and @p aid
* or creates a new (default) proxy instance.
*/
actor_ptr get_or_put(node_id_ptr node, actor_id aid);
actor_proxy_ptr get_or_put(node_id_ptr node, actor_id aid);
/**
* @brief Stores @p proxy in the list of known actor proxies.
......
......@@ -28,68 +28,82 @@
\******************************************************************************/
#ifndef CPPA_TYPED_ACTOR_PTR_HPP
#define CPPA_TYPED_ACTOR_PTR_HPP
#ifndef CPPA_ACTOR_OSTREAM_HPP
#define CPPA_ACTOR_OSTREAM_HPP
#include "cppa/replies_to.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/detail/typed_actor_util.hpp"
#include "cppa/actor.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/to_string.hpp"
namespace cppa {
template<typename... Signatures>
class typed_actor_ptr {
class local_actor;
class scoped_actor;
class actor_ostream {
public:
typedef util::type_list<Signatures...> signatures;
typedef actor_ostream& (*fun_type)(actor_ostream&);
typed_actor_ptr() = default;
typed_actor_ptr(typed_actor_ptr&&) = default;
typed_actor_ptr(const typed_actor_ptr&) = default;
typed_actor_ptr& operator=(typed_actor_ptr&&) = default;
typed_actor_ptr& operator=(const typed_actor_ptr&) = default;
actor_ostream(actor_ostream&&) = default;
actor_ostream(const actor_ostream&) = default;
template<typename... Others>
typed_actor_ptr(typed_actor_ptr<Others...> other) {
set(std::move(other));
}
actor_ostream& operator=(actor_ostream&&) = default;
actor_ostream& operator=(const actor_ostream&) = default;
template<typename... Others>
typed_actor_ptr& operator=(typed_actor_ptr<Others...> other) {
set(std::move(other));
return *this;
}
explicit actor_ostream(local_actor* self);
actor_ostream& write(std::string arg);
/** @cond PRIVATE */
static typed_actor_ptr cast_from(actor_ptr from) {
return {std::move(from)};
actor_ostream& flush();
inline actor_ostream& operator<<(std::string arg) {
return write(move(arg));
}
const actor_ptr& type_erased() const { return m_ptr; }
actor_ptr& type_erased() { return m_ptr; }
/** @endcond */
private:
inline actor_ostream& operator<<(const any_tuple& arg) {
return write(cppa::to_string(arg));
}
typed_actor_ptr(actor_ptr ptr) : m_ptr(std::move(ptr)) { }
// disambiguate between conversion to string and to any_tuple
inline actor_ostream& operator<<(const char* arg) {
return *this << std::string{arg};
}
template<class ListA, class ListB>
inline void check_signatures() {
static_assert(util::tl_is_strict_subset<ListA, ListB>::value,
"'this' must be a strict subset of 'other'");
template<typename T>
inline typename std::enable_if<
!std::is_convertible<T, std::string>::value
&& !std::is_convertible<T, any_tuple>::value,
actor_ostream&
>::type
operator<<(T&& arg) {
return write(std::to_string(std::forward<T>(arg)));
}
template<typename... Others>
inline void set(typed_actor_ptr<Others...> other) {
check_signatures<signatures, util::type_list<Others...>>();
m_ptr = std::move(other.type_erased());
inline actor_ostream& operator<<(actor_ostream::fun_type f) {
return f(*this);
}
actor_ptr m_ptr;
private:
local_actor* m_self;
actor m_printer;
};
inline actor_ostream aout(local_actor* self) {
return actor_ostream{self};
}
actor_ostream aout(scoped_actor& self);
} // namespace cppa
#endif // CPPA_TYPED_ACTOR_PTR_HPP
namespace std {
// provide convenience overlaods for aout; implemented in logging.cpp
cppa::actor_ostream& endl(cppa::actor_ostream& o);
cppa::actor_ostream& flush(cppa::actor_ostream& o);
} // namespace std
#endif // CPPA_ACTOR_OSTREAM_HPP
......@@ -31,8 +31,9 @@
#ifndef CPPA_ACTOR_PROXY_HPP
#define CPPA_ACTOR_PROXY_HPP
#include "cppa/actor.hpp"
#include "cppa/extend.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/message_header.hpp"
#include "cppa/enable_weak_ptr.hpp"
#include "cppa/weak_intrusive_ptr.hpp"
......@@ -43,9 +44,9 @@ class actor_proxy_cache;
/**
* @brief Represents a remote actor.
* @extends actor
* @extends abstract_actor
*/
class actor_proxy : public extend<actor>::with<enable_weak_ptr> {
class actor_proxy : public extend<abstract_actor>::with<enable_weak_ptr> {
typedef combined_type super;
......@@ -55,12 +56,12 @@ class actor_proxy : public extend<actor>::with<enable_weak_ptr> {
* @brief Establishes a local link state that's not synchronized back
* to the remote instance.
*/
virtual void local_link_to(const intrusive_ptr<actor>& other) = 0;
virtual void local_link_to(const actor_addr& other) = 0;
/**
* @brief Removes a local link state.
*/
virtual void local_unlink_from(const actor_ptr& other) = 0;
virtual void local_unlink_from(const actor_addr& other) = 0;
/**
* @brief Delivers given message via this proxy instance.
......
......@@ -156,16 +156,29 @@ compound_member(const std::pair<GRes (Parent::*)() const,
return {gspair, new detail::default_uniform_type_info_impl<mtype>(args...)};
}
/**
* @brief Adds a new type mapping for @p T to the libcppa type system.
* @param args Members of @p T.
* @brief Adds a new type mapping for @p C to the libcppa type system.
* @tparam C A class that is default constructible, copy constructible,
* and comparable.
* @param arg First members of @p C.
* @param args Additional members of @p C.
* @warning @p announce is <b>not</b> thead safe!
*/
template<typename T, typename... Ts>
template<class C, typename... Ts>
inline const uniform_type_info* announce(const Ts&... args) {
auto ptr = new detail::default_uniform_type_info_impl<T>(args...);
return announce(typeid(T), std::unique_ptr<uniform_type_info>{ptr});
auto ptr = new detail::default_uniform_type_info_impl<C>(args...);
return announce(typeid(C), std::unique_ptr<uniform_type_info>{ptr});
}
/**
* @brief Adds a new type mapping for an empty or "tag" class.
* @tparam C A class without any member.
* @warning @p announce_tag is <b>not</b> thead safe!
*/
template<class C>
inline const uniform_type_info* announce_tag() {
auto ptr = new detail::empty_uniform_type_info_impl<C>();
return announce(typeid(C), std::unique_ptr<uniform_type_info>{ptr});
}
/**
......
......@@ -91,7 +91,7 @@ class any_tuple {
* @brief Creates a tuple from a set of values.
*/
template<typename T, typename... Ts>
any_tuple(T v0, Ts&&... vs)
explicit any_tuple(T v0, Ts&&... vs)
: m_vals(make_cow_tuple(std::move(v0), std::forward<Ts>(vs)...).vals()) { }
/**
......
......@@ -112,6 +112,10 @@ class behavior {
*/
behavior add_continuation(continuation_fun fun);
inline operator bool() const {
return static_cast<bool>(m_impl);
}
private:
impl_ptr m_impl;
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_BEHAVIOR_POLICY_HPP
#define CPPA_BEHAVIOR_POLICY_HPP
namespace cppa {
template<bool DiscardBehavior>
struct behavior_policy { static constexpr bool discard_old = DiscardBehavior; };
template<typename T>
struct is_behavior_policy : std::false_type { };
template<bool DiscardBehavior>
struct is_behavior_policy<behavior_policy<DiscardBehavior>> : std::true_type { };
typedef behavior_policy<false> keep_behavior_t;
typedef behavior_policy<true > discard_behavior_t;
/**
* @brief Policy tag that causes {@link event_based_actor::become} to
* discard the current behavior.
* @relates local_actor
*/
constexpr discard_behavior_t discard_behavior = discard_behavior_t{};
/**
* @brief Policy tag that causes {@link event_based_actor::become} to
* keep the current behavior available.
* @relates local_actor
*/
constexpr keep_behavior_t keep_behavior = keep_behavior_t{};
} // namespace cppa
#endif // CPPA_BEHAVIOR_POLICY_HPP
......@@ -28,146 +28,161 @@
\******************************************************************************/
#ifndef CPPA_STACKED_ACTOR_MIXIN_HPP
#define CPPA_STACKED_ACTOR_MIXIN_HPP
#ifndef CPPA_BEHAVIOR_STACK_BASED_HPP
#define CPPA_BEHAVIOR_STACK_BASED_HPP
#include <chrono>
#include <memory>
#include <functional>
#include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/util/dptr.hpp"
#include "cppa/message_id.hpp"
#include "cppa/single_timeout.hpp"
#include "cppa/typed_behavior.hpp"
#include "cppa/behavior_policy.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/detail/behavior_stack.hpp"
#include "cppa/detail/receive_policy.hpp"
namespace cppa {
/**
* @brief An actor that uses the blocking API of @p libcppa and thus needs
* its own stack.
*/
template<class Base, class Subtype>
class stacked : public Base {
template<class Base, class Subtype, class BehaviorType>
class behavior_stack_based_impl : public single_timeout<Base, Subtype> {
typedef single_timeout<Base, Subtype> super;
friend class detail::receive_policy;
friend class detail::behavior_stack;
public:
protected:
/**************************************************************************
* typedefs and constructor *
**************************************************************************/
typedef stacked combined_type;
typedef BehaviorType behavior_type;
public:
typedef behavior_stack_based_impl combined_type;
static constexpr auto receive_flag = detail::rp_nestable;
typedef response_handle<behavior_stack_based_impl,
any_tuple,
nonblocking_response_handle_tag>
response_handle_type;
void dequeue(behavior& bhvr) override {
++m_nested_count;
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr);
--m_nested_count;
check_quit();
}
template <typename... Ts>
behavior_stack_based_impl(Ts&&... vs) : super(std::forward<Ts>(vs)...) { }
void dequeue_response(behavior& bhvr, message_id request_id) override {
++m_nested_count;
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
--m_nested_count;
check_quit();
}
/**************************************************************************
* become() member function family *
**************************************************************************/
virtual void run() {
exec_behavior_stack();
if (m_behavior) m_behavior();
auto dthis = util::dptr<Subtype>(this);
auto rsn = dthis->planned_exit_reason();
dthis->cleanup(rsn == exit_reason::not_exited ? exit_reason::normal : rsn);
void become(behavior_type bhvr) {
do_become(std::move(bhvr), true);
}
inline void set_behavior(std::function<void()> fun) {
m_behavior = std::move(fun);
template<bool Discard>
void become(behavior_policy<Discard>, behavior_type bhvr) {
do_become(std::move(bhvr), Discard);
}
void exec_behavior_stack() override {
m_in_bhvr_loop = true;
auto dthis = util::dptr<Subtype>(this);
if (!stack_empty() && !m_nested_count) {
while (!stack_empty()) {
++m_nested_count;
dthis->m_bhvr_stack.exec(m_recv_policy, dthis);
--m_nested_count;
check_quit();
template<typename T, typename... Ts>
inline typename std::enable_if<
!is_behavior_policy<typename util::rm_const_and_ref<T>::type>::value,
void
>::type
become(T&& arg, Ts&&... args) {
do_become(behavior_type{std::forward<T>(arg),
std::forward<Ts>(args)...},
true);
}
template<bool Discard, typename... Ts>
void become(behavior_policy<Discard>, Ts&&... args) {
do_become(behavior_type{std::forward<Ts>(args)...}, Discard);
}
m_in_bhvr_loop = false;
inline void unbecome() {
m_bhvr_stack.pop_async_back();
}
protected:
/**************************************************************************
* convenience member function for stack manipulation *
**************************************************************************/
template<typename... Ts>
stacked(Ts&&... args) : Base(std::forward<Ts>(args)...)
, m_in_bhvr_loop(false)
, m_nested_count(0) { }
inline bool has_behavior() const {
return m_bhvr_stack.empty() == false;
}
void do_become(behavior&& bhvr, bool discard_old) override {
become_impl(std::move(bhvr), discard_old, message_id());
inline behavior& get_behavior() {
CPPA_REQUIRE(m_bhvr_stack.empty() == false);
return m_bhvr_stack.back();
}
void become_waiting_for(behavior bhvr, message_id mid) override {
become_impl(std::move(bhvr), false, mid);
optional<behavior&> sync_handler(message_id msg_id) override {
return m_bhvr_stack.sync_handler(msg_id);
}
virtual bool has_behavior() {
return static_cast<bool>(m_behavior)
|| !util::dptr<Subtype>(this)->m_bhvr_stack.empty();
inline void remove_handler(message_id mid) {
m_bhvr_stack.erase(mid);
}
std::function<void()> m_behavior;
detail::receive_policy m_recv_policy;
inline detail::behavior_stack& bhvr_stack() {
return m_bhvr_stack;
}
private:
inline bool stack_empty() {
return util::dptr<Subtype>(this)->m_bhvr_stack.empty();
}
void become_impl(behavior&& bhvr, bool discard_old, message_id mid) {
auto dthis = util::dptr<Subtype>(this);
void do_become(behavior_type bhvr, bool discard_old) {
if (discard_old) this->m_bhvr_stack.pop_async_back();
this->reset_timeout();
if (bhvr.timeout().valid()) {
dthis->reset_timeout();
dthis->request_timeout(bhvr.timeout());
}
if (!dthis->m_bhvr_stack.empty() && discard_old) {
dthis->m_bhvr_stack.pop_async_back();
this->request_timeout(bhvr.timeout());
}
dthis->m_bhvr_stack.push_back(std::move(bhvr), mid);
this->m_bhvr_stack.push_back(std::move(unbox(bhvr)));
}
void check_quit() {
// do nothing if other message handlers are still running
if (m_nested_count > 0) return;
auto dthis = util::dptr<Subtype>(this);
auto rsn = dthis->planned_exit_reason();
if (rsn != exit_reason::not_exited) {
dthis->on_exit();
if (stack_empty()) {
dthis->cleanup(rsn);
throw actor_exited(rsn);
static inline behavior& unbox(behavior& arg) {
return arg;
}
else {
dthis->planned_exit_reason(exit_reason::not_exited);
if (!m_in_bhvr_loop) exec_behavior_stack();
template<typename... Ts>
static inline behavior& unbox(typed_behavior<Ts...>& arg) {
return arg.unbox();
}
// utility for getting a pointer-to-derived-type
Subtype* dptr() {
return static_cast<Subtype*>(this);
}
// utility for getting a const pointer-to-derived-type
const Subtype* dptr() const {
return static_cast<const Subtype*>(this);
}
bool m_in_bhvr_loop;
size_t m_nested_count;
// allows actors to keep previous behaviors and enables unbecome()
detail::behavior_stack m_bhvr_stack;
};
/**
* @brief Mixin for actors using a stack-based message processing.
* @note This mixin implicitly includes {@link single_timeout}.
*/
template<class BehaviorType>
class behavior_stack_based {
public:
template<class Base, class Subtype>
class impl : public behavior_stack_based_impl<Base, Subtype, BehaviorType> {
typedef behavior_stack_based_impl<Base, Subtype, BehaviorType> super;
public:
typedef impl combined_type;
template<typename... Ts>
impl(Ts&&... args) : super(std::forward<Ts>(args)...) { }
};
};
} // namespace cppa
#endif // CPPA_STACKED_ACTOR_MIXIN_HPP
#endif // CPPA_BEHAVIOR_STACK_BASED_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_BLOCKING_UNTYPED_ACTOR_HPP
#define CPPA_BLOCKING_UNTYPED_ACTOR_HPP
#include "cppa/on.hpp"
#include "cppa/extend.hpp"
#include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/sync_sender.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/response_handle.hpp"
namespace cppa {
/**
* @brief A thread-mapped or context-switching actor using a blocking
* receive rather than a behavior-stack based message processing.
* @extends local_actor
*/
class blocking_actor
: public extend<local_actor, blocking_actor>::
with<mailbox_based,
sync_sender<blocking_response_handle_tag>::impl> {
public:
/**************************************************************************
* utility stuff and receive() member function family *
**************************************************************************/
typedef std::chrono::high_resolution_clock::time_point timeout_type;
struct receive_while_helper {
std::function<void(behavior&)> m_dq;
std::function<bool()> m_stmt;
template<typename... Ts>
void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0,
"operator() requires at least one argument");
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
while (m_stmt()) m_dq(bhvr);
}
};
template<typename T>
struct receive_for_helper {
std::function<void(behavior&)> m_dq;
T& begin;
T end;
template<typename... Ts>
void operator()(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
for ( ; begin != end; ++begin) m_dq(bhvr);
}
};
struct do_receive_helper {
std::function<void(behavior&)> m_dq;
behavior m_bhvr;
template<typename Statement>
void until(Statement stmt) {
do { m_dq(m_bhvr); }
while (stmt() == false);
}
};
/**
* @brief Dequeues the next message from the mailbox that
* is matched by given behavior.
*/
template<typename... Ts>
void receive(Ts&&... args) {
static_assert(sizeof...(Ts), "at least one argument required");
dequeue(match_expr_convert(std::forward<Ts>(args)...));
}
/**
* @brief Receives messages in an endless loop.
* Semantically equal to: <tt>for (;;) { receive(...); }</tt>
*/
template<typename... Ts>
void receive_loop(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
for (;;) dequeue(bhvr);
}
/**
* @brief Receives messages as in a range-based loop.
*
* Semantically equal to:
* <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_for(i, 10) (
* on(atom("get")) >> [&]() -> any_tuple { return {"result", i}; }
* );
* @endcode
* @param begin First value in range.
* @param end Last value in range (excluded).
* @returns A functor implementing the loop.
*/
template<typename T>
receive_for_helper<T> receive_for(T& begin, const T& end) {
return {make_dequeue_callback(), begin, end};
}
/**
* @brief Receives messages as long as @p stmt returns true.
*
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_while([&]() { return (++i <= 10); })
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* );
* @endcode
* @param stmt Lambda expression, functor or function returning a @c bool.
* @returns A functor implementing the loop.
*/
template<typename Statement>
receive_while_helper receive_while(Statement stmt) {
static_assert(std::is_same<bool, decltype(stmt())>::value,
"functor or function does not return a boolean");
return {make_dequeue_callback(), stmt};
}
/**
* @brief Receives messages until @p stmt returns true.
*
* Semantically equal to:
* <tt>do { receive(...); } while (stmt() == false);</tt>
*
* <b>Usage example:</b>
* @code
* int i = 0;
* do_receive
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* )
* .until([&]() { return (++i >= 10); };
* @endcode
* @param bhvr Denotes the actor's response the next incoming message.
* @returns A functor providing the @c until member function.
*/
template<typename... Ts>
do_receive_helper do_receive(Ts&&... args) {
return { make_dequeue_callback()
, match_expr_convert(std::forward<Ts>(args)...)};
}
optional<behavior&> sync_handler(message_id msg_id) override {
auto i = m_sync_handler.find(msg_id);
if (i != m_sync_handler.end()) return i->second;
return none;
}
/**
* @brief Blocks this actor until all other actors are done.
*/
void await_all_other_actors_done();
/**
* @brief Implements the actor's behavior.
*/
virtual void act() = 0;
/**
* @brief Unwinds the stack by throwing an actor_exited exception.
* @throws actor_exited
*/
virtual void quit(std::uint32_t reason = exit_reason::normal);
/** @cond PRIVATE */
// required from invoke_policy; unused in blocking actors
inline void remove_handler(message_id) { }
// required by receive() member function family
inline void dequeue(behavior&& bhvr) {
behavior tmp{std::move(bhvr)};
dequeue(tmp);
}
// required by receive() member function family
inline void dequeue(behavior& bhvr) {
dequeue_response(bhvr, message_id::invalid);
}
// implemented by detail::proper_actor
virtual void dequeue_response(behavior& bhvr, message_id mid) = 0;
/** @endcond */
private:
// helper function to implement receive_(for|while) and do_receive
std::function<void(behavior&)> make_dequeue_callback() {
return [=](behavior& bhvr) { dequeue(bhvr); };
}
std::map<message_id, behavior> m_sync_handler;
};
} // namespace cppa
#endif // CPPA_BLOCKING_UNTYPED_ACTOR_HPP
......@@ -31,69 +31,79 @@
#ifndef CPPA_CHANNEL_HPP
#define CPPA_CHANNEL_HPP
#include <cstddef>
#include <type_traits>
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_channel.hpp"
#include "cppa/util/comparable.hpp"
namespace cppa {
// forward declarations
class actor;
class group;
class any_tuple;
class message_header;
typedef intrusive_ptr<actor> actor_ptr;
struct invalid_actor_t;
struct invalid_group_t;
namespace detail { class raw_access; }
/**
* @brief Interface for all message receivers.
*
* This interface describes an entity that can receive messages
* and is implemented by {@link actor} and {@link group}.
* @brief A handle to instances of {@link abstract_channel}.
*/
class channel : public ref_counted {
class channel : util::comparable<channel>
, util::comparable<channel, actor>
, util::comparable<channel, abstract_channel*> {
friend class actor;
friend class group;
friend class detail::raw_access;
public:
/**
* @brief Enqueues @p msg to the list of received messages.
*/
virtual void enqueue(const message_header& hdr, any_tuple msg) = 0;
channel() = default;
channel(const actor&);
/**
* @brief Enqueues @p msg to the list of received messages and returns
* true if this is an scheduled actor that successfully changed
* its state to @p pending in response to the enqueue operation.
*/
virtual bool chained_enqueue(const message_header& hdr, any_tuple msg);
channel(const group&);
/**
* @brief Sets the state from @p pending to @p ready.
*/
virtual void unchain();
channel(const invalid_actor_t&);
protected:
channel(const invalid_group_t&);
virtual ~channel();
template<typename T>
channel(intrusive_ptr<T> ptr,
typename std::enable_if<
std::is_base_of<abstract_channel, T>::value
>::type* = 0)
: m_ptr(ptr) { }
};
channel(abstract_channel* ptr);
/**
* @brief A smart pointer type that manages instances of {@link channel}.
* @relates channel
*/
typedef intrusive_ptr<channel> channel_ptr;
inline explicit operator bool() const {
return static_cast<bool>(m_ptr);
}
/**
* @brief Convenience alias.
*/
template<typename T, typename R = void>
using enable_if_channel = std::enable_if<std::is_base_of<channel, T>::value, R>;
inline bool operator!() const {
return !m_ptr;
}
void enqueue(const message_header& hdr, any_tuple msg) const;
intptr_t compare(const channel& other) const;
intptr_t compare(const actor& other) const;
intptr_t compare(const abstract_channel* other) const;
static intptr_t compare(const abstract_channel* lhs,
const abstract_channel* rhs);
private:
intrusive_ptr<abstract_channel> m_ptr;
};
} // namespace cppa
......
......@@ -31,10 +31,6 @@
#ifndef CPPA_CONFIG_HPP
#define CPPA_CONFIG_HPP
// uncomment this line or use define CPPA_DISABLE_CONTEXT_SWITCHING using CMAKE
// if boost.context is not available on your platform
//#define CPPA_DISABLE_CONTEXT_SWITCHING
#if defined(__clang__)
# define CPPA_CLANG
# define CPPA_DEPRECATED __attribute__((__deprecated__))
......@@ -54,6 +50,10 @@
# endif
#elif defined(__linux__)
# define CPPA_LINUX
# include <linux/version.h>
# if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
# define CPPA_POLL_IMPL
# endif
#elif defined(WIN32)
# define CPPA_WINDOWS
#else
......@@ -80,7 +80,7 @@
CPPA_REQUIRE__(#stmt, __FILE__, __LINE__); \
}((void) 0)
#else // CPPA_DEBUG_MODE
#define CPPA_REQUIRE(unused) ((void) 0)
#define CPPA_REQUIRE(unused) static_cast<void>(0)
#endif // CPPA_DEBUG_MODE
#define CPPA_CRITICAL__(error, file, line) { \
......@@ -105,7 +105,6 @@ std::unique_ptr<T> create_unique(Args&&... args) {
return std::unique_ptr<T>{new T(std::forward<Args>(args)...)};
}
#ifdef CPPA_WINDOWS
typedef SOCKET native_socket_type;
typedef const char* socket_send_ptr;
......
......@@ -28,68 +28,64 @@
\******************************************************************************/
#ifndef CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#define CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#ifndef CONTINUE_HELPER_HPP
#define CONTINUE_HELPER_HPP
#include <stack>
#include <functional>
#include "cppa/config.hpp"
#include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/behavior_stack.hpp"
#include "cppa/detail/yield_interface.hpp"
#include "cppa/on.hpp"
#include "cppa/behavior.hpp"
#include "cppa/message_id.hpp"
namespace cppa {
class local_actor;
/**
* @brief Context-switching actor implementation.
* @extends scheduled_actor
* @brief Helper class to enable users to add continuations
* when dealing with synchronous sends.
*/
class context_switching_actor : public extend<scheduled_actor, context_switching_actor>::with<stacked> {
class continue_helper {
friend class detail::behavior_stack;
friend class detail::receive_policy;
public:
typedef combined_type super;
typedef int message_id_wrapper_tag;
public:
continue_helper(message_id mid, local_actor* self);
/**
* @brief Creates a context-switching actor running @p fun.
* @brief Adds a continuation to the synchronous message handler
* that is invoked if the response handler successfully returned.
* @param fun The continuation as functor object.
*/
context_switching_actor(std::function<void()> fun);
resume_result resume(util::fiber* from, actor_ptr& next_job);
scheduled_actor_type impl_type();
protected:
typedef std::chrono::high_resolution_clock::time_point timeout_type;
timeout_type init_timeout(const util::duration& rel_time);
mailbox_element* await_message();
template<typename F>
continue_helper& continue_with(F fun) {
return continue_with(behavior::continuation_fun{partial_function{
on(any_vals, arg_match) >> fun
}});
}
mailbox_element* await_message(const timeout_type& abs_time);
/**
* @brief Adds a continuation to the synchronous message handler
* that is invoked if the response handler successfully returned.
* @param fun The continuation as functor object.
*/
continue_helper& continue_with(behavior::continuation_fun fun);
inline mailbox_element* try_pop() {
return m_mailbox.try_pop();
/**
* @brief Returns the ID of the expected response message.
*/
message_id get_message_id() const {
return m_mid;
}
private:
// required by util::fiber
static void trampoline(void* _this);
// members
util::fiber m_fiber;
message_id m_mid;
local_actor* m_self;
};
} // namespace cppa
#endif // CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#endif // CONTINUE_HELPER_HPP
......@@ -37,7 +37,6 @@
#include <type_traits>
#include "cppa/get.hpp"
#include "cppa/actor.hpp"
#include "cppa/cow_ptr.hpp"
#include "cppa/ref_counted.hpp"
......
This diff is collapsed.
......@@ -39,15 +39,20 @@ namespace cppa {
class actor;
class group;
class channel;
class node_id;
class behavior;
class any_tuple;
class self_type;
class actor_addr;
class actor_proxy;
class scoped_actor;
class abstract_actor;
class abstract_group;
class blocking_actor;
class message_header;
class partial_function;
class uniform_type_info;
class event_based_actor;
class primitive_variant;
class node_id;
// structs
struct anything;
......@@ -62,9 +67,7 @@ template<typename> class intrusive_ptr;
template<typename> class weak_intrusive_ptr;
// intrusive pointer typedefs
typedef intrusive_ptr<actor> actor_ptr;
typedef intrusive_ptr<group> group_ptr;
typedef intrusive_ptr<channel> channel_ptr;
typedef intrusive_ptr<abstract_group> abstract_group_ptr;
typedef intrusive_ptr<actor_proxy> actor_proxy_ptr;
typedef intrusive_ptr<node_id> node_id_ptr;
......
......@@ -38,8 +38,8 @@
#include <cstdint>
#include <condition_variable>
#include "cppa/actor.hpp"
#include "cppa/attachable.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/detail/singleton_mixin.hpp"
......@@ -59,7 +59,7 @@ class actor_registry : public singleton_mixin<actor_registry> {
* exit reason. An entry with a nullptr means the actor has finished
* execution for given reason.
*/
typedef std::pair<actor_ptr, std::uint32_t> value_type;
typedef std::pair<abstract_actor_ptr, std::uint32_t> value_type;
/**
* @brief Returns the {nullptr, invalid_exit_reason}.
......@@ -67,11 +67,11 @@ class actor_registry : public singleton_mixin<actor_registry> {
value_type get_entry(actor_id key) const;
// return nullptr if the actor wasn't put *or* finished execution
inline actor_ptr get(actor_id key) const {
inline abstract_actor_ptr get(actor_id key) const {
return get_entry(key).first;
}
void put(actor_id key, const actor_ptr& value);
void put(actor_id key, const abstract_actor_ptr& value);
void erase(actor_id key, std::uint32_t reason);
......
......@@ -94,44 +94,6 @@ class behavior_stack
m_erased_elements.clear();
}
template<class Policy, class Client>
bool invoke(Policy& policy, Client* client, mailbox_element* node) {
CPPA_REQUIRE(!empty());
CPPA_REQUIRE(client != nullptr);
CPPA_REQUIRE(node != nullptr);
// use a copy of bhvr, because invoked behavior might change m_elements
auto id = m_elements.back().second;
auto bhvr = m_elements.back().first;
if (policy.invoke(client, node, bhvr, id)) {
bool repeat;
// try to match cached messages
do {
// remove synchronous response handler if needed
if (id.valid()) {
erase_if([id](const element_type& value) {
return id == value.second;
});
}
if (!empty()) {
id = m_elements.back().second;
bhvr = m_elements.back().first;
repeat = policy.invoke_from_cache(client, bhvr, id);
}
else repeat = false;
} while (repeat);
return true;
}
return false;
}
template<class Policy, class Client>
void exec(Policy& policy, Client* client) {
while (!empty()) {
invoke(policy, client, policy.fetch_message(client));
cleanup();
}
}
private:
std::vector<element_type> m_elements;
......
......@@ -457,16 +457,68 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
m_members.push_back(unique_uti(new result_type));
}
void serialize(const void* obj, serializer* s) const {
void serialize(const void* obj, serializer* s) const override {
for (auto& m : m_members) m->serialize(obj, s);
}
void deserialize(void* obj, deserializer* d) const {
void deserialize(void* obj, deserializer* d) const override {
for (auto& m : m_members) m->deserialize(obj, d);
}
};
template<typename T>
class empty_uniform_type_info_impl : public uniform_type_info {
public:
bool equals(const std::type_info& tinfo) const override {
return typeid(T) == tinfo;
}
const char* name() const override {
return m_name.c_str();
}
any_tuple as_any_tuple(void*) const override {
return make_any_tuple(T{});
}
void serialize(const void*, serializer*) const override {
// no members means: nothing to do
}
void deserialize(void*, deserializer*) const override {
// no members means: nothing to do
}
empty_uniform_type_info_impl() {
auto uname = detail::to_uniform_name<T>();
auto cname = detail::mapped_name_by_decorated_name(uname.c_str());
if (cname == uname.c_str()) m_name = std::move(uname);
else m_name = cname;
}
protected:
bool equals(const void*, const void*) const override {
return true;
}
void* new_instance(const void*) const override {
return new T();
}
void delete_instance(void* instance) const override {
delete reinterpret_cast<T*>(instance);
}
private:
std::string m_name;
};
} } // namespace detail
#endif // CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_EVENT_BASED_ACTOR_FACTORY_HPP
#define CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
#include <type_traits>
#include "cppa/scheduler.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/tdata.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/util/type_list.hpp"
namespace cppa { namespace detail {
template<typename InitFun, typename CleanupFun, typename... Members>
class event_based_actor_impl : public event_based_actor {
public:
template<typename... Ts>
event_based_actor_impl(InitFun fun, CleanupFun cfun, Ts&&... args)
: m_init(std::move(fun)), m_on_exit(std::move(cfun))
, m_members(std::forward<Ts>(args)...) { }
void init() { apply(m_init); }
void on_exit() override {
typedef typename util::get_callable_trait<CleanupFun>::arg_types arg_types;
std::integral_constant<size_t, util::tl_size<arg_types>::value> token;
on_exit_impl(m_on_exit, token);
}
private:
InitFun m_init;
CleanupFun m_on_exit;
tdata<Members...> m_members;
template<typename F>
void apply(F& f, typename std::add_pointer<Members>::type... args) {
f(args...);
}
template<typename F, typename... Ts>
void apply(F& f, Ts... args) {
apply(f, args..., &get_ref<sizeof...(Ts)>(m_members));
}
typedef std::integral_constant<size_t, 0> zero_t;
template<typename OnExit, typename Token>
typename std::enable_if<std::is_same<Token, zero_t>::value>::type
on_exit_impl(OnExit& fun, Token) {
fun();
}
template<typename OnExit, typename Token>
typename std::enable_if<std::is_same<Token, zero_t>::value == false>::type
on_exit_impl(OnExit& fun, Token) {
apply(fun);
}
};
template<typename InitFun, typename CleanupFun, typename... Members>
class event_based_actor_factory {
public:
typedef event_based_actor_impl<InitFun, CleanupFun, Members...> impl;
event_based_actor_factory(InitFun fun, CleanupFun cfun)
: m_init(std::move(fun)), m_on_exit(std::move(cfun)) { }
template<typename... Ts>
actor_ptr spawn(Ts&&... args) {
auto ptr = make_counted<impl>(m_init, m_on_exit, std::forward<Ts>(args)...);
return get_scheduler()->exec(no_spawn_options, ptr);
}
private:
InitFun m_init;
CleanupFun m_on_exit;
};
// event-based actor factory from type list
template<typename InitFun, typename CleanupFun, class TypeList>
struct ebaf_from_type_list;
template<typename InitFun, typename CleanupFun, typename... Ts>
struct ebaf_from_type_list<InitFun, CleanupFun, util::type_list<Ts...> > {
typedef event_based_actor_factory<InitFun, CleanupFun, Ts...> type;
};
template<typename Init, typename Cleanup>
struct ebaf_from_functor {
typedef typename util::get_callable_trait<Init>::arg_types arg_types;
typedef typename util::get_callable_trait<Cleanup>::arg_types arg_types2;
static_assert(util::tl_forall<arg_types, std::is_pointer>::value,
"First functor takes non-pointer arguments");
static_assert( std::is_same<arg_types, arg_types2>::value
|| util::tl_empty<arg_types2>::value,
"Second functor must provide either the same signature "
"as the first one or must take zero arguments");
typedef typename util::tl_map<arg_types, std::remove_pointer>::type mems;
typedef typename ebaf_from_type_list<Init, Cleanup, mems>::type type;
};
} } // namespace cppa::detail
#endif // CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
......@@ -28,81 +28,94 @@
\******************************************************************************/
#ifndef CPPA_RECEIVE_LOOP_HELPER_HPP
#define CPPA_RECEIVE_LOOP_HELPER_HPP
#ifndef CPPA_FUNCTOR_BASED_ACTOR_HPP
#define CPPA_FUNCTOR_BASED_ACTOR_HPP
#include <new>
#include <type_traits>
#include "cppa/self.hpp"
#include "cppa/behavior.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/event_based_actor.hpp"
namespace cppa { namespace detail {
template<typename Statement>
struct receive_while_helper {
Statement m_stmt;
template<typename S>
receive_while_helper(S&& stmt) : m_stmt(std::forward<S>(stmt)) { }
template<typename... Ts>
void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0,
"operator() requires at least one argument");
behavior tmp = match_expr_convert(std::forward<Ts>(args)...);
local_actor* sptr = self;
while (m_stmt()) sptr->dequeue(tmp);
}
};
template<typename T>
class receive_for_helper {
T& begin;
T end;
class functor_based_actor : public event_based_actor {
public:
receive_for_helper(T& first, const T& last) : begin(first), end(last) { }
typedef std::function<behavior(event_based_actor*)> make_behavior_fun;
template<typename... Ts>
void operator()(Ts&&... args) {
auto tmp = match_expr_convert(std::forward<Ts>(args)...);
local_actor* sptr = self;
for ( ; begin != end; ++begin) sptr->dequeue(tmp);
}
typedef std::function<void(event_based_actor*)> void_fun;
};
template<typename F, typename... Ts>
functor_based_actor(F f, Ts&&... vs) {
event_based_actor* dummy = nullptr;
create(dummy, f, std::forward<Ts>(vs)...);
}
class do_receive_helper {
behavior make_behavior() override;
behavior m_bhvr;
private:
public:
void create(event_based_actor*, void_fun);
inline do_receive_helper(behavior&& bhvr) : m_bhvr(std::move(bhvr)) { }
template<class Actor, typename F, typename... Ts>
auto create(Actor*, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_convertible<
decltype(f(std::forward<Ts>(vs)...)),
behavior
>::value
>::type {
auto fun = std::bind(f, std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor*) -> behavior { return fun(); };
}
do_receive_helper(do_receive_helper&&) = default;
template<class Actor, typename F, typename... Ts>
auto create(Actor* dummy, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_convertible<
decltype(f(dummy, std::forward<Ts>(vs)...)),
behavior
>::value
>::type {
auto fun = std::bind(f, std::placeholders::_1, std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor* self) -> behavior { return fun(self); };
}
template<typename Statement>
void until(Statement&& stmt) {
static_assert(std::is_same<bool, decltype(stmt())>::value,
"functor or function does not return a boolean");
local_actor* sptr = self;
do {
sptr->dequeue(m_bhvr);
template<class Actor, typename F, typename... Ts>
auto create(Actor*, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(std::forward<Ts>(vs)...)),
void
>::value
>::type {
std::function<void()> fun = std::bind(f, std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor*) -> behavior {
fun();
return behavior{};
};
}
while (stmt() == false);
template<class Actor, typename F, typename... Ts>
auto create(Actor* dummy, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(dummy, std::forward<Ts>(vs)...)),
void
>::value
>::type {
std::function<void(Actor*)> fun = std::bind(f, std::placeholders::_1,
std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor* self) -> behavior {
fun(self);
return behavior{};
};
}
make_behavior_fun m_make_behavior;
};
} } // namespace cppa::detail
#endif // CPPA_RECEIVE_LOOP_HELPER_HPP
#endif // CPPA_FUNCTOR_BASED_ACTOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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 FUNCTOR_BASED_BLOCKING_ACTOR_HPP
#define FUNCTOR_BASED_BLOCKING_ACTOR_HPP
#include "cppa/blocking_actor.hpp"
namespace cppa {
namespace detail {
class functor_based_blocking_actor : public blocking_actor {
public:
typedef std::function<void (blocking_actor*)> act_fun;
template<typename F, typename... Ts>
functor_based_blocking_actor(F f, Ts&&... vs) {
blocking_actor* dummy = nullptr;
create(dummy, f, std::forward<Ts>(vs)...);
}
protected:
void act() override;
private:
void create(blocking_actor*, act_fun);
template<class Actor, typename F, typename T0, typename... Ts>
auto create(Actor* dummy, F f, T0&& v0, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(dummy, std::forward<T0>(v0), std::forward<Ts>(vs)...)),
void
>::value
>::type {
create(dummy, std::bind(f, std::placeholders::_1,
std::forward<T0>(v0), std::forward<Ts>(vs)...));
}
template<class Actor, typename F, typename T0, typename... Ts>
auto create(Actor* dummy, F f, T0&& v0, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(std::forward<T0>(v0), std::forward<Ts>(vs)...)),
void
>::value
>::type {
std::function<void()> fun = std::bind(f, std::forward<T0>(v0),
std::forward<Ts>(vs)...);
create(dummy, [fun](Actor*) { fun(); });
}
act_fun m_act;
};
} // namespace detail
} // namespace cppa
#endif // FUNCTOR_BASED_BLOCKING_ACTOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_GET_BEHAVIOR_HPP
#define CPPA_GET_BEHAVIOR_HPP
#include <type_traits>
#include "cppa/util/call.hpp"
#include "cppa/util/int_list.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/detail/tdata.hpp"
#include "cppa/scheduled_actor.hpp"
namespace cppa { namespace detail {
// default: <true, false, F>
template<bool IsFunctionPtr, bool HasArguments, typename F, typename... Ts>
class ftor_behavior : public scheduled_actor {
F m_fun;
public:
ftor_behavior(F ptr) : m_fun(ptr) { }
virtual void act() { m_fun(); }
};
template<typename F, typename... Ts>
class ftor_behavior<true, true, F, Ts...> : public scheduled_actor {
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
F m_fun;
typedef typename tdata_from_type_list<
typename util::tl_map<util::type_list<Ts...>,
implicit_conversions>::type>::type
tdata_type;
tdata_type m_args;
public:
ftor_behavior(F ptr, const Ts&... args) : m_fun(ptr), m_args(args...) { }
virtual void act() {
util::apply_args(m_fun, m_args, util::get_indices(m_args));
}
};
template<typename F>
class ftor_behavior<false, false, F> : public scheduled_actor {
F m_fun;
public:
ftor_behavior(const F& arg) : m_fun(arg) { }
ftor_behavior(F&& arg) : m_fun(std::move(arg)) { }
virtual void act() { m_fun(); }
};
template<typename F, typename... Ts>
class ftor_behavior<false, true, F, Ts...> : public scheduled_actor {
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
F m_fun;
typedef typename tdata_from_type_list<
typename util::tl_map<util::type_list<Ts...>,
implicit_conversions>::type>::type
tdata_type;
tdata_type m_args;
public:
ftor_behavior(const F& f, const Ts&... args) : m_fun(f), m_args(args...) {
}
ftor_behavior(F&& f, const Ts&... args)
: m_fun(std::move(f)), m_args(args...) { }
virtual void act() {
util::apply_args(m_fun, m_args, util::get_indices(m_args));
}
};
template<typename R>
scheduled_actor* get_behavior(std::integral_constant<bool, true>, R (*fptr)()) {
static_assert(std::is_convertible<R, scheduled_actor*>::value == false,
"Spawning a function returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that function?");
return new ftor_behavior<true, false, R (*)()>(fptr);
}
template<typename F>
scheduled_actor* get_behavior(std::integral_constant<bool, false>, F&& ftor) {
static_assert(std::is_convertible<decltype(ftor()), scheduled_actor*>::value == false,
"Spawning a functor returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that functor?");
typedef typename util::rm_const_and_ref<F>::type ftype;
return new ftor_behavior<false, false, ftype>(std::forward<F>(ftor));
}
template<typename F, typename T, typename... Ts>
scheduled_actor* get_behavior(std::true_type, F fptr, const T& arg, const Ts&... args) {
static_assert(std::is_convertible<decltype(fptr(arg, args...)), scheduled_actor*>::value == false,
"Spawning a function returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that function?");
typedef ftor_behavior<true, true, F, T, Ts...> impl;
return new impl(fptr, arg, args...);
}
template<typename F, typename T, typename... Ts>
scheduled_actor* get_behavior(std::false_type, F ftor, const T& arg, const Ts&... args) {
static_assert(std::is_convertible<decltype(ftor(arg, args...)), scheduled_actor*>::value == false,
"Spawning a functor returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that functor?");
typedef typename util::rm_const_and_ref<F>::type ftype;
typedef ftor_behavior<false, true, ftype, T, Ts...> impl;
return new impl(std::forward<F>(ftor), arg, args...);
}
} } // namespace cppa::detail
#endif // CPPA_GET_BEHAVIOR_HPP
......@@ -35,7 +35,7 @@
#include <mutex>
#include <thread>
#include "cppa/group.hpp"
#include "cppa/abstract_group.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/detail/singleton_mixin.hpp"
......@@ -48,18 +48,18 @@ class group_manager : public singleton_mixin<group_manager> {
public:
intrusive_ptr<group> get(const std::string& module_name,
group get(const std::string& module_name,
const std::string& group_identifier);
intrusive_ptr<group> anonymous();
group anonymous();
void add_module(group::unique_module_ptr);
void add_module(abstract_group::unique_module_ptr);
group::module_ptr get_module(const std::string& module_name);
abstract_group::module_ptr get_module(const std::string& module_name);
private:
typedef std::map<std::string, group::unique_module_ptr> modules_map;
typedef std::map<std::string, abstract_group::unique_module_ptr> modules_map;
modules_map m_mmap;
std::mutex m_mmap_mtx;
......
......@@ -34,9 +34,6 @@
#include <string>
#include <type_traits>
#include "cppa/self.hpp"
#include "cppa/actor.hpp"
#include "cppa/util/type_traits.hpp"
namespace cppa { class local_actor; }
......@@ -76,10 +73,9 @@ struct implicit_conversions {
typedef typename util::replace_type<
subtype3,
actor_ptr,
std::is_convertible<T, actor*>,
std::is_convertible<T, local_actor*>,
std::is_same<self_type, T>
actor,
std::is_convertible<T, abstract_actor*>,
std::is_same<scoped_actor, T>
>::type
type;
......
This diff is collapsed.
......@@ -28,27 +28,49 @@
\******************************************************************************/
#include "cppa/detail/scheduled_actor_dummy.hpp"
#ifndef CPPA_RAW_ACCESS_HPP
#define CPPA_RAW_ACCESS_HPP
#include "cppa/actor.hpp"
#include "cppa/group.hpp"
#include "cppa/channel.hpp"
#include "cppa/actor_addr.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/abstract_group.hpp"
#include "cppa/abstract_channel.hpp"
namespace cppa { namespace detail {
scheduled_actor_dummy::scheduled_actor_dummy()
: scheduled_actor(actor_state::blocked, false) { }
class raw_access {
public:
static abstract_actor* get(const actor& hdl) {
return hdl.m_ptr.get();
}
static abstract_actor* get(const actor_addr& hdl) {
return hdl.m_ptr.get();
}
void scheduled_actor_dummy::enqueue(const message_header&, any_tuple) { }
void scheduled_actor_dummy::quit(std::uint32_t) { }
void scheduled_actor_dummy::dequeue(behavior&) { }
void scheduled_actor_dummy::dequeue_response(behavior&, message_id) { }
void scheduled_actor_dummy::do_become(behavior&&, bool) { }
void scheduled_actor_dummy::become_waiting_for(behavior, message_id) { }
bool scheduled_actor_dummy::has_behavior() { return false; }
static abstract_channel* get(const channel& hdl) {
return hdl.m_ptr.get();
}
resume_result scheduled_actor_dummy::resume(util::fiber*, actor_ptr&) {
return resume_result::actor_blocked;
}
static abstract_group* get(const group& hdl) {
return hdl.m_ptr.get();
}
scheduled_actor_type scheduled_actor_dummy::impl_type() {
return event_based_impl;
}
static actor unsafe_cast(abstract_actor* ptr) {
return {ptr};
}
static actor unsafe_cast(const actor_addr& hdl) {
return {get(hdl)};
}
};
} } // namespace cppa::detail
#endif // CPPA_RAW_ACCESS_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_DETAIL_RESPONSE_FUTURE_UTIL_HPP
#define CPPA_DETAIL_RESPONSE_FUTURE_UTIL_HPP
#include "cppa/on.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/system_messages.hpp"
#include "cppa/util/type_traits.hpp"
namespace cppa {
namespace detail {
template<typename Actor, typename... Fs>
behavior fs2bhvr(Actor* self, Fs... fs) {
auto handle_sync_timeout = [self]() -> match_hint {
self->handle_sync_timeout();
return match_hint::skip;
};
return behavior{
on<sync_timeout_msg>() >> handle_sync_timeout,
on<unit_t>() >> skip_message,
on<sync_exited_msg>() >> skip_message,
(on(any_vals, arg_match) >> std::move(fs))...
};
}
} // namespace detail
} // namespace cppa
#endif // CPPA_DETAIL_RESPONSE_FUTURE_UTIL_HPP
......@@ -33,29 +33,22 @@
#include <cstdint>
#include "cppa/atom.hpp"
#include "cppa/actor.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/mailbox_element.hpp"
namespace cppa {
class actor_addr;
class message_id;
class local_actor;
class mailbox_element;
} // namespace cppa
namespace cppa { namespace detail {
struct sync_request_bouncer {
std::uint32_t rsn;
constexpr sync_request_bouncer(std::uint32_t r)
: rsn(r == exit_reason::not_exited ? exit_reason::normal : r) { }
inline void operator()(const actor_ptr& sender, const message_id& mid) const {
CPPA_REQUIRE(rsn != exit_reason::not_exited);
if (mid.is_request() && sender != nullptr) {
sender->enqueue({nullptr, sender, mid.response_id()},
make_any_tuple(atom("EXITED"), rsn));
}
}
inline void operator()(const mailbox_element& e) const {
(*this)(e.sender, e.mid);
}
explicit sync_request_bouncer(std::uint32_t r);
void operator()(const actor_addr& sender, const message_id& mid) const;
void operator()(const mailbox_element& e) const;
};
} } // namespace cppa::detail
......
......@@ -33,10 +33,10 @@
#include <thread>
#include "cppa/resumable.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/util/producer_consumer_list.hpp"
#include "cppa/detail/scheduled_actor_dummy.hpp"
namespace cppa { namespace detail {
......@@ -46,8 +46,9 @@ class thread_pool_scheduler : public scheduler {
public:
using scheduler::init_callback;
using scheduler::void_function;
struct dummy : resumable {
resume_result resume(util::fiber*) override;
};
struct worker;
......@@ -59,24 +60,20 @@ class thread_pool_scheduler : public scheduler {
void destroy();
void enqueue(scheduled_actor* what);
local_actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr) override;
local_actor_ptr exec(spawn_options opts, init_callback init_cb, void_function f) override;
void enqueue(resumable* what) override;
private:
//typedef util::single_reader_queue<abstract_scheduled_actor> job_queue;
typedef util::producer_consumer_list<scheduled_actor> job_queue;
typedef util::producer_consumer_list<resumable> job_queue;
size_t m_num_threads;
job_queue m_queue;
scheduled_actor_dummy m_dummy;
dummy m_dummy;
std::thread m_supervisor;
static void worker_loop(worker*);
static void supervisor_loop(job_queue*, scheduled_actor*, size_t);
static void supervisor_loop(job_queue*, resumable*, size_t);
};
......
......@@ -43,6 +43,7 @@
#include "cppa/unit.hpp"
#include "cppa/none.hpp"
#include "cppa/node_id.hpp"
#include "cppa/system_messages.hpp"
#include "cppa/util/buffer.hpp"
#include "cppa/util/duration.hpp"
......@@ -60,16 +61,21 @@ namespace cppa { namespace detail {
// ordered according to demangled type name (see uniform_type_info_map.cpp)
using mapped_type_list = util::type_list<
bool,
actor,
actor_addr,
any_tuple,
atom_value,
actor_ptr,
channel_ptr,
group_ptr,
channel,
down_msg,
exit_msg,
group,
node_id_ptr,
io::accept_handle,
io::connection_handle,
message_header,
std::nullptr_t,
sync_exited_msg,
sync_timeout_msg,
timeout_msg,
unit_t,
util::buffer,
util::duration,
......
......@@ -28,52 +28,50 @@
\******************************************************************************/
#ifndef CPPA_ABSTRACT_EVENT_BASED_ACTOR_HPP
#define CPPA_ABSTRACT_EVENT_BASED_ACTOR_HPP
#ifndef CPPA_UNTYPED_ACTOR_HPP
#define CPPA_UNTYPED_ACTOR_HPP
#include <tuple>
#include <stack>
#include <memory>
#include <vector>
#include "cppa/config.hpp"
#include "cppa/on.hpp"
#include "cppa/extend.hpp"
#include "cppa/behavior.hpp"
#include "cppa/stackless.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/logging.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/sync_sender.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/behavior_stack_based.hpp"
#include "cppa/detail/response_handle_util.hpp"
namespace cppa {
/**
* @brief Base class for all event-based actor implementations.
* @extends scheduled_actor
* @brief A cooperatively scheduled, event-based actor implementation.
*
* This is the recommended base class for user-defined actors and is used
* implicitly when spawning functor-based actors without the
* {@link blocking_api} flag.
*
* @extends local_actor
*/
class event_based_actor : public extend<scheduled_actor>::with<stackless> {
friend class detail::receive_policy;
class event_based_actor : public extend<local_actor, event_based_actor>::
with<mailbox_based,
behavior_stack_based<behavior>::impl,
sync_sender<nonblocking_response_handle_tag>::impl> {
typedef combined_type super;
public:
resume_result resume(util::fiber*, actor_ptr&);
protected:
/**
* @brief Initializes the actor.
* @brief Returns the initial actor behavior.
*/
virtual void init() = 0;
virtual behavior make_behavior() = 0;
scheduled_actor_type impl_type();
static intrusive_ptr<event_based_actor> from(std::function<void()> fun);
protected:
event_based_actor(actor_state st = actor_state::blocked);
/**
* @brief Forwards the last received message to @p whom.
*/
void forward_to(const actor& whom);
};
} // namespace cppa
#endif // CPPA_ABSTRACT_EVENT_BASED_ACTOR_HPP
#endif // CPPA_UNTYPED_ACTOR_HPP
......@@ -51,8 +51,8 @@ struct extend_helper<D, B, M, Ms...> : extend_helper<D, M<B, D>, Ms...> { };
/**
* @brief Allows convenient definition of types using mixins.
* For example, @p extend<ar, T>::with<ob, fo> is an alias for
* @p fo<ob<ar, T>, T>.
* For example, "extend<ar, T>::with<ob, fo>" is an alias for
* "fo<ob<ar, T>, T>".
*
* Mixins in libcppa always have two template parameters: base type and
* derived type. This allows mixins to make use of the curiously recurring
......@@ -64,7 +64,7 @@ struct extend {
/**
* @brief Identifies the combined type.
*/
template<template<class, class> class... Mixins>
template<CPPA_MIXIN... Mixins>
using with = typename detail::extend_helper<Derived, Base, Mixins...>::type;
};
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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_FACTORY_HPP
#define CPPA_FACTORY_HPP
#include "cppa/detail/event_based_actor_factory.hpp"
namespace cppa { namespace factory {
void default_cleanup();
/**
* @brief Returns a factory for event-based actors using @p fun as
* implementation for {@link cppa::event_based_actor::init() init()}.
*
* @p fun must take pointer arguments only. The factory creates an event-based
* actor implementation with member variables according to the functor's
* signature, as shown in the example below.
*
* @code
* auto f = factory::event_based([](int* a, int* b) { ... });
* auto actor1 = f.spawn();
* auto actor2 = f.spawn(1);
* auto actor3 = f.spawn(1, 2);
* @endcode
*
* The arguments @p a and @p b will point to @p int member variables of the
* actor. All member variables are initialized using the default constructor
* unless an initial value is passed to @p spawn.
*/
template<typename InitFun>
inline typename detail::ebaf_from_functor<InitFun, void (*)()>::type
event_based(InitFun init) {
return {std::move(init), default_cleanup};
}
/**
* @brief Returns a factory for event-based actors using @p fun0 as
* implementation for {@link cppa::event_based_actor::init() init()}
* and @p fun1 as implementation for
* {@link cppa::event_based_actor::on_exit() on_exit()}.
*/
template<typename InitFun, typename OnExitFun>
inline typename detail::ebaf_from_functor<InitFun, OnExitFun>::type
event_based(InitFun init, OnExitFun on_exit) {
return {std::move(init), on_exit};
}
} } // namespace cppa::factory
#endif // CPPA_FACTORY_HPP
......@@ -31,129 +31,85 @@
#ifndef CPPA_GROUP_HPP
#define CPPA_GROUP_HPP
#include <string>
#include <memory>
#include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_group.hpp"
#include "cppa/channel.hpp"
#include "cppa/attachable.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/util/comparable.hpp"
#include "cppa/util/type_traits.hpp"
namespace cppa { namespace detail {
class group_manager;
class peer_connection;
namespace cppa {
} } // namespace cppa::detail
class channel;
class any_tuple;
class message_header;
namespace cppa {
struct invalid_group_t { constexpr invalid_group_t() { } };
class serializer;
class deserializer;
namespace detail {
class raw_access;
} // namespace detail
/**
* @brief A multicast group.
* @brief Identifies an invalid {@link group}.
* @relates group
*/
class group : public channel {
friend class detail::group_manager;
friend class detail::peer_connection; // needs access to remote_enqueue
constexpr invalid_group_t invalid_group = invalid_group_t{};
public:
class group : util::comparable<group>
, util::comparable<group, invalid_group_t> {
class subscription;
// needs access to unsubscribe()
friend class subscription;
// unsubscribes its channel from the group on destruction
class subscription {
friend class group;
subscription(const subscription&) = delete;
subscription& operator=(const subscription&) = delete;
friend class detail::raw_access;
public:
subscription() = default;
subscription(subscription&&) = default;
subscription(const channel_ptr& s, const intrusive_ptr<group>& g);
group() = default;
~subscription();
group(group&&) = default;
inline bool valid() const { return (m_subscriber) && (m_group); }
group(const group&) = default;
private:
group(const invalid_group_t&);
channel_ptr m_subscriber;
intrusive_ptr<group> m_group;
group& operator=(group&&) = default;
};
group& operator=(const group&) = default;
/**
* @brief Module interface.
*/
class module {
std::string m_name;
group& operator=(const invalid_group_t&);
protected:
group(intrusive_ptr<abstract_group> ptr);
module(std::string module_name);
public:
inline explicit operator bool() const {
return static_cast<bool>(m_ptr);
}
/**
* @brief Get the name of this module implementation.
* @returns The name of this module implementation.
* @threadsafe
*/
const std::string& name();
inline bool operator!() const {
return !static_cast<bool>(m_ptr);
}
/**
* @brief Get a pointer to the group associated with
* the name @p group_name.
* @threadsafe
* @brief Returns a handle that grants access to
* actor operations such as enqueue.
*/
virtual intrusive_ptr<group> get(const std::string& group_name) = 0;
inline abstract_group* operator->() const {
return m_ptr.get();
}
virtual intrusive_ptr<group> deserialize(deserializer* source) = 0;
inline abstract_group& operator*() const {
return *m_ptr;
}
};
intptr_t compare(const group& other) const;
typedef module* module_ptr;
typedef std::unique_ptr<module> unique_module_ptr;
virtual void serialize(serializer* sink) = 0;
/**
* @brief A string representation of the group identifier.
* @returns 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;
module_ptr get_module() const;
/**
* @brief The name of the module.
* @returns The module name of this group (e.g. "local").
*/
const std::string& module_name() const;
/**
* @brief Subscribe @p who to this group.
* @returns A {@link subscription} object that unsubscribes @p who
* if the lifetime of @p who ends.
*/
virtual subscription subscribe(const channel_ptr& who) = 0;
inline intptr_t compare(const invalid_actor_t&) const {
return m_ptr ? 1 : 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,
static group get(const std::string& module_name,
const std::string& group_identifier);
/**
......@@ -163,45 +119,27 @@ class group : public channel {
* of an anonymous group. Anonymous groups can be used whenever
* a set of actors wants to communicate using an exclusive channel.
*/
static intrusive_ptr<group> anonymous();
static group anonymous();
/**
* @brief Add a new group module to the libcppa group management.
* @threadsafe
*/
static void add_module(unique_module_ptr);
static void add_module(abstract_group::unique_module_ptr);
/**
* @brief Returns the module associated with @p module_name.
* @threadsafe
*/
static module_ptr get_module(const std::string& module_name);
protected:
static abstract_group::module_ptr get_module(const std::string& module_name);
group(module_ptr module, std::string group_id);
virtual void unsubscribe(const channel_ptr& who) = 0;
private:
module_ptr m_module;
std::string m_identifier;
abstract_group_ptr m_ptr;
};
/**
* @brief A smart pointer type that manages instances of {@link group}.
* @relates group
*/
typedef intrusive_ptr<group> group_ptr;
/**
* @brief Makes *all* local groups accessible via network on address @p addr
* and @p port.
* @throws bind_failure
* @throws network_error
*/
void publish_local_groups_at(std::uint16_t port, const char* addr = nullptr);
} // namespace cppa
#endif // CPPA_GROUP_HPP
This diff is collapsed.
......@@ -131,6 +131,12 @@ class middleman {
*/
virtual void del_acceptor(peer_acceptor* ptr) = 0;
/**
* @brief This callback is used by peer implementations to
* invoke cleanup code when disposed.
*/
virtual void del_peer(peer* ptr) = 0;
/**
* @brief Delivers a message to given node.
*/
......@@ -156,7 +162,8 @@ class middleman {
* to the event loop of the middleman.
* @note This member function is thread-safe.
*/
virtual void register_acceptor(const actor_ptr& pa, peer_acceptor* ptr) = 0;
virtual void register_acceptor(const actor_addr& pa,
peer_acceptor* ptr) = 0;
/**
* @brief Returns the namespace that contains all remote actors
......@@ -184,7 +191,6 @@ class middleman {
// the node id of this middleman
node_id_ptr m_node;
//
std::unique_ptr<middleman_event_handler> m_handler;
};
......
......@@ -107,6 +107,7 @@ class peer : public extend<continuable>::with<buffered_writing> {
default_message_queue_ptr m_queue;
inline default_message_queue& queue() {
CPPA_REQUIRE(m_queue != nullptr);
return *m_queue;
}
......@@ -123,18 +124,18 @@ class peer : public extend<continuable>::with<buffered_writing> {
type_lookup_table m_incoming_types;
type_lookup_table m_outgoing_types;
void monitor(const actor_ptr& sender, const node_id_ptr& node, actor_id aid);
void monitor(const actor_addr& sender, const node_id_ptr& node, actor_id aid);
void kill_proxy(const actor_ptr& sender, const node_id_ptr& node, actor_id aid, std::uint32_t reason);
void kill_proxy(const actor_addr& sender, const node_id_ptr& node, actor_id aid, std::uint32_t reason);
void link(const actor_ptr& sender, const actor_ptr& ptr);
void link(const actor_addr& sender, const actor_addr& ptr);
void unlink(const actor_ptr& sender, const actor_ptr& ptr);
void unlink(const actor_addr& sender, const actor_addr& ptr);
void deliver(const message_header& hdr, any_tuple msg);
inline void enqueue(const any_tuple& msg) {
enqueue({nullptr, nullptr}, msg);
enqueue({invalid_actor_addr, nullptr}, msg);
}
void enqueue_impl(const message_header& hdr, const any_tuple& msg);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -31,7 +31,7 @@
#ifndef OPTIONAL_VARIANT_HPP
#define OPTIONAL_VARIANT_HPP
#include <iosfwd>
#include <ostream>
#include <stdexcept>
#include <type_traits>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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