Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
c91bf3fc
Commit
c91bf3fc
authored
Dec 17, 2013
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
API refactoring
parent
3eee072f
Changes
96
Hide whitespace changes
Inline
Side-by-side
Showing
96 changed files
with
2496 additions
and
3199 deletions
+2496
-3199
CMakeLists.txt
CMakeLists.txt
+5
-4
cppa.files
cppa.files
+12
-12
cppa/abstract_actor.hpp
cppa/abstract_actor.hpp
+6
-6
cppa/actor.hpp
cppa/actor.hpp
+7
-1
cppa/actor_addr.hpp
cppa/actor_addr.hpp
+1
-1
cppa/actor_namespace.hpp
cppa/actor_namespace.hpp
+1
-1
cppa/behavior_stack_based.hpp
cppa/behavior_stack_based.hpp
+20
-51
cppa/blocking_actor.hpp
cppa/blocking_actor.hpp
+0
-239
cppa/blocking_untyped_actor.hpp
cppa/blocking_untyped_actor.hpp
+191
-4
cppa/channel.hpp
cppa/channel.hpp
+1
-1
cppa/cppa.hpp
cppa/cppa.hpp
+39
-29
cppa/detail/functor_based_actor.hpp
cppa/detail/functor_based_actor.hpp
+87
-0
cppa/detail/functor_based_blocking_actor.hpp
cppa/detail/functor_based_blocking_actor.hpp
+91
-0
cppa/detail/get_behavior.hpp
cppa/detail/get_behavior.hpp
+0
-168
cppa/detail/proper_actor.hpp
cppa/detail/proper_actor.hpp
+96
-48
cppa/detail/raw_access.hpp
cppa/detail/raw_access.hpp
+1
-1
cppa/detail/thread_pool_scheduler.hpp
cppa/detail/thread_pool_scheduler.hpp
+9
-12
cppa/extend.hpp
cppa/extend.hpp
+3
-3
cppa/io/broker.hpp
cppa/io/broker.hpp
+37
-11
cppa/local_actor.hpp
cppa/local_actor.hpp
+89
-32
cppa/mailbox_based.hpp
cppa/mailbox_based.hpp
+5
-5
cppa/match_expr.hpp
cppa/match_expr.hpp
+23
-23
cppa/message_future.hpp
cppa/message_future.hpp
+14
-21
cppa/opencl/actor_facade.hpp
cppa/opencl/actor_facade.hpp
+69
-89
cppa/policy.hpp
cppa/policy.hpp
+5
-1
cppa/policy/context_switching_resume.hpp
cppa/policy/context_switching_resume.hpp
+79
-47
cppa/policy/cooperative_scheduling.hpp
cppa/policy/cooperative_scheduling.hpp
+68
-4
cppa/policy/event_based_resume.hpp
cppa/policy/event_based_resume.hpp
+113
-138
cppa/policy/invoke_policy.hpp
cppa/policy/invoke_policy.hpp
+112
-111
cppa/policy/middleman_scheduling.hpp
cppa/policy/middleman_scheduling.hpp
+108
-0
cppa/policy/nestable_invoke.hpp
cppa/policy/nestable_invoke.hpp
+14
-108
cppa/policy/no_resume.hpp
cppa/policy/no_resume.hpp
+23
-126
cppa/policy/no_scheduling.hpp
cppa/policy/no_scheduling.hpp
+68
-14
cppa/policy/not_prioritizing.hpp
cppa/policy/not_prioritizing.hpp
+25
-18
cppa/policy/priority_policy.hpp
cppa/policy/priority_policy.hpp
+1
-1
cppa/policy/resume_policy.hpp
cppa/policy/resume_policy.hpp
+4
-7
cppa/policy/sequential_invoke.hpp
cppa/policy/sequential_invoke.hpp
+22
-20
cppa/resumable.hpp
cppa/resumable.hpp
+16
-48
cppa/sb_actor.hpp
cppa/sb_actor.hpp
+7
-7
cppa/scheduled_actor.hpp
cppa/scheduled_actor.hpp
+0
-160
cppa/scheduler.hpp
cppa/scheduler.hpp
+5
-28
cppa/scoped_actor.hpp
cppa/scoped_actor.hpp
+38
-114
cppa/spawn.hpp
cppa/spawn.hpp
+18
-23
cppa/spawn_options.hpp
cppa/spawn_options.hpp
+15
-0
cppa/to_string.hpp
cppa/to_string.hpp
+4
-0
cppa/typed_actor.hpp
cppa/typed_actor.hpp
+1
-1
cppa/typed_actor_base.hpp
cppa/typed_actor_base.hpp
+2
-2
cppa/untyped_actor.hpp
cppa/untyped_actor.hpp
+7
-80
examples/curl/curl_fuse.cpp
examples/curl/curl_fuse.cpp
+26
-25
examples/hello_world.cpp
examples/hello_world.cpp
+6
-6
examples/message_passing/calculator.cpp
examples/message_passing/calculator.cpp
+10
-11
examples/message_passing/dancing_kirby.cpp
examples/message_passing/dancing_kirby.cpp
+6
-6
examples/message_passing/dining_philosophers.cpp
examples/message_passing/dining_philosophers.cpp
+21
-21
examples/remote_actors/distributed_calculator.cpp
examples/remote_actors/distributed_calculator.cpp
+17
-17
examples/remote_actors/group_chat.cpp
examples/remote_actors/group_chat.cpp
+9
-9
examples/type_system/announce_1.cpp
examples/type_system/announce_1.cpp
+10
-8
examples/type_system/announce_2.cpp
examples/type_system/announce_2.cpp
+8
-5
examples/type_system/announce_3.cpp
examples/type_system/announce_3.cpp
+7
-4
examples/type_system/announce_4.cpp
examples/type_system/announce_4.cpp
+8
-5
examples/type_system/announce_5.cpp
examples/type_system/announce_5.cpp
+17
-13
src/actor.cpp
src/actor.cpp
+3
-1
src/actor_addr.cpp
src/actor_addr.cpp
+1
-1
src/actor_namespace.cpp
src/actor_namespace.cpp
+1
-1
src/blocking_untyped_actor.cpp
src/blocking_untyped_actor.cpp
+42
-0
src/broker.cpp
src/broker.cpp
+36
-41
src/common_actor_ops.cpp
src/common_actor_ops.cpp
+1
-1
src/context_switching_resume.cpp
src/context_switching_resume.cpp
+16
-4
src/event_based_resume.cpp
src/event_based_resume.cpp
+0
-198
src/functor_based_actor.cpp
src/functor_based_actor.cpp
+11
-19
src/functor_based_blocking_actor.cpp
src/functor_based_blocking_actor.cpp
+9
-16
src/group.cpp
src/group.cpp
+1
-1
src/group_manager.cpp
src/group_manager.cpp
+4
-5
src/local_actor.cpp
src/local_actor.cpp
+16
-32
src/logging.cpp
src/logging.cpp
+1
-1
src/middleman.cpp
src/middleman.cpp
+0
-4
src/resumable.cpp
src/resumable.cpp
+37
-0
src/scheduled_actor.cpp
src/scheduled_actor.cpp
+0
-132
src/scheduler.cpp
src/scheduler.cpp
+17
-25
src/scoped_actor.cpp
src/scoped_actor.cpp
+59
-0
src/singleton_manager.cpp
src/singleton_manager.cpp
+0
-1
src/sync_request_bouncer.cpp
src/sync_request_bouncer.cpp
+1
-1
src/thread_pool_scheduler.cpp
src/thread_pool_scheduler.cpp
+14
-112
src/untyped_actor.cpp
src/untyped_actor.cpp
+39
-0
unit_testing/ping_pong.cpp
unit_testing/ping_pong.cpp
+18
-18
unit_testing/ping_pong.hpp
unit_testing/ping_pong.hpp
+2
-2
unit_testing/test.hpp
unit_testing/test.hpp
+4
-0
unit_testing/test_atom.cpp
unit_testing/test_atom.cpp
+18
-6
unit_testing/test_broker.cpp
unit_testing/test_broker.cpp
+3
-2
unit_testing/test_local_group.cpp
unit_testing/test_local_group.cpp
+7
-6
unit_testing/test_remote_actor.cpp
unit_testing/test_remote_actor.cpp
+97
-91
unit_testing/test_serialization.cpp
unit_testing/test_serialization.cpp
+4
-110
unit_testing/test_spawn.cpp
unit_testing/test_spawn.cpp
+251
-340
unit_testing/test_sync_send.cpp
unit_testing/test_sync_send.cpp
+64
-70
unit_testing/test_tuple.cpp
unit_testing/test_tuple.cpp
+6
-5
unit_testing/test_typed_spawn.cpp
unit_testing/test_typed_spawn.cpp
+4
-1
unit_testing/test_uniform_type.cpp
unit_testing/test_uniform_type.cpp
+2
-2
No files found.
CMakeLists.txt
View file @
c91bf3fc
...
...
@@ -138,6 +138,7 @@ set(LIBCPPA_SRC
src/binary_serializer.cpp
src/broker.cpp
src/buffer.cpp
src/blocking_untyped_actor.cpp
src/channel.cpp
src/common_actor_ops.cpp
src/context_switching_resume.cpp
...
...
@@ -150,11 +151,12 @@ set(LIBCPPA_SRC
src/deserializer.cpp
src/duration.cpp
src/empty_tuple.cpp
src/event_based_resume.cpp
src/exception.cpp
src/exit_reason.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
...
...
@@ -178,11 +180,10 @@ 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/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp
src/scoped_actor.cpp
src/serializer.cpp
...
...
@@ -190,13 +191,13 @@ set(LIBCPPA_SRC
src/singleton_manager.cpp
src/string_serialization.cpp
src/sync_request_bouncer.cpp
src/thread_mapped_actor.cpp
src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp
src/type_lookup_table.cpp
src/unicast_network.cpp
src/uniform_type_info.cpp
src/uniform_type_info_map.cpp
src/untyped_actor.cpp
src/weak_ptr_anchor.cpp
src/yield_interface.cpp
)
...
...
cppa.files
View file @
c91bf3fc
...
...
@@ -13,7 +13,6 @@ cppa/attachable.hpp
cppa/behavior.hpp
cppa/binary_deserializer.hpp
cppa/binary_serializer.hpp
cppa/blocking_actor.hpp
cppa/blocking_untyped_actor.hpp
cppa/channel.hpp
cppa/common_actor_ops.hpp
...
...
@@ -37,7 +36,6 @@ cppa/detail/demangle.hpp
cppa/detail/disablable_delete.hpp
cppa/detail/empty_tuple.hpp
cppa/detail/fd_util.hpp
cppa/detail/get_behavior.hpp
cppa/detail/group_manager.hpp
cppa/detail/handle.hpp
cppa/detail/ieee_754.hpp
...
...
@@ -53,7 +51,6 @@ cppa/detail/projection.hpp
cppa/detail/pseudo_tuple.hpp
cppa/detail/ptype_to_type.hpp
cppa/detail/raw_access.hpp
cppa/detail/scheduled_actor_dummy.hpp
cppa/detail/serialize_tuple.hpp
cppa/detail/singleton_manager.hpp
cppa/detail/singleton_mixin.hpp
...
...
@@ -105,7 +102,6 @@ cppa/io/remote_actor_proxy.hpp
cppa/io/stream.hpp
cppa/local_actor.hpp
cppa/logging.hpp
cppa/mailbox_based.hpp
cppa/mailbox_element.hpp
cppa/match.hpp
cppa/match_expr.hpp
...
...
@@ -117,7 +113,6 @@ cppa/message_header.hpp
cppa/message_id.hpp
cppa/message_priority.hpp
cppa/node_id.hpp
cppa/nonblocking_actor.hpp
cppa/none.hpp
cppa/object.hpp
cppa/on.hpp
...
...
@@ -133,7 +128,7 @@ cppa/opt.hpp
cppa/optional.hpp
cppa/optional_variant.hpp
cppa/partial_function.hpp
cppa/policy/invoke_policy
_base
.hpp
cppa/policy/invoke_policy.hpp
cppa/policy/nestable_invoke.hpp
cppa/policy/prioritizing.hpp
cppa/policy/sequential_invoke.hpp
...
...
@@ -144,7 +139,6 @@ cppa/ref_counted.hpp
cppa/replies_to.hpp
cppa/response_handle.hpp
cppa/sb_actor.hpp
cppa/scheduled_actor.hpp
cppa/scheduler.hpp
cppa/scoped_actor.hpp
cppa/send.hpp
...
...
@@ -152,7 +146,6 @@ cppa/serializer.hpp
cppa/singletons.hpp
cppa/spawn.hpp
cppa/spawn_options.hpp
cppa/thread_mapped_actor.hpp
cppa/timeout_definition.hpp
cppa/to_string.hpp
cppa/tpartial_function.hpp
...
...
@@ -245,7 +238,6 @@ src/demangle.cpp
src/deserializer.cpp
src/duration.cpp
src/empty_tuple.cpp
src/event_based_resume.cpp
src/exception.cpp
src/exit_reason.cpp
src/factory.cpp
...
...
@@ -286,8 +278,6 @@ src/ref_counted.cpp
src/remote_actor_proxy.cpp
src/response_handle.cpp
src/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp
src/scoped_actor.cpp
src/send.cpp
...
...
@@ -296,7 +286,6 @@ src/shared_spinlock.cpp
src/singleton_manager.cpp
src/string_serialization.cpp
src/sync_request_bouncer.cpp
src/thread_mapped_actor.cpp
src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp
src/type_lookup_table.cpp
...
...
@@ -338,3 +327,14 @@ cppa/policy/resume_policy.hpp
cppa/policy/cooperative_scheduling.hpp
cppa/policy/scheduling_policy.hpp
cppa/policy/priority_policy.hpp
cppa/policy/not_prioritizing.hpp
cppa/detail/functor_based_blocking_actor.hpp
src/functor_based_actor.cpp
cppa/mailbox_based.hpp
cppa/behavior_stack_based.hpp
cppa/resumable.hpp
src/resumable.cpp
cppa/policy/middleman_scheduling.hpp
src/untyped_actor.cpp
src/functor_based_blocking_actor.cpp
src/blocking_untyped_actor.cpp
cppa/abstract_actor.hpp
View file @
c91bf3fc
...
...
@@ -143,6 +143,12 @@ class abstract_actor : public abstract_channel {
*/
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
;
protected:
abstract_actor
();
...
...
@@ -166,12 +172,6 @@ class abstract_actor : public abstract_channel {
*/
bool
unlink_from_impl
(
const
actor_addr
&
other
);
/**
* @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 <tt>exit_reason() != exit_reason::not_exited</tt>.
*/
...
...
cppa/actor.hpp
View file @
c91bf3fc
...
...
@@ -45,6 +45,10 @@ namespace cppa {
namespace
detail
{
class
raw_access
;
}
struct
invalid_actor_t
{
constexpr
invalid_actor_t
()
{
}
};
constexpr
invalid_actor_t
invalid_actor
=
invalid_actor_t
{};
/**
* @brief Identifies an untyped actor.
*/
...
...
@@ -65,6 +69,8 @@ class actor : util::comparable<actor> {
inline
bool
operator
!
()
const
;
actor
(
const
invalid_actor_t
&
);
void
enqueue
(
const
message_header
&
hdr
,
any_tuple
msg
)
const
;
inline
common_actor_ops
*
operator
->
()
const
{
...
...
@@ -89,7 +95,7 @@ inline actor::operator bool() const {
inline
bool
actor
::
operator
!
()
const
{
return
!
static_cast
<
bool
>
(
*
this
);
}
}
// namespace cppa
#endif // CPPA_ACTOR_HPP
cppa/actor_addr.hpp
View file @
c91bf3fc
...
...
@@ -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_ADDR_HPP
...
...
cppa/actor_namespace.hpp
View file @
c91bf3fc
...
...
@@ -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
...
...
cppa/
nonblocking_actor
.hpp
→
cppa/
behavior_stack_based
.hpp
View file @
c91bf3fc
...
...
@@ -28,12 +28,9 @@
\******************************************************************************/
#ifndef CPPA_
STACKLESS
_HPP
#define CPPA_
STACKLESS
_HPP
#ifndef CPPA_
BEHAVIOR_STACK_BASED
_HPP
#define CPPA_
BEHAVIOR_STACK_BASED
_HPP
#include "cppa/util/dptr.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/behavior_stack.hpp"
namespace
cppa
{
...
...
@@ -41,14 +38,14 @@ namespace cppa {
#ifdef CPPA_DOCUMENTATION
/**
* @brief Policy tag that causes {@link
event_bas
ed_actor::become} to
* @brief Policy tag that causes {@link
untyp
ed_actor::become} to
* discard the current behavior.
* @relates local_actor
*/
constexpr
auto
discard_behavior
;
/**
* @brief Policy tag that causes {@link
event_bas
ed_actor::become} to
* @brief Policy tag that causes {@link
untyp
ed_actor::become} to
* keep the current behavior available.
* @relates local_actor
*/
...
...
@@ -75,25 +72,14 @@ constexpr keep_behavior_t keep_behavior = keep_behavior_t{};
#endif
template
<
class
Base
,
class
Subtype
>
class
stackless
:
public
Base
{
protected:
typedef
stackless
combined_type
;
class
behavior_stack_based
:
public
Base
{
public:
template
<
typename
...
Ts
>
stackless
(
Ts
&&
...
args
)
:
Base
(
std
::
forward
<
Ts
>
(
args
)...)
{
}
typedef
behavior_stack_based
combined_type
;
static
constexpr
auto
receive_flag
=
detail
::
rp_sequential
;
bool
has_behavior
()
{
return
this
->
m_bhvr_stack
.
empty
()
==
false
;
}
void
unbecome
()
{
this
->
m_bhvr_stack
.
pop_async_back
();
inline
void
unbecome
()
{
m_bhvr_stack
.
pop_async_back
();
}
/**
...
...
@@ -110,49 +96,35 @@ class stackless : public Base {
std
::
forward
<
Ts
>
(
args
)...),
true
);
}
template
<
bool
Discard
,
typename
...
Ts
>
inline
void
become
(
behavior_policy
<
Discard
>
,
Ts
&&
...
args
)
{
do_become
(
match_expr_convert
(
std
::
forward
<
Ts
>
(
args
)...),
Discard
);
}
void
become_waiting_for
(
behavior
bhvr
,
message_id
mf
)
{
if
(
bhvr
.
timeout
().
valid
())
{
this
->
reset_timeout
();
this
->
request_timeout
(
bhvr
.
timeout
());
//FIXME
}
this
->
m_bhvr_stack
.
push_back
(
std
::
move
(
bhvr
),
mf
);
m_bhvr_stack
.
push_back
(
std
::
move
(
bhvr
),
mf
);
}
void
do_become
(
behavior
&&
bhvr
,
bool
discard_old
)
{
this
->
reset_timeout
();
this
->
request_timeout
(
bhvr
.
timeout
());
if
(
discard_old
)
this
->
m_bhvr_stack
.
pop_async_back
();
this
->
m_bhvr_stack
.
push_back
(
std
::
move
(
bhvr
));
if
(
discard_old
)
m_bhvr_stack
.
pop_async_back
();
m_bhvr_stack
.
push_back
(
std
::
move
(
bhvr
));
}
inline
bool
has_behavior
()
const
{
return
this
->
m_bhvr_stack
.
empty
()
==
false
;
return
m_bhvr_stack
.
empty
()
==
false
;
}
inline
behavior
&
get_behavior
()
{
CPPA_REQUIRE
(
this
->
m_bhvr_stack
.
empty
()
==
false
);
return
this
->
m_bhvr_stack
.
back
();
CPPA_REQUIRE
(
m_bhvr_stack
.
empty
()
==
false
);
return
m_bhvr_stack
.
back
();
}
inline
void
handle_timeout
(
behavior
&
bhvr
)
{
CPPA_REQUIRE
(
bhvr
.
timeout
().
valid
());
this
->
reset_timeout
();
bhvr
.
handle_timeout
();
if
(
this
->
m_bhvr_stack
.
empty
()
==
false
)
{
this
->
request_timeout
(
get_behavior
().
timeout
());
}
}
void
exec_bhvr_stack
()
{
while
(
!
m_bhvr_stack
.
empty
())
{
m_bhvr_stack
.
exec
(
m_recv_policy
,
util
::
dptr
<
Subtype
>
(
this
));
}
}
inline
detail
::
behavior_stack
&
bhvr_stack
()
{
...
...
@@ -168,11 +140,8 @@ class stackless : public Base {
// allows actors to keep previous behaviors and enables unbecome()
detail
::
behavior_stack
m_bhvr_stack
;
// used for message handling in subclasses
detail
::
receive_policy
m_recv_policy
;
};
}
// namespace cppa
#endif // CPPA_
STACKLESS
_HPP
#endif // CPPA_
BEHAVIOR_STACK_BASED
_HPP
cppa/blocking_actor.hpp
deleted
100644 → 0
View file @
3eee072f
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_STACKED_ACTOR_MIXIN_HPP
#define CPPA_STACKED_ACTOR_MIXIN_HPP
#include <chrono>
#include <memory>
#include <functional>
#include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_element.hpp"
namespace
cppa
{
class
blocking_actor
:
public
local_actor
{
friend
class
detail
::
receive_policy
;
friend
class
detail
::
behavior_stack
;
protected:
typedef
stacked
combined_type
;
public:
static
constexpr
auto
receive_flag
=
detail
::
rp_nestable
;
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
),
"receive() requires at least one argument"
);
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
)...)};
}
virtual
void
run
()
{
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
);
}
inline
void
set_behavior
(
std
::
function
<
void
()
>
fun
)
{
m_behavior
=
std
::
move
(
fun
);
}
inline
optional
<
behavior
&>
sync_handler
(
message_id
msg_id
)
{
auto
i
=
m_sync_handler
.
find
(
msg_id
);
if
(
i
!=
m_sync_handler
.
end
())
return
i
->
second
;
return
none
;
}
protected:
template
<
typename
...
Ts
>
stacked
(
Ts
&&
...
args
)
:
Base
(
std
::
forward
<
Ts
>
(
args
)...)
{
}
virtual
bool
has_behavior
()
{
return
static_cast
<
bool
>
(
m_behavior
);
}
std
::
function
<
void
()
>
m_behavior
;
detail
::
receive_policy
m_recv_policy
;
private:
std
::
map
<
message_id
,
behavior
>
m_sync_handler
;
std
::
function
<
void
(
behavior
&
)
>
make_dequeue_callback
()
{
return
[
=
](
behavior
&
bhvr
)
{
dequeue
(
bhvr
);
};
}
void
dequeue
(
behavior
&
bhvr
)
{
m_recv_policy
.
receive
(
util
::
dptr
<
Subtype
>
(
this
),
bhvr
);
}
void
dequeue_response
(
behavior
&
bhvr
,
message_id
request_id
)
{
m_recv_policy
.
receive
(
util
::
dptr
<
Subtype
>
(
this
),
bhvr
,
request_id
);
}
};
}
// namespace cppa
#endif // CPPA_STACKED_ACTOR_MIXIN_HPP
cppa/blocking_untyped_actor.hpp
View file @
c91bf3fc
...
...
@@ -25,23 +25,210 @@
* *
* 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/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
namespace
cppa
{
/**
* @extends local_actor
*/
class
blocking_untyped_actor
:
public
extend
<
local_actor
>::
with
<
stacked
>
{
class
blocking_untyped_actor
:
public
extend
<
local_actor
>::
with
<
mailbox_based
>
{
public:
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
),
"receive() requires at least one argument"
);
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 Handles a synchronous response message in an event-based way.
* @param handle A future for a synchronous response.
* @throws std::logic_error if @p handle is not valid or if the actor
* already received the response for @p handle
* @relates message_future
*/
inline
sync_receive_helper
receive_response
(
const
message_future
&
f
)
{
return
{
f
};
}
/**
* @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
)...)};
}
inline
optional
<
behavior
&>
sync_handler
(
message_id
msg_id
)
{
auto
i
=
m_sync_handler
.
find
(
msg_id
);
if
(
i
!=
m_sync_handler
.
end
())
return
i
->
second
;
return
none
;
}
inline
void
dequeue
(
behavior
&&
bhvr
)
{
behavior
tmp
{
std
::
move
(
bhvr
)};
dequeue
(
tmp
);
}
virtual
void
dequeue
(
behavior
&
bhvr
)
=
0
;
virtual
mailbox_element
*
dequeue
()
=
0
;
virtual
mailbox_element
*
try_dequeue
()
=
0
;
virtual
mailbox_element
*
try_dequeue
(
const
timeout_type
&
)
=
0
;
void
await_all_other_actors_done
();
virtual
void
act
()
=
0
;
private:
std
::
map
<
message_id
,
behavior
>
m_sync_handler
;
std
::
function
<
void
(
behavior
&
)
>
make_dequeue_callback
()
{
return
[
=
](
behavior
&
bhvr
)
{
dequeue
(
bhvr
);
};
}
/*
void dequeue_response(behavior& bhvr, message_id request_id) {
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
}
*/
};
}
// namespace cppa
...
...
cppa/channel.hpp
View file @
c91bf3fc
...
...
@@ -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_CHANNEL_HPP
...
...
cppa/cppa.hpp
View file @
c91bf3fc
...
...
@@ -46,7 +46,6 @@
#include "cppa/behavior.hpp"
#include "cppa/announce.hpp"
#include "cppa/sb_actor.hpp"
#include "cppa/threaded.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/to_string.hpp"
#include "cppa/any_tuple.hpp"
...
...
@@ -56,14 +55,12 @@
#include "cppa/typed_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/
prioritizing
.hpp"
#include "cppa/
scoped_actor
.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/untyped_actor.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/message_future.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/blocking_untyped_actor.hpp"
#include "cppa/util/type_traits.hpp"
...
...
@@ -79,7 +76,6 @@
#include "cppa/io/connection_handle.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/detail/get_behavior.hpp"
#include "cppa/detail/actor_registry.hpp"
/**
...
...
@@ -436,8 +432,7 @@
namespace
cppa
{
template
<
typename
...
Ts
>
void
send_tuple_as
(
const
actor
&
from
,
const
channel
&
to
,
any_tuple
msg
)
{
inline
void
send_tuple_as
(
const
actor
&
from
,
const
channel
&
to
,
any_tuple
msg
)
{
to
.
enqueue
({
from
->
address
(),
to
},
std
::
move
(
msg
));
}
...
...
@@ -450,6 +445,23 @@ template<typename... Ts>
void
send_as
(
const
actor
&
from
,
const
channel
&
to
,
Ts
&&
...
args
)
{
send_tuple_as
(
from
,
to
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
args
)...));
}
inline
void
anon_send_tuple
(
const
channel
&
to
,
any_tuple
msg
)
{
to
.
enqueue
({
invalid_actor_addr
,
to
},
std
::
move
(
msg
));
}
/**
* @brief Anonymously sends a message to @p receiver;
*/
template
<
typename
...
Ts
>
inline
void
anon_send
(
const
channel
&
receiver
,
Ts
&&
...
args
)
{
anon_send_tuple
(
receiver
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
args
)...));
}
inline
void
anon_send_exit
(
const
actor_addr
&
,
std
::
uint32_t
)
{
}
/**
* @brief Blocks execution of this actor until all
* other actors finished execution.
...
...
@@ -517,10 +529,16 @@ template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor
spawn_io
(
io
::
input_stream_ptr
in
,
io
::
output_stream_ptr
out
,
Ts
&&
...
args
)
{
using
namespace
io
;
using
namespace
std
;
auto
ptr
=
make_counted
<
Impl
>
(
move
(
in
),
move
(
out
),
forward
<
Ts
>
(
args
)...);
return
eval_sopts
(
Options
,
io
::
init_and_launch
(
move
(
ptr
)));
using
namespace
policy
;
using
proper_impl
=
detail
::
proper_actor
<
Impl
,
middleman_scheduling
,
not_prioritizing
,
no_resume
,
cooperative_scheduling
>
;
auto
ptr
=
make_counted
<
proper_impl
>
(
std
::
move
(
in
),
std
::
move
(
out
),
std
::
forward
<
Ts
>
(
args
)...);
ptr
->
launch
();
return
ptr
;
}
/**
...
...
@@ -530,16 +548,12 @@ actor spawn_io(io::input_stream_ptr in,
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template
<
spawn_options
Options
=
no_spawn_options
,
typename
F
=
std
::
function
<
void
(
io
::
broker
*
)>,
typename
...
Ts
>
typename
F
=
std
::
function
<
void
(
io
::
broker
*
)>
>
actor
spawn_io
(
F
fun
,
io
::
input_stream_ptr
in
,
io
::
output_stream_ptr
out
,
Ts
&&
...
args
)
{
using
namespace
std
;
auto
ptr
=
io
::
broker
::
from
(
move
(
fun
),
move
(
in
),
move
(
out
),
forward
<
Ts
>
(
args
)...);
return
eval_sopts
(
Options
,
io
::
init_and_launch
(
move
(
ptr
)));
io
::
output_stream_ptr
out
)
{
return
spawn_io
<
io
::
default_broker
>
(
std
::
move
(
fun
),
std
::
move
(
in
),
std
::
move
(
out
));
}
/*
...
...
@@ -551,21 +565,17 @@ actor_ptr spawn_io(const char* host, uint16_t port, Ts&&... args) {
*/
template
<
spawn_options
Options
=
no_spawn_options
,
typename
F
=
std
::
function
<
void
(
io
::
broker
*
)>,
typename
...
Ts
>
actor
spawn_io
(
F
fun
,
const
std
::
string
&
host
,
uint16_t
port
,
Ts
&&
...
args
)
{
typename
F
=
std
::
function
<
void
(
io
::
broker
*
)>
>
actor
spawn_io
(
F
fun
,
const
std
::
string
&
host
,
uint16_t
port
)
{
auto
ptr
=
io
::
ipv4_io_stream
::
connect_to
(
host
.
c_str
(),
port
);
return
spawn_io
(
std
::
move
(
fun
),
ptr
,
ptr
,
std
::
forward
<
Ts
>
(
args
)...
);
return
spawn_io
(
std
::
move
(
fun
),
ptr
,
ptr
);
}
template
<
spawn_options
Options
=
no_spawn_options
,
typename
F
=
std
::
function
<
void
(
io
::
broker
*
)>,
typename
...
Ts
>
actor
spawn_io_server
(
F
fun
,
uint16_t
port
,
Ts
&&
...
args
)
{
typename
F
=
std
::
function
<
void
(
io
::
broker
*
)>
>
actor
spawn_io_server
(
F
fun
,
uint16_t
port
)
{
using
namespace
std
;
auto
ptr
=
io
::
broker
::
from
(
move
(
fun
),
io
::
ipv4_acceptor
::
create
(
port
),
forward
<
Ts
>
(
args
)...);
return
eval_sopts
(
Options
,
io
::
init_and_launch
(
move
(
ptr
)));
return
spawn_io
(
move
(
fun
),
io
::
ipv4_acceptor
::
create
(
port
));
}
/**
...
...
cppa/detail/functor_based_actor.hpp
View file @
c91bf3fc
...
...
@@ -31,13 +31,100 @@
#ifndef CPPA_FUNCTOR_BASED_ACTOR_HPP
#define CPPA_FUNCTOR_BASED_ACTOR_HPP
#include <type_traits>
#include "cppa/untyped_actor.hpp"
namespace
cppa
{
namespace
detail
{
class
functor_based_actor
:
public
untyped_actor
{
public:
typedef
std
::
function
<
behavior
(
untyped_actor
*
)
>
make_behavior_fun
;
typedef
std
::
function
<
void
(
untyped_actor
*
)
>
void_fun
;
template
<
typename
F
,
typename
...
Ts
>
functor_based_actor
(
F
f
,
Ts
&&
...
vs
)
{
untyped_actor
*
dummy
=
nullptr
;
create
(
dummy
,
f
,
std
::
forward
<
Ts
>
(
vs
)...);
}
behavior
make_behavior
()
override
;
private:
void
create
(
untyped_actor
*
,
void_fun
);
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
();
};
}
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
<
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
{};
};
}
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
{};
};
}
/*
template<class Actor, typename F, typename T0, typename... Ts>
void create(void*, F, T0&&, Ts&&...) {
// this overload acts as 'catch-all' rule to
// give the user a clear hint at what's wrong
// with the provided functor
static_assert(sizeof...(Ts) != sizeof...(Ts),
"spawn: provided functor must either return 'void'' "
"or 'cppa::behavior'");
}
*/
make_behavior_fun
m_make_behavior
;
};
...
...
cppa/detail/functor_based_blocking_actor.hpp
0 → 100644
View file @
c91bf3fc
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_untyped_actor.hpp"
namespace
cppa
{
namespace
detail
{
class
functor_based_blocking_actor
:
public
blocking_untyped_actor
{
public:
typedef
std
::
function
<
void
(
blocking_untyped_actor
*
)
>
act_fun
;
template
<
typename
F
,
typename
...
Ts
>
functor_based_blocking_actor
(
F
f
,
Ts
&&
...
vs
)
{
blocking_untyped_actor
*
dummy
=
nullptr
;
create
(
dummy
,
f
,
std
::
forward
<
Ts
>
(
vs
)...);
}
protected:
void
act
()
override
;
private:
void
create
(
blocking_untyped_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
cppa/detail/get_behavior.hpp
deleted
100644 → 0
View file @
3eee072f
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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
cppa/detail/proper_actor.hpp
View file @
c91bf3fc
...
...
@@ -3,37 +3,46 @@
#include <type_traits>
#include "cppa/
blocking_actor
.hpp"
#include "cppa/
resumable
.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/blocking_untyped_actor.hpp"
namespace
cppa
{
namespace
util
{
class
fiber
;
}
}
#include "cppa/util/duration.hpp"
namespace
cppa
{
namespace
detail
{
namespace
cppa
{
namespace
util
{
struct
fiber
;
}
// namespace util
}
// namespace cppa
namespace
cppa
{
namespace
detail
{
template
<
class
Base
,
class
SchedulingPolicy
,
class
PriorityPolicy
,
class
ResumePolicy
,
class
InvokePolicy
,
bool
OverrideDequeue
=
std
::
is_base_of
<
blocking_actor
,
Base
>
::
value
>
class
proper_actor
:
public
Base
{
bool
OverrideDequeue
=
std
::
is_base_of
<
blocking_untyped_actor
,
Base
>
::
value
>
class
proper_actor
:
public
ResumePolicy
::
template
mixin
<
Base
>
{
friend
SchedulingPolicy
;
friend
PriorityPolicy
;
friend
ResumePolicy
;
friend
InvokePolicy
;
typedef
typename
ResumePolicy
::
template
mixin
<
Base
>
super
;
public:
template
<
typename
...
Ts
>
proper_actor
(
Ts
&&
...
args
)
:
Base
(
std
::
forward
<
Ts
>
(
args
)
)
{
}
template
<
typename
...
Ts
>
proper_actor
(
Ts
&&
...
args
)
:
super
(
std
::
forward
<
Ts
>
(
args
)...
)
{
}
void
enqueue
(
const
message_header
&
hdr
,
any_tuple
msg
)
override
{
m_scheduling_policy
.
enqueue
(
this
,
hdr
,
msg
);
}
void
resume
(
util
::
fiber
*
fb
)
override
{
m_resume_policy
.
resume
(
this
,
fb
);
}
inline
void
launch
()
{
m_scheduling_policy
.
launch
(
this
);
}
inline
void
launch
()
{
m_scheduling_policy
.
launch
(
this
);
}
inline
mailbox_element
*
next_message
()
{
return
m_priority_policy
.
next_message
(
this
);
...
...
@@ -44,74 +53,113 @@ class proper_actor : public Base {
}
// grant access to the actor's mailbox
Base
::
mailbox_type
&
mailbox
()
{
return
this
->
m_mailbox
;
typename
Base
::
mailbox_type
&
mailbox
()
{
return
this
->
m_mailbox
;
}
SchedulingPolicy
&
scheduling_policy
()
{
return
m_scheduling_policy
;
}
PriorityPolicy
&
priority_policy
()
{
return
m_priority_policy
;
}
ResumePolicy
&
resume_policy
()
{
return
m_resume_policy
;
}
InvokePolicy
&
invoke_policy
()
{
return
m_invoke_policy
;
}
inline
void
push_timeout
()
{
m_scheduling_policy
.
push_timeout
();
}
inline
void
current_node
(
mailbox_element
*
ptr
)
{
this
->
m_current_node
=
ptr
;
}
inline
void
request_timeout
(
const
util
::
duration
&
rel_timeout
)
{
m_invoke_policy
.
request_timeout
(
this
,
rel_timeout
);
}
inline
mailbox_element
*
current_node
()
{
return
this
->
m_current_node
;
}
detail
::
behavior_stack
&
bhvr_stack
()
{
return
this
->
m_bhvr_stack
;
}
protected:
SchedulingPolicy
m_scheduling_policy
;
PriorityPolicy
m_priority_policy
;
ResumePolicy
m_resume_policy
;
InvokePolicy
m_invoke_policy
;
PriorityPolicy
m_priority_policy
;
ResumePolicy
m_resume_policy
;
InvokePolicy
m_invoke_policy
;
};
// for blocking actors, there's one more member function to implement
template
<
class
Base
,
class
SchedulingPolicy
,
class
PriorityPolicy
,
class
ResumePolicy
,
class
InvokePolicy
>
class
proper_actor
<
Base
,
SchedulingPolicy
,
PriorityPolicy
,
ResumePolicy
,
InvokePolicy
,
true
>
:
public
proper_actor
<
Base
,
SchedulingPolicy
,
PriorityPolicy
,
ResumePolicy
,
InvokePolicy
,
false
>
{
template
<
class
Base
,
class
SchedulingPolicy
,
class
PriorityPolicy
,
class
ResumePolicy
,
class
InvokePolicy
>
class
proper_actor
<
Base
,
SchedulingPolicy
,
PriorityPolicy
,
ResumePolicy
,
InvokePolicy
,
true
>
final
:
public
proper_actor
<
Base
,
SchedulingPolicy
,
PriorityPolicy
,
ResumePolicy
,
InvokePolicy
,
false
>
{
typedef
proper_actor
<
Base
,
SchedulingPolicy
,
PriorityPolicy
,
ResumePolicy
,
InvokePolicy
,
false
>
super
;
public:
template
<
typename
...
Ts
>
proper_actor
(
Ts
&&
...
args
)
:
super
(
std
::
forward
<
Ts
>
(
args
)...)
{
}
void
dequeue
(
behavior
&
bhvr
)
override
{
if
(
bhvr
.
timeout
().
valid
())
{
auto
abs_time
=
m_scheduling_policy
.
init_timeout
(
this
,
bhvr
.
timeout
());
auto
tout
=
this
->
m_scheduling_policy
.
init_timeout
(
this
,
bhvr
.
timeout
());
auto
done
=
false
;
while
(
!
done
)
{
if
(
!
m_resume_policy
.
await_data
(
this
,
abs_time
))
{
if
(
!
this
->
m_resume_policy
.
await_data
(
this
,
tout
))
{
bhvr
.
handle_timeout
();
done
=
true
;
}
else
{
auto
msg
=
m_priority_policy
.
next_message
(
this
);
}
else
{
auto
msg
=
this
->
m_priority_policy
.
next_message
(
this
);
// must not return nullptr, because await_data guarantees
// at least one message in our mailbox
CPPA_REQUIRE
(
msg
!=
nullptr
);
done
=
m_invoke_policy
.
invoke
(
this
,
bhvr
,
msg
);
done
=
this
->
m_invoke_policy
.
invoke
(
this
,
msg
,
bhvr
);
}
}
}
else
{
}
else
{
for
(;;)
{
auto
msg
=
m_priority_policy
.
next_message
(
this
);
auto
msg
=
this
->
m_priority_policy
.
next_message
(
this
);
while
(
msg
)
{
if
(
m_invoke_policy
.
invoke
(
this
,
bhvr
,
msg
))
{
if
(
this
->
m_invoke_policy
.
invoke
(
this
,
msg
,
bhvr
))
{
// we're done
return
;
}
msg
=
m_priority_policy
.
next_message
(
this
);
msg
=
this
->
m_priority_policy
.
next_message
(
this
);
}
m_resume_policy
.
await_data
(
this
);
this
->
m_resume_policy
.
await_data
(
this
);
}
}
}
mailbox_element
*
dequeue
()
override
{
auto
e
=
try_dequeue
();
if
(
!
e
)
{
this
->
m_resume_policy
.
await_data
(
this
);
return
try_dequeue
();
// guaranteed to succeed after await_data
}
return
e
;
}
mailbox_element
*
try_dequeue
()
override
{
return
this
->
m_priority_policy
.
next_message
(
this
);
}
mailbox_element
*
try_dequeue
(
const
typename
Base
::
timeout_type
&
tout
)
override
{
if
(
this
->
m_resume_policy
.
await_data
(
this
,
tout
))
{
return
try_dequeue
();
}
return
nullptr
;
}
};
}
}
// namespace cppa::detail
}
// namespace detail
}
// namespace cppa
#endif // PROPER_ACTOR_HPP
cppa/detail/raw_access.hpp
View file @
c91bf3fc
...
...
@@ -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_RAW_ACCESS_HPP
...
...
cppa/detail/thread_pool_scheduler.hpp
View file @
c91bf3fc
...
...
@@ -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
::
actor_fun
;
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
,
actor_fun
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
);
};
...
...
cppa/extend.hpp
View file @
c91bf3fc
...
...
@@ -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
;
};
...
...
cppa/io/broker.hpp
View file @
c91bf3fc
...
...
@@ -33,9 +33,9 @@
#include <map>
#include "cppa/stackless.hpp"
#include "cppa/threadless.hpp"
#include "cppa/extend.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/behavior_stack_based.hpp"
#include "cppa/util/buffer.hpp"
...
...
@@ -45,7 +45,10 @@
#include "cppa/io/accept_handle.hpp"
#include "cppa/io/connection_handle.hpp"
namespace
cppa
{
namespace
io
{
#include "cppa/policy/sequential_invoke.hpp"
namespace
cppa
{
namespace
io
{
class
broker
;
...
...
@@ -58,7 +61,9 @@ local_actor_ptr init_and_launch(broker_ptr);
* and other components in the network.
* @extends local_actor
*/
class
broker
:
public
extend
<
local_actor
>::
with
<
threadless
,
stackless
>
{
class
broker
:
public
extend
<
local_actor
>::
with
<
behavior_stack_based
>
{
friend
class
policy
::
sequential_invoke
;
typedef
combined_type
super
;
...
...
@@ -97,6 +102,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
void
write
(
const
connection_handle
&
hdl
,
util
::
buffer
&&
buf
);
/*
template<typename F, typename... Ts>
static broker_ptr from(F fun,
input_stream_ptr in,
...
...
@@ -121,6 +127,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
std::forward<Ts>(args)...),
std::move(in));
}
*/
template
<
typename
F
,
typename
...
Ts
>
actor
fork
(
F
fun
,
connection_handle
hdl
,
Ts
&&
...
args
)
{
...
...
@@ -154,14 +161,16 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
explicit
broker
(
scribe_pointer
);
virtual
behavior
make_behavior
()
=
0
;
private:
actor
_addr
fork_impl
(
std
::
function
<
void
(
broker
*
)
>
fun
,
connection_handle
hdl
);
actor
fork_impl
(
std
::
function
<
void
(
broker
*
)
>
fun
,
connection_handle
hdl
);
static
broker_ptr
from_impl
(
std
::
function
<
void
(
broker
*
)
>
fun
,
input_stream_ptr
in
,
output_stream_ptr
out
);
//
static broker_ptr from_impl(std::function<void (broker*)> fun,
//
input_stream_ptr in,
//
output_stream_ptr out);
void
invoke_message
(
const
message_header
&
hdr
,
any_tuple
msg
);
...
...
@@ -178,10 +187,27 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
std
::
map
<
accept_handle
,
doorman_pointer
>
m_accept
;
std
::
map
<
connection_handle
,
scribe_pointer
>
m_io
;
policy
::
sequential_invoke
m_invoke
;
};
//typedef intrusive_ptr<broker> broker_ptr;
class
default_broker
:
public
broker
{
public:
typedef
std
::
function
<
void
(
broker
*
)
>
function_type
;
default_broker
(
input_stream_ptr
in
,
output_stream_ptr
out
,
function_type
f
);
behavior
make_behavior
()
override
;
private:
function_type
m_fun
;
};
}
}
// namespace cppa::network
}
// namespace io
}
// namespace cppa
#endif // CPPA_BROKER_HPP
cppa/local_actor.hpp
View file @
c91bf3fc
...
...
@@ -31,6 +31,7 @@
#ifndef CPPA_CONTEXT_HPP
#define CPPA_CONTEXT_HPP
#include <atomic>
#include <cstdint>
#include <functional>
...
...
@@ -42,9 +43,10 @@
#include "cppa/any_tuple.hpp"
#include "cppa/message_id.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/
mailbox_based
.hpp"
#include "cppa/
spawn_options
.hpp"
#include "cppa/memory_cached.hpp"
#include "cppa/message_future.hpp"
#include "cppa/message_header.hpp"
...
...
@@ -58,6 +60,8 @@
#include "cppa/detail/behavior_stack.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace
cppa
{
// forward declarations
...
...
@@ -66,22 +70,69 @@ class message_future;
class
local_scheduler
;
class
sync_handle_helper
;
namespace
detail
{
class
receive_policy
;
}
namespace
util
{
struct
fiber
;
}
// namespace util
template
<
class
Impl
,
spawn_options
Options
=
no_spawn_options
,
typename
...
Ts
>
actor
spawn
(
Ts
&&
...
args
);
template
<
spawn_options
Options
=
no_spawn_options
,
typename
...
Ts
>
actor
spawn
(
Ts
&&
...
args
);
/**
* @brief Base class for local running Actors.
* @extends actor
*/
class
local_actor
:
public
extend
<
abstract_actor
>::
with
<
memory_cached
,
mailbox_based
>
{
friend
class
detail
::
receive_policy
;
class
local_actor
:
public
extend
<
abstract_actor
>::
with
<
memory_cached
>
{
typedef
combined_type
super
;
public:
typedef
detail
::
disposer
del
;
typedef
intrusive
::
single_reader_queue
<
mailbox_element
,
del
>
mailbox_type
;
~
local_actor
();
inline
actor
eval_opts
(
spawn_options
opts
,
actor
res
)
{
if
(
has_monitor_flag
(
opts
))
{
monitor
(
res
);
}
if
(
has_link_flag
(
opts
))
{
link_to
(
res
);
}
return
res
;
}
template
<
class
Impl
,
spawn_options
Options
=
no_spawn_options
,
typename
...
Ts
>
actor
spawn
(
Ts
&&
...
args
)
{
auto
res
=
cppa
::
spawn
<
Impl
,
make_unbound
(
Options
)
>
(
std
::
forward
<
Ts
>
(
args
)...);
return
eval_opts
(
Options
,
std
::
move
(
res
));
}
template
<
spawn_options
Options
=
no_spawn_options
,
typename
...
Ts
>
actor
spawn
(
Ts
&&
...
args
)
{
auto
res
=
cppa
::
spawn
<
make_unbound
(
Options
)
>
(
std
::
forward
<
Ts
>
(
args
)...);
return
eval_opts
(
Options
,
std
::
move
(
res
));
}
/**
* @brief Sends @p what to the receiver specified in @p dest.
*/
void
send_tuple
(
message_priority
prio
,
const
channel
&
dest
,
any_tuple
what
);
/**
* @brief Sends <tt>{what...}</tt> to the receiver specified in @p hdr.
* @pre <tt>sizeof...(Ts) > 0</tt>
*/
template
<
typename
...
Ts
>
void
send
(
message_priority
prio
,
const
channel
&
whom
,
Ts
&&
...
what
)
{
send_tuple
(
prio
,
whom
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
what
)...));
}
/**
* @brief Sends @p what to the receiver specified in @p dest.
*/
...
...
@@ -96,6 +147,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
send_tuple
(
whom
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
what
)...));
}
void
send_exit
(
const
actor_addr
&
whom
,
std
::
uint32_t
reason
);
/**
* @brief Sends @p what as a synchronous message to @p whom.
* @param whom Receiver of the message.
...
...
@@ -128,8 +181,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
}
template
<
typename
...
Ts
>
message_future
timed_sync_send
(
const
util
::
duration
&
rtime
,
const
actor
&
dest
,
message_future
timed_sync_send
(
const
actor
&
dest
,
const
util
::
duration
&
rtime
,
Ts
&&
...
what
)
{
static_assert
(
sizeof
...(
Ts
)
>
0
,
"no message to send"
);
return
timed_sync_send_tuple
(
rtime
,
dest
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
what
)...));
...
...
@@ -146,6 +199,12 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
const
util
::
duration
&
rtime
,
any_tuple
data
);
template
<
typename
...
Ts
>
void
delayed_send
(
const
channel
&
dest
,
const
util
::
duration
&
rtime
,
Ts
&&
...
args
)
{
delayed_send_tuple
(
dest
,
rtime
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
args
)...));
}
/**
* @brief Causes this actor to subscribe to the group @p what.
*
...
...
@@ -234,15 +293,6 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
demonitor
(
whom
->
address
());
}
/**
* @brief Can be overridden to initialize an actor before any
* message is handled.
* @warning Must not call blocking functions such as
* {@link cppa::receive receive}.
* @note Calling {@link become} to set an initial behavior is supported.
*/
virtual
void
init
();
/**
* @brief Can be overridden to perform cleanup code after an actor
* finished execution.
...
...
@@ -309,9 +359,7 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
else
quit
(
exit_reason
::
unhandled_sync_failure
);
}
local_actor
(
bool
is_scheduled
=
false
);
virtual
bool
initialized
()
const
=
0
;
local_actor
();
inline
bool
chaining_enabled
();
...
...
@@ -332,20 +380,32 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
inline
void
mark_arrived
(
message_id
response_id
);
//virtual void become_waiting_for(behavior, message_id) = 0;
//inline detail::behavior_stack& bhvr_stack();
inline
std
::
uint32_t
planned_exit_reason
()
const
;
//virtual void do_become(behavior&& bhvr, bool discard_old) = 0
;
inline
void
planned_exit_reason
(
std
::
uint32_t
value
)
;
//inline void do_become(const behavior& bhvr, bool discard_old);
actor_state
cas_state
(
actor_state
expected
,
actor_state
desired
)
{
auto
e
=
expected
;
do
{
if
(
m_state
.
compare_exchange_weak
(
e
,
desired
))
return
desired
;
}
while
(
e
==
expected
);
return
e
;
}
inline
std
::
uint32_t
planned_exit_reason
()
const
;
inline
void
set_state
(
actor_state
new_value
)
{
m_state
.
store
(
new_value
);
}
inline
void
planned_exit_reason
(
std
::
uint32_t
value
);
inline
actor_state
state
()
const
{
return
m_state
;
}
protected:
template
<
typename
...
Ts
>
inline
mailbox_element
*
new_mailbox_element
(
Ts
&&
...
args
)
{
return
mailbox_element
::
create
(
std
::
forward
<
Ts
>
(
args
)...);
}
void
remove_handler
(
message_id
id
);
void
cleanup
(
std
::
uint32_t
reason
);
...
...
@@ -353,9 +413,6 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
// true if this actor receives EXIT messages as ordinary messages
bool
m_trap_exit
;
// true if this actor takes part in cooperative scheduling
bool
m_is_scheduled
;
// identifies the ID of the last sent synchronous request
message_id
m_last_request_id
;
...
...
@@ -372,12 +429,12 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
// {group => subscription} map of all joined groups
std
::
map
<
group_ptr
,
group
::
subscription
>
m_subscriptions
;
// allows actors to keep previous behaviors and enables unbecome()
//detail::behavior_stack m_bhvr_stack;
// set by quit
std
::
uint32_t
m_planned_exit_reason
;
// the state of the (possibly cooperatively scheduled) actor
std
::
atomic
<
actor_state
>
m_state
;
/** @endcond */
private:
...
...
cppa/mailbox_based.hpp
View file @
c91bf3fc
...
...
@@ -53,6 +53,11 @@ class mailbox_based : public Base {
}
}
template
<
typename
...
Ts
>
inline
mailbox_element
*
new_mailbox_element
(
Ts
&&
...
args
)
{
return
mailbox_element
::
create
(
std
::
forward
<
Ts
>
(
args
)...);
}
protected:
typedef
mailbox_based
combined_type
;
...
...
@@ -68,11 +73,6 @@ class mailbox_based : public Base {
Base
::
cleanup
(
reason
);
}
template
<
typename
...
Ts
>
inline
mailbox_element
*
new_mailbox_element
(
Ts
&&
...
args
)
{
return
mailbox_element
::
create
(
std
::
forward
<
Ts
>
(
args
)...);
}
mailbox_type
m_mailbox
;
};
...
...
cppa/match_expr.hpp
View file @
c91bf3fc
...
...
@@ -64,7 +64,7 @@ template<typename T1, typename T2>
inline
const
T2
&
deduce_const
(
const
T1
&
,
T2
&
rhs
)
{
return
rhs
;
}
template
<
class
FilteredPattern
>
struct
invoke_
policy
_base
{
struct
invoke_
util
_base
{
typedef
FilteredPattern
filtered_pattern
;
typedef
typename
pseudo_tuple_from_type_list
<
filtered_pattern
>::
type
tuple_type
;
...
...
@@ -72,9 +72,9 @@ struct invoke_policy_base {
// covers wildcard_position::multiple and wildcard_position::in_between
template
<
wildcard_position
,
class
Pattern
,
class
FilteredPattern
>
struct
invoke_
policy_impl
:
invoke_policy
_base
<
FilteredPattern
>
{
struct
invoke_
util_impl
:
invoke_util
_base
<
FilteredPattern
>
{
typedef
invoke_
policy
_base
<
FilteredPattern
>
super
;
typedef
invoke_
util
_base
<
FilteredPattern
>
super
;
template
<
class
Tuple
>
static
bool
can_invoke
(
const
std
::
type_info
&
type_token
,
...
...
@@ -113,12 +113,12 @@ struct invoke_policy_impl : invoke_policy_base<FilteredPattern> {
};
template
<
>
struct
invoke_
policy
_impl
<
wildcard_position
::
nil
,
struct
invoke_
util
_impl
<
wildcard_position
::
nil
,
util
::
empty_type_list
,
util
::
empty_type_list
>
:
invoke_
policy
_base
<
util
::
empty_type_list
>
{
:
invoke_
util
_base
<
util
::
empty_type_list
>
{
typedef
invoke_
policy
_base
<
util
::
empty_type_list
>
super
;
typedef
invoke_
util
_base
<
util
::
empty_type_list
>
super
;
template
<
typename
PtrType
,
class
Tuple
>
static
bool
prepare_invoke
(
typename
super
::
tuple_type
&
,
...
...
@@ -137,12 +137,12 @@ struct invoke_policy_impl<wildcard_position::nil,
};
template
<
class
Pattern
,
typename
...
Ts
>
struct
invoke_
policy
_impl
<
wildcard_position
::
nil
,
struct
invoke_
util
_impl
<
wildcard_position
::
nil
,
Pattern
,
util
::
type_list
<
Ts
...
>>
:
invoke_
policy
_base
<
util
::
type_list
<
Ts
...
>>
{
:
invoke_
util
_base
<
util
::
type_list
<
Ts
...
>>
{
typedef
invoke_
policy
_base
<
util
::
type_list
<
Ts
...
>>
super
;
typedef
invoke_
util
_base
<
util
::
type_list
<
Ts
...
>>
super
;
typedef
typename
super
::
tuple_type
tuple_type
;
...
...
@@ -242,12 +242,12 @@ struct invoke_policy_impl<wildcard_position::nil,
};
template
<
>
struct
invoke_
policy
_impl
<
wildcard_position
::
leading
,
struct
invoke_
util
_impl
<
wildcard_position
::
leading
,
util
::
type_list
<
anything
>
,
util
::
empty_type_list
>
:
invoke_
policy
_base
<
util
::
empty_type_list
>
{
:
invoke_
util
_base
<
util
::
empty_type_list
>
{
typedef
invoke_
policy
_base
<
util
::
empty_type_list
>
super
;
typedef
invoke_
util
_base
<
util
::
empty_type_list
>
super
;
template
<
class
Tuple
>
static
inline
bool
can_invoke
(
const
std
::
type_info
&
,
const
Tuple
&
)
{
...
...
@@ -266,12 +266,12 @@ struct invoke_policy_impl<wildcard_position::leading,
};
template
<
class
Pattern
,
typename
...
Ts
>
struct
invoke_
policy
_impl
<
wildcard_position
::
trailing
,
struct
invoke_
util
_impl
<
wildcard_position
::
trailing
,
Pattern
,
util
::
type_list
<
Ts
...
>>
:
invoke_
policy
_base
<
util
::
type_list
<
Ts
...
>>
{
:
invoke_
util
_base
<
util
::
type_list
<
Ts
...
>>
{
typedef
invoke_
policy
_base
<
util
::
type_list
<
Ts
...
>>
super
;
typedef
invoke_
util
_base
<
util
::
type_list
<
Ts
...
>>
super
;
template
<
class
Tuple
>
static
bool
can_invoke
(
const
std
::
type_info
&
arg_types
,
...
...
@@ -308,12 +308,12 @@ struct invoke_policy_impl<wildcard_position::trailing,
};
template
<
class
Pattern
,
typename
...
Ts
>
struct
invoke_
policy
_impl
<
wildcard_position
::
leading
,
struct
invoke_
util
_impl
<
wildcard_position
::
leading
,
Pattern
,
util
::
type_list
<
Ts
...
>>
:
invoke_
policy
_base
<
util
::
type_list
<
Ts
...
>>
{
:
invoke_
util
_base
<
util
::
type_list
<
Ts
...
>>
{
typedef
invoke_
policy
_base
<
util
::
type_list
<
Ts
...
>>
super
;
typedef
invoke_
util
_base
<
util
::
type_list
<
Ts
...
>>
super
;
template
<
class
Tuple
>
static
bool
can_invoke
(
const
std
::
type_info
&
arg_types
,
...
...
@@ -352,8 +352,8 @@ struct invoke_policy_impl<wildcard_position::leading,
};
template
<
class
Pattern
>
struct
invoke_
policy
:
invoke_
policy
_impl
<
struct
invoke_
util
:
invoke_
util
_impl
<
get_wildcard_position
<
Pattern
>
(),
Pattern
,
typename
util
::
tl_filter_not_type
<
Pattern
,
anything
>::
type
>
{
...
...
@@ -507,7 +507,7 @@ Result unroll_expr(PPFPs& fs,
auto
&
f
=
get
<
N
>
(
fs
);
typedef
typename
util
::
rm_const_and_ref
<
decltype
(
f
)
>::
type
Fun
;
typedef
typename
Fun
::
pattern_type
pattern_type
;
typedef
detail
::
invoke_
policy
<
pattern_type
>
policy
;
typedef
detail
::
invoke_
util
<
pattern_type
>
policy
;
typename
policy
::
tuple_type
targs
;
if
(
policy
::
prepare_invoke
(
targs
,
type_token
,
is_dynamic
,
ptr
,
tup
))
{
auto
is
=
util
::
get_indices
(
targs
);
...
...
@@ -536,7 +536,7 @@ inline bool can_unroll_expr(PPFPs& fs,
auto
&
f
=
get
<
N
>
(
fs
);
typedef
typename
util
::
rm_const_and_ref
<
decltype
(
f
)
>::
type
Fun
;
typedef
typename
Fun
::
pattern_type
pattern_type
;
typedef
detail
::
invoke_
policy
<
pattern_type
>
policy
;
typedef
detail
::
invoke_
util
<
pattern_type
>
policy
;
return
policy
::
can_invoke
(
arg_types
,
tup
);
}
...
...
@@ -556,7 +556,7 @@ inline std::uint64_t calc_bitmask(PPFPs& fs,
auto
&
f
=
get
<
N
>
(
fs
);
typedef
typename
util
::
rm_const_and_ref
<
decltype
(
f
)
>::
type
Fun
;
typedef
typename
Fun
::
pattern_type
pattern_type
;
typedef
detail
::
invoke_
policy
<
pattern_type
>
policy
;
typedef
detail
::
invoke_
util
<
pattern_type
>
policy
;
std
::
uint64_t
result
=
policy
::
can_invoke
(
tinf
,
tup
)
?
(
0x01
<<
N
)
:
0x00
;
return
result
|
calc_bitmask
(
fs
,
long_constant
<
N
-
1l
>
(),
tinf
,
tup
);
}
...
...
cppa/message_future.hpp
View file @
c91bf3fc
...
...
@@ -34,7 +34,9 @@
#include <cstdint>
#include <type_traits>
#include "cppa/on.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/message_id.hpp"
#include "cppa/partial_function.hpp"
namespace
cppa
{
...
...
@@ -56,8 +58,10 @@ class continue_helper {
inline
continue_helper
(
message_id
mid
)
:
m_mid
(
mid
)
{
}
template
<
typename
F
>
continue_helper
&
continue_with
(
F
fun
);
continue_helper
&
continue_with
(
F
)
{
}
inline
message_id
get_message_id
()
const
{
return
m_mid
;
}
...
...
@@ -78,12 +82,14 @@ class message_future {
message_future
()
=
delete
;
inline
continue_helper
then
(
const
partial_function
&
pfun
)
{
inline
continue_helper
then
(
const
behavior
&
)
{
//FIXME
return
message_id
{};
}
inline
continue_helper
await
(
const
partial_function
&
pfun
)
{
inline
continue_helper
await
(
const
behavior
&
)
{
//FIXME
return
message_id
{};
}
/**
...
...
@@ -113,7 +119,7 @@ class message_future {
continue_helper
>::
type
then
(
Fs
...
fs
)
{
return
then
(
fs2bhvr
(
std
::
move
(
fs
)...)
);
return
then
(
partial_function
{(
on_arg_match
>>
std
::
move
(
fs
))...}
);
}
/**
...
...
@@ -124,7 +130,7 @@ class message_future {
template
<
typename
...
Fs
>
typename
std
::
enable_if
<
util
::
all_callable
<
Fs
...
>::
value
>::
type
await
(
Fs
...
fs
)
{
await
(
fs2bhvr
({
std
::
move
(
fs
)...})
);
await
(
partial_function
{(
on_arg_match
>>
std
::
move
(
fs
))...}
);
}
/**
...
...
@@ -142,8 +148,6 @@ class message_future {
message_id
m_mid
;
local_actor
*
self
;
partial_function
fs2bhvr
(
partial_function
pf
);
inline
void
check_consistency
()
{
}
};
...
...
@@ -193,17 +197,6 @@ inline sync_handle_helper handle_response(const message_future& f) {
return
{
f
};
}
/**
* @brief Handles a synchronous response message in an event-based way.
* @param handle A future for a synchronous response.
* @throws std::logic_error if @p handle is not valid or if the actor
* already received the response for @p handle
* @relates message_future
*/
inline
sync_receive_helper
receive_response
(
const
message_future
&
f
)
{
return
{
f
};
}
}
// namespace cppa
#endif // CPPA_MESSAGE_FUTURE_HPP
cppa/opencl/actor_facade.hpp
View file @
c91bf3fc
...
...
@@ -28,7 +28,6 @@
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPENCL_ACTOR_FACADE_HPP
#define CPPA_OPENCL_ACTOR_FACADE_HPP
...
...
@@ -55,34 +54,35 @@
#include "cppa/detail/scheduled_actor_dummy.hpp"
namespace
cppa
{
namespace
opencl
{
namespace
cppa
{
namespace
opencl
{
class
opencl_metainfo
;
template
<
typename
Signature
>
template
<
typename
Signature
>
class
actor_facade
;
template
<
typename
Ret
,
typename
...
Args
>
class
actor_facade
<
Ret
(
Args
...)
>
:
public
actor
{
template
<
typename
Ret
,
typename
...
Args
>
class
actor_facade
<
Ret
(
Args
...)
>
:
public
a
bstract_a
ctor
{
friend
class
command
<
actor_facade
,
Ret
>
;
public:
typedef
cow_tuple
<
typename
util
::
rm_const_and_ref
<
Args
>::
type
...
>
args_tuple
;
typedef
cow_tuple
<
typename
util
::
rm_const_and_ref
<
Args
>::
type
...
>
args_tuple
;
typedef
std
::
function
<
optional
<
args_tuple
>
(
any_tuple
)
>
arg_mapping
;
typedef
std
::
function
<
any_tuple
(
Ret
&
)
>
result_mapping
;
static
intrusive_ptr
<
actor_facade
>
create
(
const
program
&
prog
,
const
char
*
kernel_name
,
arg_mapping
map_args
,
result_mapping
map_result
,
const
dim_vec
&
global_dims
,
const
dim_vec
&
offsets
,
const
dim_vec
&
local_dims
)
{
static
intrusive_ptr
<
actor_facade
>
create
(
const
program
&
prog
,
const
char
*
kernel_name
,
arg_mapping
map_args
,
result_mapping
map_result
,
const
dim_vec
&
global_dims
,
const
dim_vec
&
offsets
,
const
dim_vec
&
local_dims
)
{
if
(
global_dims
.
empty
())
{
auto
str
=
"OpenCL kernel needs at least 1 global dimension."
;
CPPA_LOGM_ERROR
(
detail
::
demangle
(
typeid
(
actor_facade
)).
c_str
(),
str
);
CPPA_LOGM_ERROR
(
detail
::
demangle
(
typeid
(
actor_facade
)).
c_str
(),
str
);
throw
std
::
runtime_error
(
str
);
}
auto
check_vec
=
[
&
](
const
dim_vec
&
vec
,
const
char
*
name
)
{
...
...
@@ -90,30 +90,27 @@ class actor_facade<Ret(Args...)> : public actor {
std
::
ostringstream
oss
;
oss
<<
name
<<
" vector is not empty, but "
<<
"its size differs from global dimensions vector's size"
;
CPPA_LOGM_ERROR
(
detail
::
demangle
<
actor_facade
>
().
c_str
(),
oss
.
str
());
CPPA_LOGM_ERROR
(
detail
::
demangle
<
actor_facade
>
().
c_str
(),
oss
.
str
());
throw
std
::
runtime_error
(
oss
.
str
());
}
};
check_vec
(
offsets
,
"offsets"
);
check_vec
(
local_dims
,
"local dimensions"
);
cl_int
err
{
0
};
cl_int
err
{
0
};
kernel_ptr
kernel
;
kernel
.
adopt
(
clCreateKernel
(
prog
.
m_program
.
get
(),
kernel_name
,
&
err
));
kernel
.
adopt
(
clCreateKernel
(
prog
.
m_program
.
get
(),
kernel_name
,
&
err
));
if
(
err
!=
CL_SUCCESS
)
{
std
::
ostringstream
oss
;
oss
<<
"clCreateKernel: "
<<
get_opencl_error
(
err
);
CPPA_LOGM_ERROR
(
detail
::
demangle
<
actor_facade
>
().
c_str
(),
oss
.
str
());
CPPA_LOGM_ERROR
(
detail
::
demangle
<
actor_facade
>
().
c_str
(),
oss
.
str
());
throw
std
::
runtime_error
(
oss
.
str
());
}
return
new
actor_facade
<
Ret
(
Args
...)
>
{
prog
,
kernel
,
global_dims
,
offsets
,
local_dims
,
std
::
move
(
map_args
),
std
::
move
(
map_result
)};
return
new
actor_facade
<
Ret
(
Args
...)
>
{
prog
,
kernel
,
global_dims
,
offsets
,
local_dims
,
std
::
move
(
map_args
),
std
::
move
(
map_result
)
};
}
void
enqueue
(
const
message_header
&
hdr
,
any_tuple
msg
)
override
{
...
...
@@ -124,47 +121,38 @@ class actor_facade<Ret(Args...)> : public actor {
private:
actor_facade
(
const
program
&
prog
,
kernel_ptr
kernel
,
actor_facade
(
const
program
&
prog
,
kernel_ptr
kernel
,
const
dim_vec
&
global_dimensions
,
const
dim_vec
&
global_offsets
,
const
dim_vec
&
local_dimensions
,
arg_mapping
map_args
,
result_mapping
map_result
)
:
m_kernel
(
kernel
)
,
m_program
(
prog
.
m_program
)
,
m_context
(
prog
.
m_context
)
,
m_queue
(
prog
.
m_queue
)
,
m_global_dimensions
(
global_dimensions
)
,
m_global_offsets
(
global_offsets
)
,
m_local_dimensions
(
local_dimensions
)
,
m_map_args
(
std
::
move
(
map_args
))
,
m_map_result
(
std
::
move
(
map_result
))
{
const
dim_vec
&
global_offsets
,
const
dim_vec
&
local_dimensions
,
arg_mapping
map_args
,
result_mapping
map_result
)
:
m_kernel
(
kernel
),
m_program
(
prog
.
m_program
),
m_context
(
prog
.
m_context
),
m_queue
(
prog
.
m_queue
),
m_global_dimensions
(
global_dimensions
),
m_global_offsets
(
global_offsets
),
m_local_dimensions
(
local_dimensions
),
m_map_args
(
std
::
move
(
map_args
)),
m_map_result
(
std
::
move
(
map_result
))
{
CPPA_LOG_TRACE
(
"id: "
<<
this
->
id
());
}
template
<
long
...
Is
>
void
enqueue_impl
(
const
actor_ptr
&
sender
,
any_tuple
msg
,
message_id
id
,
template
<
long
...
Is
>
void
enqueue_impl
(
const
actor_ptr
&
sender
,
any_tuple
msg
,
message_id
id
,
util
::
int_list
<
Is
...
>
)
{
auto
opt
=
m_map_args
(
std
::
move
(
msg
));
if
(
opt
)
{
response_handle
handle
{
this
,
sender
,
id
.
response_id
()
};
response_handle
handle
{
this
,
sender
,
id
.
response_id
()
};
size_t
ret_size
=
std
::
accumulate
(
m_global_dimensions
.
begin
(),
m_global_dimensions
.
end
(),
1
,
std
::
multiplies
<
size_t
>
{});
m_global_dimensions
.
end
(),
1
,
std
::
multiplies
<
size_t
>
{});
std
::
vector
<
mem_ptr
>
arguments
;
add_arguments_to_kernel
<
Ret
>
(
arguments
,
ret_size
,
add_arguments_to_kernel
<
Ret
>
(
arguments
,
ret_size
,
get_ref
<
Is
>
(
*
opt
)...);
auto
cmd
=
make_counted
<
command
<
actor_facade
,
Ret
>>
(
handle
,
this
,
std
::
move
(
arguments
));
auto
cmd
=
make_counted
<
command
<
actor_facade
,
Ret
>>
(
handle
,
this
,
std
::
move
(
arguments
));
cmd
->
enqueue
();
}
else
{
CPPA_LOGMF
(
CPPA_ERROR
,
this
,
"actor_facade::enqueue() tuple_cast failed."
);
}
else
{
CPPA_LOGMF
(
CPPA_ERROR
,
this
,
"actor_facade::enqueue() tuple_cast failed."
);
}
}
typedef
std
::
vector
<
mem_ptr
>
args_vec
;
...
...
@@ -180,36 +168,30 @@ class actor_facade<Ret(Args...)> : public actor {
result_mapping
m_map_result
;
void
add_arguments_to_kernel_rec
(
args_vec
&
arguments
)
{
cl_int
err
{
0
};
for
(
size_t
i
=
1
;
i
<
arguments
.
size
();
++
i
)
{
err
=
clSetKernelArg
(
m_kernel
.
get
(),
(
i
-
1
),
sizeof
(
cl_mem
),
cl_int
err
{
0
};
for
(
size_t
i
=
1
;
i
<
arguments
.
size
();
++
i
)
{
err
=
clSetKernelArg
(
m_kernel
.
get
(),
(
i
-
1
),
sizeof
(
cl_mem
),
static_cast
<
void
*>
(
&
arguments
[
i
]));
CPPA_LOG_ERROR_IF
(
err
!=
CL_SUCCESS
,
"clSetKernelArg: "
<<
get_opencl_error
(
err
));
}
err
=
clSetKernelArg
(
m_kernel
.
get
(),
arguments
.
size
()
-
1
,
sizeof
(
cl_mem
),
static_cast
<
void
*>
(
&
arguments
[
0
]));
err
=
clSetKernelArg
(
m_kernel
.
get
(),
arguments
.
size
()
-
1
,
sizeof
(
cl_mem
),
static_cast
<
void
*>
(
&
arguments
[
0
]));
CPPA_LOG_ERROR_IF
(
err
!=
CL_SUCCESS
,
"clSetKernelArg: "
<<
get_opencl_error
(
err
));
}
template
<
typename
T0
,
typename
...
Ts
>
void
add_arguments_to_kernel_rec
(
args_vec
&
arguments
,
T0
&
arg0
,
Ts
&
...
args
)
{
cl_int
err
{
0
};
auto
buf
=
clCreateBuffer
(
m_context
.
get
(),
CL_MEM_READ_ONLY
|
CL_MEM_COPY_HOST_PTR
,
sizeof
(
typename
T0
::
value_type
)
*
arg0
.
size
(),
arg0
.
data
(),
&
err
);
template
<
typename
T0
,
typename
...
Ts
>
void
add_arguments_to_kernel_rec
(
args_vec
&
arguments
,
T0
&
arg0
,
Ts
&
...
args
)
{
cl_int
err
{
0
};
auto
buf
=
clCreateBuffer
(
m_context
.
get
(),
CL_MEM_READ_ONLY
|
CL_MEM_COPY_HOST_PTR
,
sizeof
(
typename
T0
::
value_type
)
*
arg0
.
size
(),
arg0
.
data
(),
&
err
);
if
(
err
!=
CL_SUCCESS
)
{
CPPA_LOGMF
(
CPPA_ERROR
,
this
,
"clCreateBuffer: "
<<
get_opencl_error
(
err
));
}
else
{
CPPA_LOGMF
(
CPPA_ERROR
,
this
,
"clCreateBuffer: "
<<
get_opencl_error
(
err
));
}
else
{
mem_ptr
tmp
;
tmp
.
adopt
(
std
::
move
(
buf
));
arguments
.
push_back
(
tmp
);
...
...
@@ -217,21 +199,18 @@ class actor_facade<Ret(Args...)> : public actor {
}
}
template
<
typename
R
,
typename
...
Ts
>
void
add_arguments_to_kernel
(
args_vec
&
arguments
,
size_t
ret_size
,
template
<
typename
R
,
typename
...
Ts
>
void
add_arguments_to_kernel
(
args_vec
&
arguments
,
size_t
ret_size
,
Ts
&&
...
args
)
{
arguments
.
clear
();
cl_int
err
{
0
};
auto
buf
=
clCreateBuffer
(
m_context
.
get
(),
CL_MEM_WRITE_ONLY
,
cl_int
err
{
0
};
auto
buf
=
clCreateBuffer
(
m_context
.
get
(),
CL_MEM_WRITE_ONLY
,
sizeof
(
typename
R
::
value_type
)
*
ret_size
,
nullptr
,
&
err
);
nullptr
,
&
err
);
if
(
err
!=
CL_SUCCESS
)
{
CPPA_LOGMF
(
CPPA_ERROR
,
this
,
"clCreateBuffer: "
<<
get_opencl_error
(
err
));
}
else
{
CPPA_LOGMF
(
CPPA_ERROR
,
this
,
"clCreateBuffer: "
<<
get_opencl_error
(
err
));
}
else
{
mem_ptr
tmp
;
tmp
.
adopt
(
std
::
move
(
buf
));
arguments
.
push_back
(
tmp
);
...
...
@@ -241,6 +220,7 @@ class actor_facade<Ret(Args...)> : public actor {
};
}
}
// namespace cppa::opencl
}
// namespace opencl
}
// namespace cppa
#endif // CPPA_OPENCL_ACTOR_FACADE_HPP
cppa/policy.hpp
View file @
c91bf3fc
...
...
@@ -33,10 +33,14 @@
#include "cppa/policy/no_resume.hpp"
#include "cppa/policy/prioritizing.hpp"
#include "cppa/policy/no_scheduling.hpp"
#include "cppa/policy/invoke_policy.hpp"
#include "cppa/policy/nestable_invoke.hpp"
#include "cppa/policy/not_prioritizing.hpp"
#include "cppa/policy/sequential_invoke.hpp"
#include "cppa/policy/event_based_resume.hpp"
#include "cppa/policy/invoke_policy_base.hpp"
#include "cppa/policy/middleman_scheduling.hpp"
#include "cppa/policy/cooperative_scheduling.hpp"
#include "cppa/policy/context_switching_resume.hpp"
#endif // CPPA_POLICY_HPP
cppa/policy/context_switching_resume.hpp
View file @
c91bf3fc
...
...
@@ -27,19 +27,26 @@
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#define CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#include "cppa/config.hpp"
#include "cppa/resumable.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/util/fiber.hpp"
#include "cppa/policy/resume_policy.hpp"
#include "cppa/detail/yield_interface.hpp"
namespace
cppa
{
class
local_actor
;
}
namespace
cppa
{
class
local_actor
;
}
namespace
cppa
{
namespace
policy
{
namespace
cppa
{
namespace
policy
{
/**
* @brief Context-switching actor implementation.
...
...
@@ -49,9 +56,57 @@ class context_switching_resume {
public:
// required by util::fiber
static
void
trampoline
(
void
*
_this
);
// Base must be a mailbox-based actor
template
<
class
Base
>
struct
mixin
:
Base
,
resumable
{
template
<
typename
...
Ts
>
mixin
(
Ts
&&
...
args
)
:
Base
(
std
::
forward
<
Ts
>
(
args
)...)
,
m_fiber
(
context_switching_resume
::
trampoline
,
static_cast
<
blocking_untyped_actor
*>
(
this
))
{
}
resumable
::
resume_result
resume
(
util
::
fiber
*
from
)
override
{
CPPA_REQUIRE
(
from
!=
nullptr
);
using
namespace
detail
;
for
(;;)
{
switch
(
call
(
&
m_fiber
,
from
))
{
case
yield_state
:
:
done
:
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
return
resumable
::
done
;
}
case
yield_state
:
:
ready
:
{
break
;
}
case
yield_state
:
:
blocked
:
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
switch
(
this
->
cas_state
(
actor_state
::
about_to_block
,
actor_state
::
blocked
))
{
case
actor_state
:
:
ready
:
{
// restore variables
CPPA_REQUIRE
(
next_job
==
nullptr
);
break
;
}
case
actor_state
:
:
blocked
:
{
// wait until someone re-schedules that actor
return
resumable
::
resume_later
;
}
default:
{
CPPA_CRITICAL
(
"illegal yield result"
);
}
}
break
;
}
default:
{
CPPA_CRITICAL
(
"illegal state"
);
}
}
}
}
util
::
fiber
m_fiber
;
};
template
<
class
Actor
,
typename
F
>
template
<
class
Actor
,
typename
F
>
void
fetch_messages
(
Actor
*
self
,
F
cb
)
{
auto
e
=
self
->
m_mailbox
.
try_pop
();
while
(
e
==
nullptr
)
{
...
...
@@ -63,7 +118,8 @@ class context_switching_resume {
self
->
set_state
(
actor_state
::
ready
);
}
// wait until actor becomes rescheduled
else
detail
::
yield
(
detail
::
yield_state
::
blocked
);
else
detail
::
yield
(
detail
::
yield_state
::
blocked
);
}
}
// ok, we have at least one message
...
...
@@ -73,7 +129,7 @@ class context_switching_resume {
}
}
template
<
class
Actor
,
typename
F
>
template
<
class
Actor
,
typename
F
>
void
try_fetch_messages
(
Actor
*
self
,
F
cb
)
{
auto
e
=
self
->
m_mailbox
.
try_pop
();
while
(
e
)
{
...
...
@@ -83,57 +139,33 @@ class context_switching_resume {
}
template
<
class
Actor
>
resume_result
resume
(
Actor
*
self
,
util
::
fiber
*
from
)
{
CPPA_LOG_TRACE
(
"state = "
<<
static_cast
<
int
>
(
self
->
state
()));
CPPA_REQUIRE
(
from
!=
nullptr
);
CPPA_REQUIRE
(
next_job
==
nullptr
);
using
namespace
detail
;
for
(;;)
{
switch
(
call
(
&
m_fiber
,
from
))
{
case
yield_state
:
:
done
:
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
return
resume_result
::
actor_done
;
}
case
yield_state
:
:
ready
:
{
break
;
}
case
yield_state
:
:
blocked
:
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
switch
(
compare_exchange_state
(
actor_state
::
about_to_block
,
actor_state
::
blocked
))
{
case
actor_state
:
:
ready
:
{
// restore variables
CPPA_REQUIRE
(
next_job
==
nullptr
);
break
;
}
case
actor_state
:
:
blocked
:
{
// wait until someone re-schedules that actor
return
resume_result
::
actor_blocked
;
}
default:
{
CPPA_CRITICAL
(
"illegal yield result"
);
}
}
break
;
}
default:
{
CPPA_CRITICAL
(
"illegal state"
);
}
void
await_data
(
Actor
*
self
)
{
while
(
self
->
m_mailbox
.
can_fetch_more
()
==
false
)
{
self
->
set_state
(
actor_state
::
about_to_block
);
// make sure mailbox is empty
if
(
self
->
m_mailbox
.
can_fetch_more
())
{
// someone preempt us => continue
self
->
set_state
(
actor_state
::
ready
);
}
// wait until actor becomes rescheduled
else
detail
::
yield
(
detail
::
yield_state
::
blocked
);
}
}
private:
template
<
class
Actor
,
typename
AbsTimeout
>
bool
await_data
(
Actor
*
self
,
const
AbsTimeout
&
)
{
await_data
(
self
);
return
true
;
}
// required by util::fiber
static
void
trampoline
(
void
*
_this
);
private:
// members
util
::
fiber
m_fiber
;
};
}
}
// namespace cppa::policy
}
// namespace policy
}
// namespace cppa
#endif // CPPA_CONTEXT_SWITCHING_ACTOR_HPP
cppa/policy/cooperative_scheduling.hpp
View file @
c91bf3fc
...
...
@@ -31,6 +31,17 @@
#ifndef CPPA_COOPERATIVE_SCHEDULING_HPP
#define CPPA_COOPERATIVE_SCHEDULING_HPP
#include <atomic>
#include "cppa/any_tuple.hpp"
#include "cppa/resumable.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/message_header.hpp"
#include "cppa/detail/yield_interface.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace
cppa
{
namespace
policy
{
class
cooperative_scheduling
{
...
...
@@ -49,12 +60,12 @@ class cooperative_scheduling {
// this does return nullptr
template
<
class
Actor
,
typename
F
>
void
fetch_messages
(
Actor
*
self
,
F
cb
)
{
auto
e
=
self
->
m
_mailbox
.
try_pop
();
auto
e
=
self
->
m
ailbox
()
.
try_pop
();
while
(
e
==
nullptr
)
{
if
(
self
->
m
_mailbox
.
can_fetch_more
()
==
false
)
{
if
(
self
->
m
ailbox
()
.
can_fetch_more
()
==
false
)
{
self
->
set_state
(
actor_state
::
about_to_block
);
// make sure mailbox is empty
if
(
self
->
m
_mailbox
.
can_fetch_more
())
{
if
(
self
->
m
ailbox
()
.
can_fetch_more
())
{
// someone preempt us => continue
self
->
set_state
(
actor_state
::
ready
);
}
...
...
@@ -65,7 +76,7 @@ class cooperative_scheduling {
// ok, we have at least one message
while
(
e
)
{
cb
(
e
);
e
=
self
->
m
_mailbox
.
try_pop
();
e
=
self
->
m
ailbox
()
.
try_pop
();
}
}
...
...
@@ -76,6 +87,59 @@ class cooperative_scheduling {
fetch_messages
(
self
,
cb
);
}
template
<
class
Actor
>
inline
void
launch
(
Actor
*
)
{
static_cast
<
void
>
(
m_hidden
);
}
template
<
class
Actor
>
void
enqueue
(
Actor
*
self
,
const
message_header
&
hdr
,
any_tuple
&
msg
)
{
auto
e
=
self
->
new_mailbox_element
(
hdr
,
std
::
move
(
msg
));
switch
(
self
->
mailbox
().
enqueue
(
e
))
{
case
intrusive
:
:
first_enqueued
:
{
auto
state
=
self
->
state
();
auto
set_ready
=
[
&
]()
->
bool
{
auto
s
=
self
->
cas_state
(
state
,
actor_state
::
ready
);
return
s
==
actor_state
::
ready
;
};
for
(;;)
{
switch
(
state
)
{
case
actor_state
:
:
blocked
:
{
if
(
set_ready
())
{
CPPA_REQUIRE
(
m_scheduler
!=
nullptr
);
//m_scheduler->enqueue(this);
return
;
}
break
;
}
case
actor_state
:
:
about_to_block
:
{
if
(
set_ready
())
{
return
;
}
break
;
}
default:
return
;
}
}
break
;
}
case
intrusive
:
:
queue_closed
:
{
if
(
hdr
.
id
.
is_request
())
{
//FIXME
//detail::sync_request_bouncer f{exit_reason()};
//f(hdr.sender, hdr.id);
}
break
;
}
default:
break
;
}
}
private:
// denotes whether this actor is ignored by await_all_actors_done()
bool
m_hidden
;
};
}
}
// namespace cppa::policy
...
...
cppa/policy/event_based_resume.hpp
View file @
c91bf3fc
...
...
@@ -40,163 +40,138 @@
#include "cppa/config.hpp"
#include "cppa/extend.hpp"
#include "cppa/behavior.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/policy/resume_policy.hpp"
namespace
cppa
{
namespace
policy
{
/**
* @brief Base class for all event-based actor implementations.
* @extends scheduled_actor
*/
class
event_based_resume
{
public:
template
<
class
Actor
>
void
await_data
(
Actor
*
)
{
static_assert
(
std
::
is_same
<
Actor
,
Actor
>::
value
==
false
,
"The event_based_resume policy cannot be used "
"to implement blocking actors"
);
}
template
<
class
Actor
>
bool
await_data
(
Actor
*
,
const
util
::
duration
&
)
{
static_assert
(
std
::
is_same
<
Actor
,
Actor
>::
value
==
false
,
"The event_based_resume policy cannot be used "
"to implement blocking actors"
);
}
template
<
class
Actor
>
timeout_type
init_timeout
(
Actor
*
self
,
const
util
::
duration
&
rel_time
)
{
// request explicit timeout message
self
->
request_timeout
(
rel_time
);
return
0
;
// return some dummy value
}
template
<
class
Actor
,
typename
F
>
void
fetch_messages
(
Actor
*
self
,
F
cb
)
{
auto
e
=
self
->
m_mailbox
.
try_pop
();
while
(
e
)
{
cb
(
e
);
e
=
self
->
m_mailbox
.
try_pop
();
}
}
template
<
class
Actor
,
typename
F
>
inline
void
fetch_messages
(
Actor
*
self
,
F
cb
,
timeout_type
)
{
// a call to this call is always preceded by init_timeout,
// which will trigger a timeout message
fetch_messages
(
self
,
cb
);
}
template
<
class
Actor
,
typename
F
>
void
try_fetch_messages
(
Actor
*
self
,
F
cb
)
{
// try_fetch and fetch have the same semantics for event-based actors
fetch_messages
(
self
,
cb
);
}
template
<
class
Actor
>
resume_result
resume
(
Actor
*
self
,
util
::
fiber
*
)
{
CPPA_LOG_TRACE
(
"id = "
<<
self
->
id
()
<<
", state = "
<<
static_cast
<
int
>
(
self
->
state
()));
CPPA_REQUIRE
(
self
->
state
()
==
actor_state
::
ready
||
self
->
state
()
==
actor_state
::
pending
);
auto
done_cb
=
[
&
]()
->
bool
{
CPPA_LOG_TRACE
(
""
);
if
(
self
->
exit_reason
()
==
self
->
exit_reason
::
not_exited
)
{
if
(
self
->
planned_exit_reason
()
==
self
->
exit_reason
::
not_exited
)
{
self
->
planned_exit_reason
(
exit_reason
::
normal
);
}
self
->
on_exit
();
if
(
!
m_bhvr_stack
.
empty
())
{
planned_exit_reason
(
exit_reason
::
not_exited
);
return
false
;
// on_exit did set a new behavior
// Base must be a mailbox-based actor
template
<
class
Base
>
struct
mixin
:
Base
,
resumable
{
template
<
typename
...
Ts
>
mixin
(
Ts
&&
...
args
)
:
Base
(
std
::
forward
<
Ts
>
(
args
)...)
{
}
resumable
::
resume_result
resume
(
util
::
fiber
*
)
override
{
CPPA_LOG_TRACE
(
"id = "
<<
this
->
id
()
<<
", state = "
<<
static_cast
<
int
>
(
this
->
state
()));
CPPA_REQUIRE
(
this
->
state
()
==
actor_state
::
ready
||
this
->
state
()
==
actor_state
::
pending
);
auto
done_cb
=
[
&
]()
->
bool
{
CPPA_LOG_TRACE
(
""
);
if
(
this
->
exit_reason
()
==
exit_reason
::
not_exited
)
{
if
(
this
->
planned_exit_reason
()
==
exit_reason
::
not_exited
)
{
this
->
planned_exit_reason
(
exit_reason
::
normal
);
}
this
->
on_exit
();
if
(
!
this
->
bhvr_stack
().
empty
())
{
this
->
planned_exit_reason
(
exit_reason
::
not_exited
);
return
false
;
// on_exit did set a new behavior
}
this
->
cleanup
(
this
->
planned_exit_reason
());
}
cleanup
(
planned_exit_reason
()
);
}
set_state
(
actor_state
::
done
);
m_bhvr_stack
.
clear
();
m_bhvr_stack
.
cleanup
()
;
on_exit
()
;
this
->
set_state
(
actor_state
::
done
);
this
->
bhvr_stack
().
clear
();
this
->
bhvr_stack
().
cleanup
(
);
this
->
on_exit
();
return
true
;
}
;
CPPA_REQUIRE
(
next_job
==
nullptr
);
return
true
;
};
CPPA_REQUIRE
(
next_job
==
nullptr
);
try
{
//auto e = m_mailbox.try_pop();
for
(
auto
e
=
m_mailbox
.
try_pop
();
;
e
=
m_mailbox
.
try_pop
())
{
//e = m_mailbox.try_pop();
if
(
e
==
nullptr
)
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"no more element in mailbox; going to block"
);
set_state
(
actor_state
::
about_to_block
);
std
::
atomic_thread_fence
(
std
::
memory_order_seq_cst
);
if
(
this
->
m_mailbox
.
can_fetch_more
()
==
false
)
{
switch
(
compare_exchange_state
(
actor_state
::
about_to_block
,
actor_state
::
blocked
))
{
case
actor_state
:
:
ready
:
// interrupted by arriving message
// restore members
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"interrupted by arriving message"
);
break
;
case
actor_state
:
:
blocked
:
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"set state successfully to blocked"
);
// done setting actor to blocked
return
resume_result
::
actor_blocked
;
default:
CPPA_LOGMF
(
CPPA_ERROR
,
self
,
"invalid state"
);
CPPA_CRITICAL
(
"invalid state"
);
};
try
{
//auto e = m_mailbox.try_pop();
for
(
auto
e
=
this
->
m_mailbox
.
try_pop
();
;
e
=
this
->
m_mailbox
.
try_pop
())
{
//e = m_mailbox.try_pop();
if
(
e
==
nullptr
)
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"no more element in mailbox; going to block"
);
this
->
set_state
(
actor_state
::
about_to_block
);
std
::
atomic_thread_fence
(
std
::
memory_order_seq_cst
);
if
(
this
->
m_mailbox
.
can_fetch_more
()
==
false
)
{
switch
(
this
->
cas_state
(
actor_state
::
about_to_block
,
actor_state
::
blocked
))
{
case
actor_state
:
:
ready
:
// interrupted by arriving message
// restore members
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"interrupted by arriving message"
);
break
;
case
actor_state
:
:
blocked
:
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"set state successfully to blocked"
);
// done setting actor to blocked
return
resumable
::
resume_later
;
default:
CPPA_LOGMF
(
CPPA_ERROR
,
self
,
"invalid state"
);
CPPA_CRITICAL
(
"invalid state"
);
};
}
else
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"mailbox can fetch more"
);
this
->
set_state
(
actor_state
::
ready
);
}
}
/*
else {
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"mailbox can fetch more"
);
set_state
(
actor_state
::
ready
);
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
}
}
else
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"try to invoke message: "
<<
to_string
(
e
->
msg
));
if
(
m_bhvr_stack
.
invoke
(
m_recv_policy
,
this
,
e
))
{
CPPA_LOG_DEBUG_IF
(
m_chained_actor
,
"set actor with ID "
<<
m_chained_actor
->
id
()
<<
" as successor"
);
if
(
m_bhvr_stack
.
empty
()
&&
done_cb
())
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"behavior stack empty"
);
return
resume_result
::
actor_done
;
if (this->bhvr_stack().invoke(m_recv_policy, this, e)) {
CPPA_LOG_DEBUG_IF(m_chained_actor,
"set actor with ID "
<< m_chained_actor->id()
<< " as successor");
if (this->bhvr_stack().empty() && done_cb()) {
CPPA_LOGMF(CPPA_DEBUG, self, "behavior stack empty");
return resume_result::actor_done;
}
this->bhvr_stack().cleanup();
}
m_bhvr_stack
.
cleanup
();
}
*/
}
}
}
catch
(
actor_exited
&
what
)
{
CPPA_LOG_INFO
(
"actor died because of exception: actor_exited, "
"reason = "
<<
what
.
reason
());
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
what
.
reason
());
catch
(
actor_exited
&
what
)
{
CPPA_LOG_INFO
(
"actor died because of exception: actor_exited, "
"reason = "
<<
what
.
reason
());
if
(
this
->
exit_reason
()
==
exit_reason
::
not_exited
)
{
this
->
quit
(
what
.
reason
());
}
}
}
catch
(
std
::
exception
&
e
)
{
CPPA_LOG_WARNING
(
"actor died because of exception: "
<<
detail
::
demangle
(
typeid
(
e
))
<<
", what() = "
<<
e
.
what
());
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
exit_reason
::
unhandled_exception
);
catch
(
std
::
exception
&
e
)
{
CPPA_LOG_WARNING
(
"actor died because of exception: "
<<
detail
::
demangle
(
typeid
(
e
))
<<
", what() = "
<<
e
.
what
());
if
(
this
->
exit_reason
()
==
exit_reason
::
not_exited
)
{
this
->
quit
(
exit_reason
::
unhandled_exception
);
}
}
}
catch
(...)
{
CPPA_LOG_WARNING
(
"actor died because of an unknown exception"
);
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
exit_reason
::
unhandled_exception
);
catch
(...)
{
CPPA_LOG_WARNING
(
"actor died because of an unknown exception"
);
if
(
this
->
exit_reason
()
==
exit_reason
::
not_exited
)
{
this
->
quit
(
exit_reason
::
unhandled_exception
);
}
}
done_cb
();
return
resumable
::
done
;
}
done_cb
();
return
resume_result
::
actor_done
;
};
template
<
class
Actor
>
void
await_data
(
Actor
*
)
{
static_assert
(
std
::
is_same
<
Actor
,
Actor
>::
value
==
false
,
"The event-based resume policy cannot be used "
"to implement blocking actors"
);
}
template
<
class
Actor
>
bool
await_data
(
Actor
*
,
const
util
::
duration
&
)
{
static_assert
(
std
::
is_same
<
Actor
,
Actor
>::
value
==
false
,
"The event-based resume policy cannot be used "
"to implement blocking actors"
);
}
};
...
...
cppa/policy/invoke_policy
_base
.hpp
→
cppa/policy/invoke_policy.hpp
View file @
c91bf3fc
...
...
@@ -28,8 +28,8 @@
\******************************************************************************/
#ifndef CPPA_
NESTABLE_RECEIV
E_POLICY_HPP
#define CPPA_
NESTABLE_RECEIV
E_POLICY_HPP
#ifndef CPPA_
INVOK
E_POLICY_HPP
#define CPPA_
INVOK
E_POLICY_HPP
#include <list>
#include <memory>
...
...
@@ -45,6 +45,7 @@
#include "cppa/mailbox_element.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/dptr.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/detail/matches.hpp"
...
...
@@ -59,35 +60,38 @@ enum receive_policy_flag {
rp_sequential
};
enum
handle_message_result
{
hm_timeout_msg
,
hm_skip_msg
,
hm_drop_msg
,
hm_cache_msg
,
hm_msg_handled
};
template
<
receive_policy_flag
X
>
struct
rp_flag
{
typedef
std
::
integral_constant
<
receive_policy_flag
,
X
>
type
;
};
/**
* @brief The invoke_policy <b>concept</b> class. Please note that this
* class is <b>not</b> implemented. It only explains the all
* required member function and their behavior for any resume policy.
*/
template
<
class
Derived
>
class
invoke_policy
_base
{
class
invoke_policy
{
public:
typedef
mailbox_element
*
pointer
;
typedef
std
::
unique_ptr
<
mailbox_element
,
detail
::
disposer
>
smart_pointer
;
enum
handle_message_result
{
hm_timeout_msg
,
hm_skip_msg
,
hm_drop_msg
,
hm_cache_msg
,
hm_msg_handled
};
template
<
class
Client
,
class
Fun
>
bool
invoke_from_cache
(
Client
*
client
,
template
<
class
Actor
,
class
Fun
>
bool
invoke_from_cache
(
Actor
*
self
,
Fun
&
fun
,
message_id
awaited_response
=
message_id
{})
{
std
::
integral_constant
<
receive_policy_flag
,
Client
::
receive_flag
>
policy
;
auto
i
=
m_cache
.
begin
();
auto
e
=
m_cache
.
end
();
while
(
i
!=
e
)
{
switch
(
this
->
handle_message
(
client
,
i
->
get
(),
fun
,
awaited_response
,
policy
))
{
switch
(
this
->
handle_message
(
self
,
i
->
get
(),
fun
,
awaited_response
))
{
case
hm_msg_handled
:
{
m_cache
.
erase
(
i
);
return
true
;
...
...
@@ -113,15 +117,14 @@ class invoke_policy_base {
m_cache
.
emplace_back
(
std
::
move
(
node_ptr
));
}
template
<
class
Client
,
class
Fun
>
bool
invoke
(
Client
*
client
,
template
<
class
Actor
,
class
Fun
>
bool
invoke
(
Actor
*
self
,
pointer
node_ptr
,
Fun
&
fun
,
message_id
awaited_response
=
message_id
())
{
smart_pointer
node
(
node_ptr
);
std
::
integral_constant
<
receive_policy_flag
,
Client
::
receive_flag
>
policy
;
switch
(
this
->
handle_message
(
client
,
node
.
get
(),
fun
,
awaited_response
,
policy
))
{
switch
(
this
->
handle_message
(
self
,
node
.
get
(),
fun
,
awaited_response
))
{
case
hm_msg_handled
:
{
return
true
;
}
...
...
@@ -142,71 +145,71 @@ class invoke_policy_base {
return
false
;
}
template
<
class
Client
,
class
FunOrBehavior
>
inline
void
receive_wo_timeout
(
Client
*
client
,
FunOrBehavior
&
fun
)
{
if
(
!
invoke_from_cache
(
client
,
fun
))
{
while
(
!
invoke
(
client
,
client
->
await_message
(),
fun
))
{
}
template
<
class
Actor
,
class
FunOrBehavior
>
inline
void
receive_wo_timeout
(
Actor
*
self
,
FunOrBehavior
&
fun
)
{
if
(
!
invoke_from_cache
(
self
,
fun
))
{
while
(
!
invoke
(
self
,
self
->
await_message
(),
fun
))
{
}
}
}
template
<
class
Client
>
void
receive
(
Client
*
client
,
partial_function
&
fun
)
{
receive_wo_timeout
(
client
,
fun
);
template
<
class
Actor
>
void
receive
(
Actor
*
self
,
partial_function
&
fun
)
{
receive_wo_timeout
(
self
,
fun
);
}
template
<
class
Client
>
void
receive
(
Client
*
client
,
behavior
&
bhvr
)
{
template
<
class
Actor
>
void
receive
(
Actor
*
self
,
behavior
&
bhvr
)
{
if
(
!
bhvr
.
timeout
().
valid
())
{
receive_wo_timeout
(
client
,
bhvr
);
receive_wo_timeout
(
self
,
bhvr
);
}
else
if
(
!
invoke_from_cache
(
client
,
bhvr
))
{
else
if
(
!
invoke_from_cache
(
self
,
bhvr
))
{
if
(
bhvr
.
timeout
().
is_zero
())
{
pointer
e
=
nullptr
;
while
((
e
=
client
->
try_pop
())
!=
nullptr
)
{
while
((
e
=
self
->
try_pop
())
!=
nullptr
)
{
CPPA_REQUIRE
(
e
->
marked
==
false
);
if
(
invoke
(
client
,
e
,
bhvr
))
{
if
(
invoke
(
self
,
e
,
bhvr
))
{
return
;
// done
}
}
handle_timeout
(
client
,
bhvr
);
dptr
()
->
handle_timeout
(
self
,
bhvr
);
}
else
{
auto
timeout
=
client
->
init_timeout
(
bhvr
.
timeout
());
auto
timeout
=
self
->
init_timeout
(
bhvr
.
timeout
());
pointer
e
=
nullptr
;
while
((
e
=
client
->
await_message
(
timeout
))
!=
nullptr
)
{
while
((
e
=
self
->
await_message
(
timeout
))
!=
nullptr
)
{
CPPA_REQUIRE
(
e
->
marked
==
false
);
if
(
invoke
(
client
,
e
,
bhvr
))
{
if
(
invoke
(
self
,
e
,
bhvr
))
{
return
;
// done
}
}
handle_timeout
(
client
,
bhvr
);
dptr
()
->
handle_timeout
(
self
,
bhvr
);
}
}
}
template
<
class
Client
>
void
receive
(
Client
*
client
,
behavior
&
bhvr
,
message_id
mid
)
{
template
<
class
Actor
>
void
receive
(
Actor
*
self
,
behavior
&
bhvr
,
message_id
mid
)
{
CPPA_REQUIRE
(
mid
.
is_response
());
if
(
!
invoke_from_cache
(
client
,
bhvr
,
mid
))
{
if
(
!
invoke_from_cache
(
self
,
bhvr
,
mid
))
{
if
(
bhvr
.
timeout
().
valid
())
{
CPPA_REQUIRE
(
bhvr
.
timeout
().
is_zero
()
==
false
);
auto
timeout
=
client
->
init_timeout
(
bhvr
.
timeout
());
auto
timeout
=
self
->
init_timeout
(
bhvr
.
timeout
());
pointer
e
=
nullptr
;
while
((
e
=
client
->
await_message
(
timeout
))
!=
nullptr
)
{
while
((
e
=
self
->
await_message
(
timeout
))
!=
nullptr
)
{
CPPA_REQUIRE
(
e
->
marked
==
false
);
if
(
invoke
(
client
,
e
,
bhvr
,
mid
))
{
if
(
invoke
(
self
,
e
,
bhvr
,
mid
))
{
return
;
// done
}
}
handle_timeout
(
client
,
bhvr
);
dptr
()
->
handle_timeout
(
self
,
bhvr
);
}
else
while
(
!
invoke
(
client
,
client
->
await_message
(),
bhvr
,
mid
))
{
}
else
while
(
!
invoke
(
self
,
self
->
await_message
(),
bhvr
,
mid
))
{
}
}
}
template
<
class
Client
>
mailbox_element
*
fetch_message
(
Client
*
client
)
{
return
client
->
await_message
();
template
<
class
Actor
>
mailbox_element
*
fetch_message
(
Actor
*
self
)
{
return
self
->
await_message
();
}
typedef
typename
rp_flag
<
rp_nestable
>::
type
nestable
;
...
...
@@ -216,13 +219,8 @@ class invoke_policy_base {
std
::
list
<
std
::
unique_ptr
<
mailbox_element
,
detail
::
disposer
>
>
m_cache
;
template
<
class
Client
>
inline
void
handle_timeout
(
Client
*
client
,
behavior
&
bhvr
)
{
client
->
handle_timeout
(
bhvr
);
}
template
<
class
Client
>
inline
void
handle_timeout
(
Client
*
,
partial_function
&
)
{
template
<
class
Actor
>
inline
void
handle_timeout
(
Actor
*
,
partial_function
&
)
{
CPPA_CRITICAL
(
"handle_timeout(partial_function&)"
);
}
...
...
@@ -239,11 +237,11 @@ class invoke_policy_base {
// identifies 'special' messages that should not be processed normally:
// - system messages such as EXIT (if
client
doesn't trap exits) and TIMEOUT
// - system messages such as EXIT (if
self
doesn't trap exits) and TIMEOUT
// - expired synchronous response messages
template
<
class
Client
>
filter_result
filter_msg
(
Client
*
client
,
pointer
node
)
{
template
<
class
Actor
>
filter_result
filter_msg
(
Actor
*
self
,
pointer
node
)
{
const
any_tuple
&
msg
=
node
->
msg
;
auto
mid
=
node
->
mid
;
auto
&
arr
=
detail
::
static_types_array
<
atom_value
,
std
::
uint32_t
>::
arr
;
...
...
@@ -254,9 +252,9 @@ class invoke_policy_base {
auto
v1
=
msg
.
get_as
<
std
::
uint32_t
>
(
1
);
if
(
v0
==
atom
(
"EXIT"
))
{
CPPA_REQUIRE
(
!
mid
.
valid
());
if
(
client
->
m_trap_exit
==
false
)
{
if
(
self
->
trap_exit
()
==
false
)
{
if
(
v1
!=
exit_reason
::
normal
)
{
client
->
quit
(
v1
);
self
->
quit
(
v1
);
return
non_normal_exit_signal
;
}
return
normal_exit_signal
;
...
...
@@ -264,8 +262,9 @@ class invoke_policy_base {
}
else
if
(
v0
==
atom
(
"SYNC_TOUT"
))
{
CPPA_REQUIRE
(
!
mid
.
valid
());
return
client
->
waits_for_timeout
(
v1
)
?
timeout_message
:
expired_timeout_message
;
//FIXME
//return self->waits_for_timeout(v1) ? timeout_message
// : expired_timeout_message;
}
}
else
if
(
msg
.
size
()
==
1
...
...
@@ -275,7 +274,7 @@ class invoke_policy_base {
return
timeout_response_message
;
}
if
(
mid
.
is_response
())
{
return
(
client
->
awaits
(
mid
))
?
sync_response
return
(
self
->
awaits
(
mid
))
?
sync_response
:
expired_sync_response
;
}
return
ordinary_message
;
...
...
@@ -283,37 +282,37 @@ class invoke_policy_base {
public:
template
<
class
Client
>
inline
response_handle
fetch_response_handle
(
Client
*
cl
,
int
)
{
template
<
class
Actor
>
inline
response_handle
fetch_response_handle
(
Actor
*
cl
,
int
)
{
return
cl
->
make_response_handle
();
}
template
<
class
Client
>
inline
response_handle
fetch_response_handle
(
Client
*
,
response_handle
&
hdl
)
{
template
<
class
Actor
>
inline
response_handle
fetch_response_handle
(
Actor
*
,
response_handle
&
hdl
)
{
return
std
::
move
(
hdl
);
}
// - extracts response message from handler
// - returns true if fun was successfully invoked
template
<
class
Client
,
class
Fun
,
class
MaybeResponseHandle
=
int
>
optional
<
any_tuple
>
invoke_fun
(
Client
*
client
,
template
<
class
Actor
,
class
Fun
,
class
MaybeResponseHandle
=
int
>
optional
<
any_tuple
>
invoke_fun
(
Actor
*
self
,
any_tuple
&
msg
,
message_id
&
mid
,
Fun
&
fun
,
MaybeResponseHandle
hdl
=
MaybeResponseHandle
{})
{
auto
res
=
fun
(
msg
);
// might change mid
if
(
res
)
{
//message_header hdr{
client
, sender, mid.is_request() ? mid.response_id()
//message_header hdr{
self
, sender, mid.is_request() ? mid.response_id()
// : message_id{}};
if
(
res
->
empty
())
{
// make sure synchronous requests
// always receive a response
if
(
mid
.
is_request
()
&&
!
mid
.
is_answered
())
{
CPPA_LOGMF
(
CPPA_WARNING
,
client
,
"actor with ID "
<<
client
->
id
()
CPPA_LOGMF
(
CPPA_WARNING
,
self
,
"actor with ID "
<<
self
->
id
()
<<
" did not reply to a "
"synchronous request message"
);
auto
fhdl
=
fetch_response_handle
(
client
,
hdl
);
auto
fhdl
=
fetch_response_handle
(
self
,
hdl
);
if
(
fhdl
.
valid
())
fhdl
.
apply
(
make_any_tuple
(
atom
(
"VOID"
)));
}
}
else
{
...
...
@@ -321,11 +320,11 @@ class invoke_policy_base {
&&
res
->
template
get_as
<
atom_value
>(
0
)
==
atom
(
"MESSAGE_ID"
))
{
auto
id
=
res
->
template
get_as
<
std
::
uint64_t
>(
1
);
auto
msg_id
=
message_id
::
from_integer_value
(
id
);
auto
ref_opt
=
client
->
sync_handler
(
msg_id
);
// calls
client
->response_handle() if hdl is a dummy
auto
ref_opt
=
self
->
sync_handler
(
msg_id
);
// calls
self
->response_handle() if hdl is a dummy
// argument, forwards hdl otherwise to reply to the
// original request message
auto
fhdl
=
fetch_response_handle
(
client
,
hdl
);
auto
fhdl
=
fetch_response_handle
(
self
,
hdl
);
if
(
ref_opt
)
{
auto
&
ref
=
*
ref_opt
;
// copy original behavior
...
...
@@ -342,7 +341,7 @@ class invoke_policy_base {
// recursively call invoke_fun on the
// result to correctly handle stuff like
// sync_send(...).then(...).then(...)...
return
invoke_fun
(
client
,
return
invoke_fun
(
self
,
intermediate
,
mutable_mid
,
f2
,
...
...
@@ -357,7 +356,7 @@ class invoke_policy_base {
res
->
reset
();
}
else
{
// respond by using the result of 'fun'
auto
fhdl
=
fetch_response_handle
(
client
,
hdl
);
auto
fhdl
=
fetch_response_handle
(
self
,
hdl
);
if
(
fhdl
.
valid
())
fhdl
.
apply
(
std
::
move
(
*
res
));
}
}
...
...
@@ -370,47 +369,45 @@ class invoke_policy_base {
// the workflow of handle_message (hm) is as follows:
// - should_skip? if yes: return hm_skip_msg
// - msg is ordinary message? if yes:
// - begin(...) -> prepares a
client
for message handling
// -
client
could process message?
// - begin(...) -> prepares a
self
for message handling
// -
self
could process message?
// - yes: cleanup()
// - no: revert(...) -> set
client
back to state it had before begin()
// - no: revert(...) -> set
self
back to state it had before begin()
template
<
class
Client
,
class
Fun
,
class
Policy
>
handle_message_result
handle_message
(
Client
*
client
,
template
<
class
Actor
,
class
Fun
>
handle_message_result
handle_message
(
Actor
*
self
,
pointer
node
,
Fun
&
fun
,
message_id
awaited_response
,
Policy
policy
)
{
message_id
awaited_response
)
{
bool
handle_sync_failure_on_mismatch
=
true
;
if
(
Derived
::
hm_should_skip
(
node
,
policy
))
{
return
hm_skip_msg
;
if
(
dptr
()
->
hm_should_skip
(
node
))
{
return
hm_skip_msg
;
}
switch
(
this
->
filter_msg
(
client
,
node
))
{
switch
(
this
->
filter_msg
(
self
,
node
))
{
default:
{
CPPA_CRITICAL
(
"illegal filter result"
);
}
case
normal_exit_signal
:
{
CPPA_LOGMF
(
CPPA_DEBUG
,
client
,
"dropped normal exit signal"
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"dropped normal exit signal"
);
return
hm_drop_msg
;
}
case
expired_sync_response
:
{
CPPA_LOGMF
(
CPPA_DEBUG
,
client
,
"dropped expired sync response"
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"dropped expired sync response"
);
return
hm_drop_msg
;
}
case
expired_timeout_message
:
{
CPPA_LOGMF
(
CPPA_DEBUG
,
client
,
"dropped expired timeout message"
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"dropped expired timeout message"
);
return
hm_drop_msg
;
}
case
non_normal_exit_signal
:
{
// this message was handled
// by calling
client
->quit(...)
// by calling
self
->quit(...)
return
hm_msg_handled
;
}
case
timeout_message
:
{
handle_timeout
(
client
,
fun
);
dptr
()
->
handle_timeout
(
self
,
fun
);
if
(
awaited_response
.
valid
())
{
client
->
mark_arrived
(
awaited_response
);
client
->
remove_handler
(
awaited_response
);
self
->
mark_arrived
(
awaited_response
);
//FIXME: self
->remove_handler(awaited_response);
}
return
hm_msg_handled
;
}
...
...
@@ -420,46 +417,50 @@ class invoke_policy_base {
}
case
sync_response
:
{
if
(
awaited_response
.
valid
()
&&
node
->
mid
==
awaited_response
)
{
auto
previous_node
=
Derived
::
hm_begin
(
client
,
node
,
policy
);
auto
res
=
invoke_fun
(
client
,
auto
previous_node
=
dptr
()
->
hm_begin
(
self
,
node
);
auto
res
=
invoke_fun
(
self
,
node
->
msg
,
node
->
mid
,
fun
);
if
(
!
res
&&
handle_sync_failure_on_mismatch
)
{
CPPA_LOGMF
(
CPPA_WARNING
,
client
,
self
,
"sync failure occured in actor with ID "
<<
client
->
id
());
client
->
handle_sync_failure
();
<<
self
->
id
());
self
->
handle_sync_failure
();
}
client
->
mark_arrived
(
awaited_response
);
client
->
remove_handler
(
awaited_response
);
Derived
::
hm_cleanup
(
client
,
previous_node
,
policy
);
self
->
mark_arrived
(
awaited_response
);
//FIXME: self
->remove_handler(awaited_response);
dptr
()
->
hm_cleanup
(
self
,
previous_node
);
return
hm_msg_handled
;
}
return
hm_cache_msg
;
}
case
ordinary_message
:
{
if
(
!
awaited_response
.
valid
())
{
auto
previous_node
=
Derived
::
hm_begin
(
client
,
node
,
policy
);
auto
res
=
invoke_fun
(
client
,
auto
previous_node
=
dptr
()
->
hm_begin
(
self
,
node
);
auto
res
=
invoke_fun
(
self
,
node
->
msg
,
node
->
mid
,
fun
);
if
(
res
)
{
Derived
::
hm_cleanup
(
client
,
previous_node
,
policy
);
dptr
()
->
hm_cleanup
(
self
,
previous_node
);
return
hm_msg_handled
;
}
// no match (restore
client
members)
Derived
::
hm_revert
(
client
,
previous_node
,
policy
);
// no match (restore
self
members)
dptr
()
->
hm_revert
(
self
,
previous_node
);
}
return
hm_cache_msg
;
}
}
}
Derived
*
dptr
()
{
return
static_cast
<
Derived
*>
(
this
);
}
};
}
}
// namespace cppa::policy
#endif // CPPA_
NESTABLE_RECEIV
E_POLICY_HPP
#endif // CPPA_
INVOK
E_POLICY_HPP
cppa/policy/middleman_scheduling.hpp
0 → 100644
View file @
c91bf3fc
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_POLICY_MIDDLEMAN_SCHEDULING_HPP
#define CPPA_POLICY_MIDDLEMAN_SCHEDULING_HPP
#include "cppa/singletons.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/io/middleman.hpp"
#include "cppa/policy/cooperative_scheduling.hpp"
namespace
cppa
{
namespace
policy
{
// Actor must implement invoke_message
class
middleman_scheduling
{
public:
template
<
class
Actor
>
class
continuation
{
public:
typedef
intrusive_ptr
<
Actor
>
pointer
;
continuation
(
pointer
ptr
,
const
message_header
&
hdr
,
any_tuple
&&
msg
)
:
m_self
(
std
::
move
(
ptr
)),
m_hdr
(
hdr
),
m_data
(
std
::
move
(
msg
))
{
}
inline
void
operator
()()
const
{
m_self
->
invoke_message
(
m_hdr
,
move
(
m_data
));
}
private:
pointer
m_self
;
message_header
m_hdr
;
any_tuple
m_data
;
};
using
timeout_type
=
int
;
template
<
class
Actor
>
timeout_type
init_timeout
(
Actor
*
self
,
const
util
::
duration
&
rel_time
)
{
// request explicit timeout message
self
->
request_timeout
(
rel_time
);
return
0
;
// return some dummy value
}
// this does return nullptr
template
<
class
Actor
,
typename
F
>
inline
void
fetch_messages
(
Actor
*
,
F
)
{
// clients cannot fetch messages
}
template
<
class
Actor
,
typename
F
>
inline
void
fetch_messages
(
Actor
*
self
,
F
cb
,
timeout_type
)
{
// a call to this call is always preceded by init_timeout,
// which will trigger a timeout message
fetch_messages
(
self
,
cb
);
}
template
<
class
Actor
>
inline
void
launch
(
Actor
*
)
{
// nothing to do
}
template
<
class
Actor
>
void
enqueue
(
Actor
*
self
,
const
message_header
&
hdr
,
any_tuple
&
msg
)
{
get_middleman
()
->
run_later
(
continuation
<
Actor
>
{
self
,
hdr
,
std
::
move
(
msg
)});
}
};
}
// namespace policy
}
// namespace cppa
#endif // CPPA_POLICY_MIDDLEMAN_SCHEDULING_HPP
cppa/policy/nestable_invoke.hpp
View file @
c91bf3fc
...
...
@@ -44,13 +44,13 @@
#include "cppa/intrusive/single_reader_queue.hpp"
#include "cppa/policy/invoke_policy
_base
.hpp"
#include "cppa/policy/invoke_policy.hpp"
namespace
cppa
{
namespace
detail
{
class
receive_policy
;
}
}
namespace
cppa
{
namespace
policy
{
class
nestable_invoke
:
public
invoke_policy
_base
<
nestable_invoke
>
{
class
nestable_invoke
:
public
invoke_policy
<
nestable_invoke
>
{
typedef
std
::
unique_lock
<
std
::
mutex
>
lock_type
;
...
...
@@ -62,34 +62,32 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> {
template
<
class
Client
>
static
inline
pointer
hm_begin
(
Client
*
client
,
pointer
node
)
{
auto
previous
=
client
->
m_current_node
;
client
->
m_current_node
=
node
;
auto
previous
=
client
->
current_node
()
;
client
->
current_node
(
node
)
;
return
previous
;
}
template
<
class
Client
>
static
inline
void
hm_cleanup
(
Client
*
client
,
pointer
/*previous*/
)
{
client
->
m_current_node
=
&
(
client
->
m_dummy_node
);
if
(
client
->
has_behavior
())
{
client
->
request_timeout
(
client
->
get_behavior
().
timeout
());
}
else
client
->
reset_timeout
();
client
->
current_node
(
&
(
client
->
m_dummy_node
));
}
template
<
class
Client
>
static
inline
void
hm_revert
(
Client
*
client
,
pointer
previous
)
{
client
->
m_current_node
=
previous
;
client
->
current_node
(
previous
)
;
}
typedef
std
::
chrono
::
high_resolution_clock
::
time_point
timeout_type
;
nestable_invoke
()
:
m_initialized
(
false
)
{
}
inline
void
reset_timeout
()
{
}
inline
void
request_timeout
(
const
util
::
duration
&
)
{
}
template
<
class
Actor
>
inline
void
request_timeout
(
Actor
*
,
const
util
::
duration
&
)
{
}
inline
void
handle_timeout
(
behavior
&
bhvr
)
{
bhvr
.
handle_timeout
();
}
template
<
class
Actor
>
inline
void
handle_timeout
(
Actor
*
,
behavior
&
bhvr
)
{
bhvr
.
handle_timeout
();
}
inline
void
pop_timeout
()
{
}
...
...
@@ -97,19 +95,7 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> {
inline
bool
waits_for_timeout
(
std
::
uint32_t
)
{
return
false
;
}
virtual
mailbox_element
*
try_pop
()
{
return
this
->
m_mailbox
.
try_pop
();
}
mailbox_element
*
pop
()
{
wait_for_data
();
return
try_pop
();
}
inline
mailbox_element
*
try_pop
(
const
timeout_type
&
abs_time
)
{
return
(
timed_wait_for_data
(
abs_time
))
?
try_pop
()
:
nullptr
;
}
/*
void run_detached() {
auto dthis = util::dptr<Subtype>(this);
dthis->init();
...
...
@@ -120,87 +106,7 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> {
auto rsn = dthis->planned_exit_reason();
dthis->cleanup(rsn == exit_reason::not_exited ? exit_reason::normal : rsn);
}
inline
void
initialized
(
bool
value
)
{
m_initialized
=
value
;
}
bool
initialized
()
const
override
{
return
m_initialized
;
}
protected:
typedef
threaded
combined_type
;
void
enqueue_impl
(
typename
Base
::
mailbox_type
&
mbox
,
const
message_header
&
hdr
,
any_tuple
&&
msg
)
{
auto
ptr
=
this
->
new_mailbox_element
(
hdr
,
std
::
move
(
msg
));
switch
(
mbox
.
enqueue
(
ptr
))
{
case
intrusive
:
:
first_enqueued
:
{
lock_type
guard
(
m_mtx
);
m_cv
.
notify_one
();
break
;
}
default:
break
;
case
intrusive
:
:
queue_closed
:
if
(
hdr
.
id
.
valid
())
{
detail
::
sync_request_bouncer
f
{
this
->
exit_reason
()};
f
(
hdr
.
sender
,
hdr
.
id
);
}
break
;
}
}
void
enqueue
(
const
message_header
&
hdr
,
any_tuple
msg
)
override
{
enqueue_impl
(
this
->
m_mailbox
,
hdr
,
std
::
move
(
msg
));
}
timeout_type
init_timeout
(
const
util
::
duration
&
rel_time
)
{
auto
result
=
std
::
chrono
::
high_resolution_clock
::
now
();
result
+=
rel_time
;
return
result
;
}
mailbox_element
*
await_message
()
{
return
pop
();
}
mailbox_element
*
await_message
(
const
timeout_type
&
abs_time
)
{
return
try_pop
(
abs_time
);
}
virtual
bool
mailbox_empty
()
{
return
this
->
m_mailbox
.
empty
();
}
bool
timed_wait_for_data
(
const
timeout_type
&
abs_time
)
{
CPPA_REQUIRE
(
not
this
->
m_mailbox
.
closed
());
if
(
mailbox_empty
())
{
lock_type
guard
(
m_mtx
);
while
(
mailbox_empty
())
{
if
(
m_cv
.
wait_until
(
guard
,
abs_time
)
==
std
::
cv_status
::
timeout
)
{
return
false
;
}
}
}
return
true
;
}
void
wait_for_data
()
{
if
(
mailbox_empty
())
{
lock_type
guard
(
m_mtx
);
while
(
mailbox_empty
())
m_cv
.
wait
(
guard
);
}
}
std
::
mutex
m_mtx
;
std
::
condition_variable
m_cv
;
private:
bool
m_initialized
;
*/
};
...
...
cppa/policy/no_resume.hpp
View file @
c91bf3fc
...
...
@@ -5,144 +5,41 @@
#include "cppa/policy/resume_policy.hpp"
namespace
cppa
{
namespace
util
{
struct
fiber
;
}
// namespace util
}
// namespace cppa
namespace
cppa
{
namespace
policy
{
// this policy simply forwards calls to @p await_data to the scheduling
// policy and throws an exception whenever @p resume is called;
// it intentionally works only with the no_scheduling policy
class
no_resume
{
public:
using
timeout_type
=
std
::
chrono
::
high_resolution_clock
::
time_point
;
template
<
class
Base
>
struct
mixin
:
Base
{
template
<
class
Actor
>
timeout_type
init_timeout
(
Actor
*
self
,
const
util
::
duration
&
rel_time
)
{
// request explicit timeout message
self
->
request_timeout
(
rel_time
);
return
0
;
// return some dummy value
}
template
<
typename
...
Ts
>
mixin
(
Ts
&&
...
args
)
:
Base
(
std
::
forward
<
Ts
>
(
args
)...)
{
}
template
<
class
Actor
,
typename
F
>
void
fetch_messages
(
Actor
*
self
,
F
cb
)
{
auto
e
=
self
->
m_mailbox
.
try_pop
();
while
(
e
)
{
cb
(
e
);
e
=
self
->
m_mailbox
.
try_pop
();
inline
resumable
::
resume_result
resume
(
util
::
fiber
*
)
{
this
->
act
();
return
resumable
::
done
;
}
}
template
<
class
Actor
,
typename
F
>
inline
void
fetch_messages
(
Actor
*
self
,
F
cb
,
timeout_type
)
{
// a call to this call is always preceded by init_timeout,
// which will trigger a timeout message
fetch_messages
(
self
,
cb
);
}
};
template
<
class
Actor
,
typename
F
>
void
try_fetch_messages
(
Actor
*
self
,
F
cb
)
{
// try_fetch and fetch have the same semantics for event-based actors
fetch_messages
(
self
,
cb
);
template
<
class
Actor
>
void
await_data
(
Actor
*
self
)
{
self
->
scheduling_policy
().
await_data
(
self
);
}
template
<
class
Actor
>
resume_result
resume
(
Actor
*
self
,
util
::
fiber
*
)
{
CPPA_LOG_TRACE
(
"id = "
<<
self
->
id
()
<<
", state = "
<<
static_cast
<
int
>
(
self
->
state
()));
CPPA_REQUIRE
(
self
->
state
()
==
actor_state
::
ready
||
self
->
state
()
==
actor_state
::
pending
);
auto
done_cb
=
[
&
]()
->
bool
{
CPPA_LOG_TRACE
(
""
);
if
(
self
->
exit_reason
()
==
self
->
exit_reason
::
not_exited
)
{
if
(
self
->
planned_exit_reason
()
==
self
->
exit_reason
::
not_exited
)
{
self
->
planned_exit_reason
(
exit_reason
::
normal
);
}
self
->
on_exit
();
if
(
!
m_bhvr_stack
.
empty
())
{
planned_exit_reason
(
exit_reason
::
not_exited
);
return
false
;
// on_exit did set a new behavior
}
cleanup
(
planned_exit_reason
());
}
set_state
(
actor_state
::
done
);
m_bhvr_stack
.
clear
();
m_bhvr_stack
.
cleanup
();
on_exit
();
CPPA_REQUIRE
(
next_job
==
nullptr
);
return
true
;
};
CPPA_REQUIRE
(
next_job
==
nullptr
);
try
{
//auto e = m_mailbox.try_pop();
for
(
auto
e
=
m_mailbox
.
try_pop
();
;
e
=
m_mailbox
.
try_pop
())
{
//e = m_mailbox.try_pop();
if
(
e
==
nullptr
)
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"no more element in mailbox; going to block"
);
set_state
(
actor_state
::
about_to_block
);
std
::
atomic_thread_fence
(
std
::
memory_order_seq_cst
);
if
(
this
->
m_mailbox
.
can_fetch_more
()
==
false
)
{
switch
(
compare_exchange_state
(
actor_state
::
about_to_block
,
actor_state
::
blocked
))
{
case
actor_state
:
:
ready
:
// interrupted by arriving message
// restore members
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"interrupted by arriving message"
);
break
;
case
actor_state
:
:
blocked
:
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"set state successfully to blocked"
);
// done setting actor to blocked
return
resume_result
::
actor_blocked
;
default:
CPPA_LOGMF
(
CPPA_ERROR
,
self
,
"invalid state"
);
CPPA_CRITICAL
(
"invalid state"
);
};
}
else
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"mailbox can fetch more"
);
set_state
(
actor_state
::
ready
);
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
}
}
else
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"try to invoke message: "
<<
to_string
(
e
->
msg
));
if
(
m_bhvr_stack
.
invoke
(
m_recv_policy
,
this
,
e
))
{
CPPA_LOG_DEBUG_IF
(
m_chained_actor
,
"set actor with ID "
<<
m_chained_actor
->
id
()
<<
" as successor"
);
if
(
m_bhvr_stack
.
empty
()
&&
done_cb
())
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"behavior stack empty"
);
return
resume_result
::
actor_done
;
}
m_bhvr_stack
.
cleanup
();
}
}
}
}
catch
(
actor_exited
&
what
)
{
CPPA_LOG_INFO
(
"actor died because of exception: actor_exited, "
"reason = "
<<
what
.
reason
());
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
what
.
reason
());
}
}
catch
(
std
::
exception
&
e
)
{
CPPA_LOG_WARNING
(
"actor died because of exception: "
<<
detail
::
demangle
(
typeid
(
e
))
<<
", what() = "
<<
e
.
what
());
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
exit_reason
::
unhandled_exception
);
}
}
catch
(...)
{
CPPA_LOG_WARNING
(
"actor died because of an unknown exception"
);
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
exit_reason
::
unhandled_exception
);
}
}
done_cb
();
return
resume_result
::
actor_done
;
template
<
class
Actor
,
typename
AbsTimeout
>
bool
await_data
(
Actor
*
self
,
const
AbsTimeout
&
abs_time
)
{
return
self
->
scheduling_policy
().
await_data
(
self
,
abs_time
);
}
};
...
...
cppa/policy/no_scheduling.hpp
View file @
c91bf3fc
...
...
@@ -33,8 +33,14 @@
#include <mutex>
#include <thread>
#include <chrono>
#include <condition_variable>
#include "cppa/util/fiber.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/policy/scheduling_policy.hpp"
#include "cppa/detail/sync_request_bouncer.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
...
...
@@ -47,6 +53,43 @@ class no_scheduling {
public:
typedef
std
::
chrono
::
high_resolution_clock
::
time_point
timeout_type
;
template
<
class
Actor
>
inline
timeout_type
init_timeout
(
Actor
*
,
const
util
::
duration
&
rel_time
)
{
auto
result
=
std
::
chrono
::
high_resolution_clock
::
now
();
result
+=
rel_time
;
return
result
;
}
template
<
class
Actor
,
typename
F
>
bool
fetch_messages
(
Actor
*
self
,
F
cb
)
{
await_data
(
self
);
fetch_messages_impl
(
self
,
cb
);
}
template
<
class
Actor
,
typename
F
>
bool
try_fetch_messages
(
Actor
*
self
,
F
cb
)
{
auto
next
=
[
&
]
{
return
self
->
mailbox
().
try_pop
();
};
auto
e
=
next
();
if
(
!
e
)
return
false
;
do
{
cb
(
e
);
e
=
next
();
}
while
(
e
);
return
true
;
}
template
<
class
Actor
,
typename
F
>
timed_fetch_result
fetch_messages
(
Actor
*
self
,
F
cb
,
timeout_type
abs_time
)
{
if
(
!
await_data
(
self
,
abs_time
))
{
return
timed_fetch_result
::
no_message
;
}
fetch_messages_impl
(
self
,
cb
);
return
timed_fetch_result
::
success
;
}
template
<
class
Actor
>
void
enqueue
(
Actor
*
self
,
const
message_header
&
hdr
,
any_tuple
&
msg
)
{
auto
ptr
=
self
->
new_mailbox_element
(
hdr
,
std
::
move
(
msg
));
...
...
@@ -69,22 +112,29 @@ class no_scheduling {
template
<
class
Actor
>
void
launch
(
Actor
*
self
)
{
std
::
thread
([
=
]
{
auto
rr
=
resume_result
::
actor_blocked
;
while
(
rr
!=
resume_result
::
actor_done
)
{
wait_for_data
();
self
->
resume
();
util
::
fiber
fself
;
auto
rr
=
resumable
::
resume_later
;
while
(
rr
!=
resumable
::
done
)
{
await_data
(
self
);
self
->
resume
(
&
fself
);
}
}).
detach
();
}
private:
template
<
class
Actor
>
void
await_data
(
Actor
*
self
)
{
if
(
self
->
mailbox
().
empty
())
{
lock_type
guard
(
m_mtx
);
while
(
self
->
mailbox
().
empty
())
m_cv
.
wait
(
guard
);
}
}
bool
timed_wait_for_data
(
const
timeout_type
&
abs_time
)
{
CPPA_REQUIRE
(
not
this
->
m_mailbox
.
closed
());
if
(
mailbox_empty
())
{
template
<
class
Actor
>
bool
await_data
(
Actor
*
self
,
const
timeout_type
&
abs_time
)
{
CPPA_REQUIRE
(
!
self
->
mailbox
().
closed
());
if
(
self
->
mailbox
().
empty
())
{
lock_type
guard
(
m_mtx
);
while
(
mailbox_
empty
())
{
while
(
self
->
mailbox
().
empty
())
{
if
(
m_cv
.
wait_until
(
guard
,
abs_time
)
==
std
::
cv_status
::
timeout
)
{
return
false
;
}
...
...
@@ -93,11 +143,15 @@ class no_scheduling {
return
true
;
}
void
wait_for_data
()
{
if
(
mailbox_empty
())
{
lock_type
guard
(
m_mtx
);
while
(
mailbox_empty
())
m_cv
.
wait
(
guard
);
private:
template
<
class
Actor
,
typename
F
>
void
fetch_messages_impl
(
Actor
*
self
,
F
cb
)
{
auto
next
=
[
&
]
{
return
self
->
mailbox
().
try_pop
();
};
for
(
auto
e
=
next
();
e
!=
nullptr
;
e
=
next
())
{
cb
(
e
);
}
}
std
::
mutex
m_mtx
;
...
...
cppa/
detail/scheduled_actor_dummy
.hpp
→
cppa/
policy/not_prioritizing
.hpp
View file @
c91bf3fc
...
...
@@ -28,24 +28,31 @@
\******************************************************************************/
#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
*
)
override
;
void
quit
(
std
::
uint32_t
)
override
;
void
dequeue
(
behavior
&
)
override
;
void
dequeue_response
(
behavior
&
,
message_id
)
override
;
bool
has_behavior
()
override
;
scheduled_actor_type
impl_type
()
override
;
#ifndef NOT_PRIORITIZING_HPP
#define NOT_PRIORITIZING_HPP
#include "cppa/mailbox_element.hpp"
#include "cppa/policy/priority_policy.hpp"
namespace
cppa
{
namespace
policy
{
struct
not_prioritizing
{
template
<
class
Actor
>
mailbox_element
*
next_message
(
Actor
*
self
)
{
return
self
->
mailbox
().
try_pop
();
}
template
<
class
Actor
,
typename
F
>
bool
fetch_messages
(
Actor
*
,
F
)
{
//FIXME
}
};
}
}
// namespace cppa::detail
}
// namespace policy
}
// namespace cppa
#endif //
CPPA_SCHEDULED_ACTOR_DUMMY
_HPP
#endif //
NOT_PRIORITIZING
_HPP
cppa/policy/priority_policy.hpp
View file @
c91bf3fc
...
...
@@ -62,7 +62,7 @@ class priority_policy {
* for re-scheduling.
*/
template
<
class
Actor
,
typename
F
>
bool
fetch_messages
(
Actor
*
self
);
bool
fetch_messages
(
Actor
*
self
,
F
cb
);
};
...
...
cppa/policy/resume_policy.hpp
View file @
c91bf3fc
...
...
@@ -31,18 +31,15 @@
#ifndef CPPA_RESUME_POLICY_HPP
#define CPPA_RESUME_POLICY_HPP
#include "cppa/resumable.hpp"
// this header consists all type definitions needed to
// implement the resume_policy trait
namespace
cppa
{
namespace
util
{
class
duration
;
}
}
namespace
cppa
{
namespace
util
{
class
duration
;
struct
fiber
;
}
}
namespace
cppa
{
namespace
policy
{
enum
class
resume_result
{
actor_blocked
,
actor_done
};
/**
* @brief The resume_policy <b>concept</b> class. Please note that this
* class is <b>not</b> implemented. It only explains the all
...
...
@@ -59,7 +56,7 @@ class resume_policy {
* actor finishes execution.
*/
template
<
class
Actor
>
resume_result
resume
(
Actor
*
self
,
util
::
fiber
*
from
);
resum
able
::
resum
e_result
resume
(
Actor
*
self
,
util
::
fiber
*
from
);
/**
* @brief Waits unconditionally until a new message arrives.
...
...
cppa/policy/sequential_invoke.hpp
View file @
c91bf3fc
...
...
@@ -36,14 +36,14 @@
#include "cppa/util/duration.hpp"
#include "cppa/policy/invoke_policy
_base
.hpp"
#include "cppa/policy/invoke_policy.hpp"
namespace
cppa
{
namespace
policy
{
/**
* @brief An actor that is scheduled or otherwise managed.
*/
class
sequential_invoke
:
public
invoke_policy
_base
<
sequential_invoke
>
{
class
sequential_invoke
:
public
invoke_policy
<
sequential_invoke
>
{
public:
...
...
@@ -53,26 +53,26 @@ class sequential_invoke : public invoke_policy_base<sequential_invoke> {
return
node
->
marked
;
}
template
<
class
Client
>
static
inline
pointer
hm_begin
(
Client
*
client
,
pointer
node
)
{
auto
previous
=
client
->
m_current_node
;
client
->
m_current_node
=
node
;
client
->
push_timeout
();
template
<
class
Actor
>
inline
pointer
hm_begin
(
Actor
*
self
,
pointer
node
)
{
auto
previous
=
self
->
m_current_node
;
self
->
m_current_node
=
node
;
push_timeout
();
node
->
marked
=
true
;
return
previous
;
}
template
<
class
Client
>
static
inline
void
hm_cleanup
(
Client
*
client
,
pointer
previous
)
{
client
->
m_current_node
->
marked
=
false
;
client
->
m_current_node
=
previous
;
template
<
class
Actor
>
inline
void
hm_cleanup
(
Actor
*
self
,
pointer
previous
)
{
self
->
m_current_node
->
marked
=
false
;
self
->
m_current_node
=
previous
;
}
template
<
class
Client
>
static
inline
void
hm_revert
(
Client
*
client
,
pointer
previous
)
{
client
->
m_current_node
->
marked
=
false
;
client
->
m_current_node
=
previous
;
client
->
pop_timeout
();
template
<
class
Actor
>
inline
void
hm_revert
(
Actor
*
self
,
pointer
previous
)
{
self
->
m_current_node
->
marked
=
false
;
self
->
m_current_node
=
previous
;
pop_timeout
();
}
inline
void
reset_timeout
()
{
...
...
@@ -82,22 +82,24 @@ class sequential_invoke : public invoke_policy_base<sequential_invoke> {
}
}
void
request_timeout
(
const
util
::
duration
&
d
)
{
template
<
class
Actor
>
void
request_timeout
(
Actor
*
self
,
const
util
::
duration
&
d
)
{
if
(
!
d
.
valid
())
m_has_pending_tout
=
false
;
else
{
auto
msg
=
make_any_tuple
(
atom
(
"SYNC_TOUT"
),
++
m_pending_tout
);
if
(
d
.
is_zero
())
{
// immediately enqueue timeout message if duration == 0s
this
->
enqueue
({
this
->
address
(),
this
},
std
::
move
(
msg
));
self
->
enqueue
({
self
->
address
(),
self
},
std
::
move
(
msg
));
//auto e = this->new_mailbox_element(this, std::move(msg));
//this->m_mailbox.enqueue(e);
}
else
this
->
delayed_send_tuple
(
this
,
d
,
std
::
move
(
msg
));
else
self
->
delayed_send_tuple
(
self
,
d
,
std
::
move
(
msg
));
m_has_pending_tout
=
true
;
}
}
inline
void
handle_timeout
(
behavior
&
bhvr
)
{
template
<
class
Actor
>
inline
void
handle_timeout
(
Actor
*
,
behavior
&
bhvr
)
{
bhvr
.
handle_timeout
();
reset_timeout
();
}
...
...
cppa/
thread_mapped_actor
.hpp
→
cppa/
resumable
.hpp
View file @
c91bf3fc
...
...
@@ -28,64 +28,32 @@
\******************************************************************************/
#ifndef CPPA_THREAD_BASED_ACTOR_HPP
#define CPPA_THREAD_BASED_ACTOR_HPP
#include "cppa/config.hpp"
#include <map>
#include <list>
#include <mutex>
#include <stack>
#include <atomic>
#include <vector>
#include <memory>
#include <cstdint>
#include "cppa/atom.hpp"
#include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/threaded.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/detail/receive_policy.hpp"
#ifndef CPPA_RESUMABLE_HPP
#define CPPA_RESUMABLE_HPP
namespace
cppa
{
class
self_type
;
class
scheduler_helper
;
/**
* @brief An actor using the blocking API running in its own thread.
* @extends local_actor
*/
class
thread_mapped_actor
:
public
extend
<
local_actor
,
thread_mapped_actor
>::
with
<
stacked
,
threaded
>
{
namespace
util
{
struct
fiber
;
}
// namespace util
typedef
combined_type
super
;
struct
resumable
{
public:
enum
resume_result
{
resume_later
,
done
};
thread_mapped_actor
();
// intrusive next pointer needed to use
// 'resumable' with 'single_reader_queue'
resumable
*
next
;
thread_mapped_actor
(
std
::
function
<
void
()
>
fun
);
virtual
~
resumable
(
);
inline
void
initialized
(
bool
value
)
{
m_initialized
=
value
;
}
bool
initialized
()
const
override
;
private:
bool
m_initialized
;
virtual
resume_result
resume
(
util
::
fiber
*
)
=
0
;
};
typedef
intrusive_ptr
<
thread_mapped_actor
>
thread_mapped_actor_ptr
;
}
// namespace cppa
#endif // CPPA_
THREAD_BASED_ACTOR
_HPP
#endif // CPPA_
RESUMABLE
_HPP
cppa/sb_actor.hpp
View file @
c91bf3fc
...
...
@@ -35,7 +35,7 @@
#include <type_traits>
#include "cppa/util/dptr.hpp"
#include "cppa/
event_bas
ed_actor.hpp"
#include "cppa/
untyp
ed_actor.hpp"
namespace
cppa
{
...
...
@@ -45,11 +45,11 @@ namespace cppa {
* to initialize the derived actor with its @p init_state member.
* @tparam Derived Direct subclass of @p sb_actor.
*/
template
<
class
Derived
,
class
Base
=
event_bas
ed_actor
>
template
<
class
Derived
,
class
Base
=
untyp
ed_actor
>
class
sb_actor
:
public
Base
{
static_assert
(
std
::
is_base_of
<
event_bas
ed_actor
,
Base
>::
value
,
"Base must be either
event_bas
ed_actor or a derived type"
);
static_assert
(
std
::
is_base_of
<
untyp
ed_actor
,
Base
>::
value
,
"Base must be either
untyp
ed_actor or a derived type"
);
protected:
...
...
@@ -58,11 +58,11 @@ class sb_actor : public Base {
public:
/**
* @brief Overrides {@link
event_bas
ed_actor::init()} and sets
* @brief Overrides {@link
untyp
ed_actor::init()} and sets
* the initial actor behavior to <tt>Derived::init_state</tt>.
*/
void
init
()
override
{
become
(
util
::
dptr
<
Derived
>
(
this
)
->
init_state
)
;
behavior
make_behavior
()
override
{
return
util
::
dptr
<
Derived
>
(
this
)
->
init_state
;
}
protected:
...
...
cppa/scheduled_actor.hpp
deleted
100644 → 0
View file @
3eee072f
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_BEHAVIOR_HPP
#define CPPA_ACTOR_BEHAVIOR_HPP
#include <functional>
#include "cppa/config.hpp"
#include "cppa/extend.hpp"
#include "cppa/threadless.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/message_priority.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace
cppa
{
class
scheduler
;
namespace
util
{
struct
fiber
;
}
enum
scheduled_actor_type
{
context_switching_impl
,
// enqueued to the job queue on startup
event_based_impl
,
// not enqueued to the job queue on startup
default_event_based_impl
// scheduler enqueues a 'RUN' message on startup
};
class
scheduled_actor
;
/**
* @brief A base class for cooperatively scheduled actors.
* @extends local_actor
*/
class
scheduled_actor
:
public
extend
<
local_actor
>::
with
<
threadless
>
{
typedef
combined_type
super
;
public:
~
scheduled_actor
();
/**
* @brief Intrusive next pointer needed by the scheduler's job queue.
*/
scheduled_actor
*
next
;
/**
* @brief Continues execution of this actor.
* @param next_job Denotes the next actor to be resumed, should be
* set in case of chaining.
* @note This member function is called from the scheduler's worker threads.
*/
virtual
resume_result
resume
(
util
::
fiber
*
from
)
=
0
;
/**
* @brief Called once by the scheduler after actor is initialized,
* but before @p resume is called.
*/
void
attach_to_scheduler
(
scheduler
*
sched
,
bool
hidden
);
/**
* @brief Returns @p false if this actor can be disposed immediately
* after construction, @p true otherwise.
*/
virtual
bool
has_behavior
()
=
0
;
/**
* @brief Denotes wheter this actor is enqueued to the scheduler's
* job queue on startup.
*/
virtual
scheduled_actor_type
impl_type
()
=
0
;
/**
* @brief Returns @p true if this actor is ignored by
* {@link await_all_actors_done()}, false otherwise.
*/
inline
bool
is_hidden
()
const
;
virtual
void
run_detached
();
void
enqueue
(
const
message_header
&
,
any_tuple
)
override
;
protected:
scheduled_actor
(
actor_state
init_state
,
bool
enable_chained_send
);
void
cleanup
(
std
::
uint32_t
reason
)
override
;
typedef
intrusive
::
single_reader_queue
<
mailbox_element
,
detail
::
disposer
>
mailbox_type
;
actor_state
compare_exchange_state
(
actor_state
expected
,
actor_state
desired
);
inline
void
set_state
(
actor_state
new_value
)
{
m_state
.
store
(
new_value
);
}
inline
actor_state
state
()
const
{
return
m_state
;
}
bool
initialized
()
const
;
private:
bool
enqueue_impl
(
actor_state
,
const
message_header
&
,
any_tuple
&&
);
std
::
atomic
<
actor_state
>
m_state
;
protected:
scheduler
*
m_scheduler
;
bool
m_hidden
;
};
typedef
intrusive_ptr
<
scheduled_actor
>
scheduled_actor_ptr
;
inline
bool
scheduled_actor
::
is_hidden
()
const
{
return
m_hidden
;
}
}
// namespace cppa
#endif // CPPA_ACTOR_BEHAVIOR_HPP
cppa/scheduler.hpp
View file @
c91bf3fc
...
...
@@ -41,8 +41,8 @@
#include "cppa/actor.hpp"
#include "cppa/channel.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/resumable.hpp"
#include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/util/duration.hpp"
...
...
@@ -52,7 +52,7 @@ namespace cppa {
class
untyped_actor
;
class
scheduled_actor
;
class
scheduler_helper
;
class
event_bas
ed_actor
;
class
untyp
ed_actor
;
typedef
intrusive_ptr
<
scheduled_actor
>
scheduled_actor_ptr
;
namespace
detail
{
class
singleton_manager
;
}
// namespace detail
...
...
@@ -83,12 +83,9 @@ class scheduler {
public:
typedef
std
::
function
<
void
(
local_actor
*
)
>
init_callback
;
typedef
std
::
function
<
behavior
(
untyped_actor
*
)
>
actor_fun
;
const
actor
&
printer
()
const
;
actor
printer
()
const
;
virtual
void
enqueue
(
scheduled_actor
*
)
=
0
;
virtual
void
enqueue
(
resumable
*
)
=
0
;
/**
* @brief Informs the scheduler about a converted context
...
...
@@ -128,33 +125,13 @@ class scheduler {
//TODO: delayed_send_helper()->enqueue(nullptr, std::move(tup));
}
/**
* @brief Executes @p ptr in this scheduler.
*/
virtual
local_actor_ptr
exec
(
spawn_options
opts
,
scheduled_actor_ptr
ptr
)
=
0
;
/**
* @brief Creates a new actor from @p actor_behavior and executes it
* in this scheduler.
*/
virtual
local_actor_ptr
exec
(
spawn_options
opts
,
init_callback
init_cb
,
actor_fun
actor_behavior
)
=
0
;
template
<
typename
F
,
typename
T
,
typename
...
Ts
>
local_actor_ptr
exec
(
spawn_options
opts
,
init_callback
cb
,
F
f
,
T
&&
a0
,
Ts
&&
...
as
)
{
return
this
->
exec
(
opts
,
cb
,
std
::
bind
(
f
,
std
::
forward
<
T
>
(
a0
),
std
::
forward
<
Ts
>
(
as
)...));
}
private:
static
scheduler
*
create_singleton
();
inline
void
dispose
()
{
delete
this
;
}
actor
&
delayed_send_helper
();
actor
delayed_send_helper
();
scheduler_helper
*
m_helper
;
...
...
cppa/scoped_actor.hpp
View file @
c91bf3fc
...
...
@@ -25,131 +25,55 @@
* *
* 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_SCOPED_ACTOR_HPP
#define CPPA_SCOPED_ACTOR_HPP
#include "cppa/behavior.hpp"
#include "cppa/
thread_map
ped_actor.hpp"
#include "cppa/
blocking_unty
ped_actor.hpp"
namespace
cppa
{
class
scoped_actor
{
public:
/**
* @brief Dequeues the next message from the mailbox that
* is matched by given behavior.
*/
template
<
typename
...
Ts
>
void
receive
(
Ts
&&
...
args
);
/**
* @brief Receives messages in an endless loop.
* Semantically equal to: <tt>for (;;) { receive(...); }</tt>
*/
template
<
typename
...
Ts
>
void
receive_loop
(
Ts
&&
...
args
);
/**
* @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
>
detail
::
receive_for_helper
<
T
>
receive_for
(
T
&
begin
,
const
T
&
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
>
detail
::
receive_while_helper
<
Statement
>
receive_while
(
Statement
&&
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
>
detail
::
do_receive_helper
do_receive
(
Ts
&&
...
args
);
private:
intrusive_ptr
<
thread_mapped_actor
>
m_self
;
public:
scoped_actor
();
~
scoped_actor
();
inline
blocking_untyped_actor
*
operator
->
()
const
{
return
m_self
.
get
();
}
inline
blocking_untyped_actor
&
operator
*
()
const
{
return
*
m_self
;
}
inline
blocking_untyped_actor
*
get
()
const
{
return
m_self
.
get
();
}
operator
channel
()
const
{
return
get
();
}
operator
actor
()
const
{
return
get
();
}
operator
actor_addr
()
const
{
return
get
()
->
address
();
}
private:
intrusive_ptr
<
blocking_untyped_actor
>
m_self
;
};
/******************************************************************************
* inline and template function implementations *
******************************************************************************/
template
<
typename
...
Ts
>
void
scoped_actor
::
receive
(
Ts
&&
...
args
)
{
m_self
->
receive
(
std
::
forward
<
Ts
(
args
)...);
}
template
<
typename
...
Ts
>
void
scoped_actor
::
receive_loop
(
Ts
&&
...
args
)
{
m_self
->
receive_loop
(
std
::
forward
<
Ts
(
args
)...);
}
template
<
typename
T
>
detail
::
receive_for_helper
<
T
>
scoped_actor
::
receive_for
(
T
&
begin
,
const
T
&
end
)
{
m_self
->
receive_for
(
begin
,
end
);
}
template
<
typename
Statement
>
detail
::
receive_while_helper
<
Statement
>
scoped_actor
::
receive_while
(
Statement
&&
stmt
)
{
m_self
->
receive_while
(
std
::
forward
<
Statement
(
stmt
));
}
template
<
typename
...
Ts
>
detail
::
do_receive_helper
scoped_actor
::
do_receive
(
Ts
&&
...
args
)
{
m_self
->
do_receive
(
std
::
forward
<
Ts
(
args
)...);
}
}
// namespace cppa
#endif // CPPA_SCOPED_ACTOR_HPP
cppa/spawn.hpp
View file @
c91bf3fc
...
...
@@ -39,17 +39,11 @@
#include "cppa/spawn_options.hpp"
#include "cppa/detail/proper_actor.hpp"
#include "cppa/detail/functor_based_actor.hpp"
#include "cppa/detail/functor_based_blocking_actor.hpp"
namespace
cppa
{
/** @cond PRIVATE */
constexpr
bool
unbound_spawn_options
(
spawn_options
opts
)
{
return
!
has_monitor_flag
(
opts
)
&&
!
has_link_flag
(
opts
);
}
/** @endcond */
/**
* @ingroup ActorCreation
* @{
...
...
@@ -58,17 +52,21 @@ constexpr bool unbound_spawn_options(spawn_options opts) {
/**
* @brief Spawns an actor of type @p Impl.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link
event_bas
ed_actor} or {@link sb_actor}.
* @tparam Impl Subtype of {@link
untyp
ed_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor} to the spawned {@link actor}.
*/
template
<
class
Impl
,
spawn_options
Options
=
no_spawn_options
,
typename
...
Ts
>
template
<
class
Impl
,
spawn_options
Options
,
typename
...
Ts
>
actor
spawn
(
Ts
&&
...
args
)
{
static_assert
(
std
::
is_base_of
<
event_based_actor
,
Impl
>::
value
,
"Impl is not a derived type of event_based_actor"
);
static_assert
(
unbound_spawn_options
(
Options
),
static_assert
(
std
::
is_base_of
<
untyped_actor
,
Impl
>::
value
||
(
std
::
is_base_of
<
blocking_untyped_actor
,
Impl
>::
value
&&
has_blocking_api_flag
(
Options
)),
"Impl is not a derived type of untyped_actor or "
"is a derived type of blocking_untyped_actor but "
"blocking_api_flag is missing"
);
static_assert
(
is_unbound
(
Options
),
"top-level spawns cannot have monitor or link flag"
);
static_assert
(
unbound_spawn_options
(
Options
),
static_assert
(
is_unbound
(
Options
),
"top-level spawns cannot have monitor or link flag"
);
using
scheduling_policy
=
typename
std
::
conditional
<
has_detach_flag
(
Options
),
...
...
@@ -100,6 +98,8 @@ actor spawn(Ts&&... args) {
resume_policy
,
invoke_policy
>
;
auto
ptr
=
make_counted
<
proper_impl
>
(
std
::
forward
<
Ts
>
(
args
)...);
ptr
->
launch
();
return
ptr
;
/*
scheduled_actor_ptr ptr;
if (has_priority_aware_flag(Options)) {
...
...
@@ -121,7 +121,8 @@ actor spawn(Ts&&... args) {
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor} to the spawned {@link actor}.
*/
template
<
spawn_options
Options
=
no_spawn_options
,
typename
...
Ts
>
//template<spawn_options Options = no_spawn_options, typename... Ts>
template
<
spawn_options
Options
,
typename
...
Ts
>
actor
spawn
(
Ts
&&
...
args
)
{
static_assert
(
sizeof
...(
Ts
)
>
0
,
"too few arguments provided"
);
using
base_class
=
typename
std
::
conditional
<
...
...
@@ -129,13 +130,7 @@ actor spawn(Ts&&... args) {
detail
::
functor_based_blocking_actor
,
detail
::
functor_based_actor
>::
type
;
return
spawn
<
base_class
>
(
std
::
forward
<
Ts
>
(
args
)...);
using
impl
=
detail
::
proper_actor
<
untyped_actor
,
scheduling_policy
,
priority_policy
,
resume_policy
,
invoke_policy
>
;
return
make_counted
<
impl
>
();
return
spawn
<
base_class
,
Options
>
(
std
::
forward
<
Ts
>
(
args
)...);
}
/**
...
...
@@ -163,7 +158,7 @@ actor spawn_in_group(const group_ptr& grp, Ts&&... args) {
/**
* @brief Spawns an actor of type @p Impl that immediately joins @p grp.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link
event_bas
ed_actor} or {@link sb_actor}.
* @tparam Impl Subtype of {@link
untyp
ed_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns.
...
...
cppa/spawn_options.hpp
View file @
c91bf3fc
...
...
@@ -173,6 +173,21 @@ constexpr bool has_blocking_api_flag(spawn_options opts) {
/** @} */
/** @cond PRIVATE */
constexpr
bool
is_unbound
(
spawn_options
opts
)
{
return
!
has_monitor_flag
(
opts
)
&&
!
has_link_flag
(
opts
);
}
constexpr
spawn_options
make_unbound
(
spawn_options
opts
)
{
return
static_cast
<
spawn_options
>
(
(
static_cast
<
int
>
(
opts
)
&
~
static_cast
<
int
>
(
spawn_options
::
link_flag
))
&
~
static_cast
<
int
>
(
spawn_options
::
monitor_flag
));
}
/** @endcond */
}
// namespace cppa
#endif // CPPA_SPAWN_OPTIONS_HPP
cppa/to_string.hpp
View file @
c91bf3fc
...
...
@@ -72,6 +72,10 @@ inline std::string to_string(const actor& what) {
return
detail
::
to_string_impl
(
what
);
}
inline
std
::
string
to_string
(
const
actor_addr
&
what
)
{
return
detail
::
to_string_impl
(
what
);
}
inline
std
::
string
to_string
(
const
group_ptr
&
what
)
{
return
detail
::
to_string_impl
(
what
);
}
...
...
cppa/typed_actor.hpp
View file @
c91bf3fc
...
...
@@ -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_TYPED_ACTOR_HPP
...
...
cppa/typed_actor_base.hpp
View file @
c91bf3fc
...
...
@@ -34,7 +34,7 @@
#include "cppa/replies_to.hpp"
#include "cppa/typed_behavior.hpp"
#include "cppa/message_future.hpp"
#include "cppa/
event_bas
ed_actor.hpp"
#include "cppa/
untyp
ed_actor.hpp"
#include "cppa/detail/typed_actor_util.hpp"
...
...
@@ -44,7 +44,7 @@ template<typename... Signatures>
class
typed_actor_ptr
;
template
<
typename
...
Signatures
>
class
typed_actor
:
public
event_bas
ed_actor
{
class
typed_actor
:
public
untyp
ed_actor
{
public:
...
...
cppa/untyped_actor.hpp
View file @
c91bf3fc
...
...
@@ -25,103 +25,30 @@
* *
* 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_UNTYPED_ACTOR_HPP
#define CPPA_UNTYPED_ACTOR_HPP
#include "cppa/extend.hpp"
#include "cppa/stackless.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/behavior_stack_based.hpp"
namespace
cppa
{
/**
* @extends local_actor
*/
class
untyped_actor
:
public
local_actor
{
bool
has_behavior
()
{
return
this
->
m_bhvr_stack
.
empty
()
==
false
;
}
void
unbecome
()
{
this
->
m_bhvr_stack
.
pop_async_back
();
}
/**
* @brief Sets the actor's behavior and discards the previous behavior
* unless {@link keep_behavior} is given as first argument.
*/
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
(
match_expr_convert
(
std
::
forward
<
T
>
(
arg
),
std
::
forward
<
Ts
>
(
args
)...),
true
);
}
template
<
bool
Discard
,
typename
...
Ts
>
inline
void
become
(
behavior_policy
<
Discard
>
,
Ts
&&
...
args
)
{
do_become
(
match_expr_convert
(
std
::
forward
<
Ts
>
(
args
)...),
Discard
);
}
void
become_waiting_for
(
behavior
bhvr
,
message_id
mf
)
{
if
(
bhvr
.
timeout
().
valid
())
{
this
->
reset_timeout
();
this
->
request_timeout
(
bhvr
.
timeout
());
}
this
->
m_bhvr_stack
.
push_back
(
std
::
move
(
bhvr
),
mf
);
}
void
do_become
(
behavior
&&
bhvr
,
bool
discard_old
)
{
this
->
reset_timeout
();
this
->
request_timeout
(
bhvr
.
timeout
());
if
(
discard_old
)
this
->
m_bhvr_stack
.
pop_async_back
();
this
->
m_bhvr_stack
.
push_back
(
std
::
move
(
bhvr
));
}
inline
bool
has_behavior
()
const
{
return
this
->
m_bhvr_stack
.
empty
()
==
false
;
}
inline
behavior
&
get_behavior
()
{
CPPA_REQUIRE
(
this
->
m_bhvr_stack
.
empty
()
==
false
);
return
this
->
m_bhvr_stack
.
back
();
}
inline
void
handle_timeout
(
behavior
&
bhvr
)
{
CPPA_REQUIRE
(
bhvr
.
timeout
().
valid
());
this
->
reset_timeout
();
bhvr
.
handle_timeout
();
if
(
this
->
m_bhvr_stack
.
empty
()
==
false
)
{
this
->
request_timeout
(
get_behavior
().
timeout
());
}
}
void
exec_bhvr_stack
()
{
while
(
!
m_bhvr_stack
.
empty
())
{
m_bhvr_stack
.
exec
(
m_recv_policy
,
util
::
dptr
<
Subtype
>
(
this
));
}
}
inline
detail
::
behavior_stack
&
bhvr_stack
()
{
return
m_bhvr_stack
;
}
inline
optional
<
behavior
&>
sync_handler
(
message_id
msg_id
)
{
return
m_bhvr_stack
.
sync_handler
(
msg_id
);
}
class
untyped_actor
:
public
extend
<
local_actor
>::
with
<
mailbox_based
,
behavior_stack_based
>
{
protected:
// allows actors to keep previous behaviors and enables unbecome()
detail
::
behavior_stack
m_bhvr_stack
;
virtual
behavior
make_behavior
()
=
0
;
void
forward_to
(
const
actor
&
other
);
};
...
...
examples/curl/curl_fuse.cpp
View file @
c91bf3fc
...
...
@@ -110,17 +110,17 @@ constexpr int min_req_interval = 10;
constexpr
int
max_req_interval
=
300
;
const
actor_ostream
&
print
(
const
char
*
color_code
,
const
char
*
actor_name
)
{
return
aout
<<
color_code
<<
actor_name
<<
" (id = "
<<
self
->
id
()
<<
"): "
;
return
aout
<<
color_code
<<
actor_name
;
//
<< " (id = " << self->id() << "): ";
}
}
// namespace <anonymous>
// provides print utility and each base_actor has a parent
class
base_actor
:
public
event_bas
ed_actor
{
class
base_actor
:
public
untyp
ed_actor
{
protected:
base_actor
(
actor
_ptr
parent
,
std
::
string
name
,
std
::
string
color_code
)
base_actor
(
actor
parent
,
std
::
string
name
,
std
::
string
color_code
)
:
m_parent
(
std
::
move
(
parent
))
,
m_name
(
std
::
move
(
name
))
,
m_color
(
std
::
move
(
color_code
))
{
}
...
...
@@ -133,7 +133,7 @@ class base_actor : public event_based_actor {
print
()
<<
"on_exit"
<<
color
::
reset_endl
;
}
actor
_ptr
m_parent
;
actor
m_parent
;
private:
...
...
@@ -147,19 +147,19 @@ class client_job : public base_actor {
public:
client_job
(
actor
_ptr
parent
)
client_job
(
actor
parent
)
:
base_actor
(
std
::
move
(
parent
),
"client_job"
,
color
::
blue
)
{
}
protected:
void
init
()
override
{
behavior
make_behavior
()
override
{
print
()
<<
"init"
<<
color
::
reset_endl
;
send
(
m_parent
,
atom
(
"read"
),
"http://www.example.com/index.html"
,
static_cast
<
uint64_t
>
(
0
),
static_cast
<
uint64_t
>
(
4095
));
become
(
return
(
on
(
atom
(
"reply"
),
arg_match
)
>>
[
=
](
const
util
::
buffer
&
buf
)
{
print
()
<<
"successfully received "
<<
buf
.
size
()
...
...
@@ -181,18 +181,18 @@ class client : public base_actor {
public:
client
(
const
actor
_ptr
&
parent
)
client
(
const
actor
&
parent
)
:
base_actor
(
parent
,
"client"
,
color
::
green
),
m_count
(
0
)
{
}
protected:
void
init
()
override
{
behavior
make_behavior
()
override
{
using
std
::
chrono
::
milliseconds
;
link_to
(
m_parent
);
print
()
<<
"init"
<<
color
::
reset_endl
;
// start 'loop'
send
(
this
,
atom
(
"next"
));
become
(
return
(
on
(
atom
(
"next"
))
>>
[
=
]
{
print
()
<<
"spawn new client_job (nr. "
<<
++
m_count
...
...
@@ -203,7 +203,7 @@ class client : public base_actor {
spawn
<
client_job
,
detached
+
linked
>
(
m_parent
);
// compute random delay until next job is launched
auto
delay
=
(
rand
()
+
min_req_interval
)
%
max_req_interval
;
delayed_send
(
self
,
milliseconds
(
delay
),
atom
(
"next"
));
delayed_send
(
this
,
milliseconds
(
delay
),
atom
(
"next"
));
}
);
}
...
...
@@ -219,17 +219,17 @@ class curl_worker : public base_actor {
public:
curl_worker
(
const
actor
_ptr
&
parent
)
curl_worker
(
const
actor
&
parent
)
:
base_actor
(
parent
,
"curl_worker"
,
color
::
yellow
)
{
}
protected:
void
init
()
override
{
behavior
make_behavior
()
override
{
print
()
<<
"init"
<<
color
::
reset_endl
;
m_curl
=
curl_easy_init
();
curl_easy_setopt
(
m_curl
,
CURLOPT_WRITEFUNCTION
,
&
curl_worker
::
cb
);
curl_easy_setopt
(
m_curl
,
CURLOPT_NOSIGNAL
,
1
);
become
(
return
(
on
(
atom
(
"read"
),
arg_match
)
>>
[
=
](
const
std
::
string
&
fname
,
uint64_t
offset
,
uint64_t
range
)
->
cow_tuple
<
atom_value
,
util
::
buffer
>
{
...
...
@@ -314,31 +314,32 @@ class curl_master : public base_actor {
protected:
void
init
()
override
{
behavior
make_behavior
()
override
{
print
()
<<
"init"
<<
color
::
reset_endl
;
// spawn workers
for
(
size_t
i
=
0
;
i
<
num_curl_workers
;
++
i
)
{
m_idle_worker
.
push_back
(
spawn
<
curl_worker
,
detached
+
linked
>
(
this
));
}
auto
worker_finished
=
[
=
]
{
actor_ptr
sender
=
self
->
last_sender
();
m_busy_worker
.
erase
(
std
::
find
(
m_busy_worker
.
begin
(),
m_busy_worker
.
end
(),
sender
));
m_idle_worker
.
push_back
(
sender
);
auto
sender
=
last_sender
();
auto
i
=
std
::
find
(
m_busy_worker
.
begin
(),
m_busy_worker
.
end
(),
sender
);
m_idle_worker
.
push_back
(
*
i
);
m_busy_worker
.
erase
(
i
);
print
()
<<
"worker is done"
<<
color
::
reset_endl
;
};
print
()
<<
"spawned "
<<
m_idle_worker
.
size
()
<<
" worker"
<<
color
::
reset_endl
;
become
(
return
(
on
(
atom
(
"read"
),
arg_match
)
>>
[
=
](
const
std
::
string
&
,
uint64_t
,
uint64_t
)
{
print
()
<<
"received {'read'}"
<<
color
::
reset_endl
;
// forward job to first idle worker
actor
_ptr
worker
=
m_idle_worker
.
front
();
actor
worker
=
m_idle_worker
.
front
();
m_idle_worker
.
erase
(
m_idle_worker
.
begin
());
m_busy_worker
.
push_back
(
worker
);
forward_to
(
worker
);
...
...
@@ -364,8 +365,8 @@ class curl_master : public base_actor {
private:
std
::
vector
<
actor
_ptr
>
m_idle_worker
;
std
::
vector
<
actor
_ptr
>
m_busy_worker
;
std
::
vector
<
actor
>
m_idle_worker
;
std
::
vector
<
actor
>
m_busy_worker
;
};
...
...
@@ -394,7 +395,7 @@ int main() {
while
(
!
shutdown_flag
)
{
sleep
(
1
);
}
aout
<<
color
::
cyan
<<
"received CTRL+C"
<<
color
::
reset_endl
;
// shutdown actors
send_exit
(
master
,
exit_reason
::
user_shutdown
);
anon_
send_exit
(
master
,
exit_reason
::
user_shutdown
);
// await actors
act
.
sa_handler
=
[](
int
)
{
abort
();
};
set_sighandler
();
...
...
examples/hello_world.cpp
View file @
c91bf3fc
...
...
@@ -5,11 +5,11 @@
using
namespace
std
;
using
namespace
cppa
;
void
mirror
(
)
{
behavior
mirror
(
untyped_actor
*
self
)
{
// wait for messages
become
(
return
(
// invoke this lambda expression if we receive a string
on_arg_match
>>
[](
const
string
&
what
)
->
string
{
on_arg_match
>>
[
=
](
const
string
&
what
)
->
string
{
// prints "Hello World!" via aout (thread-safe cout wrapper)
aout
<<
what
<<
endl
;
// terminates this actor ('become' otherwise loops forever)
...
...
@@ -20,11 +20,11 @@ void mirror() {
);
}
void
hello_world
(
const
actor_pt
r
&
buddy
)
{
void
hello_world
(
untyped_actor
*
self
,
const
acto
r
&
buddy
)
{
// send "Hello World!" to our buddy ...
sync_send
(
buddy
,
"Hello World!"
).
then
(
s
elf
->
s
ync_send
(
buddy
,
"Hello World!"
).
then
(
// ... and wait for a response
on_arg_match
>>
[](
const
string
&
what
)
{
on_arg_match
>>
[
=
](
const
string
&
what
)
{
// prints "!dlroW olleH"
aout
<<
what
<<
endl
;
}
...
...
examples/message_passing/calculator.cpp
View file @
c91bf3fc
...
...
@@ -13,9 +13,9 @@ using std::endl;
using
namespace
cppa
;
// implementation using the blocking API
void
blocking_math_fun
()
{
void
blocking_math_fun
(
blocking_untyped_actor
*
self
)
{
bool
done
=
false
;
do_receive
(
self
->
do_receive
(
// "arg_match" matches the parameter types of given lambda expression
// thus, it's equal to
// - on<atom("plus"), int, int>()
...
...
@@ -34,38 +34,38 @@ void blocking_math_fun() {
).
until
(
gref
(
done
));
}
void
calculator
()
{
void
calculator
(
untyped_actor
*
self
)
{
// execute this behavior until actor terminates
become
(
self
->
become
(
on
(
atom
(
"plus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
{
return
make_cow_tuple
(
atom
(
"result"
),
a
+
b
);
},
on
(
atom
(
"minus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
{
return
make_cow_tuple
(
atom
(
"result"
),
a
-
b
);
},
on
(
atom
(
"quit"
))
>>
[]
{
on
(
atom
(
"quit"
))
>>
[
=
]
{
// terminate actor with normal exit reason
self
->
quit
();
}
);
}
void
tester
(
const
actor_pt
r
&
testee
)
{
void
tester
(
untyped_actor
*
self
,
const
acto
r
&
testee
)
{
self
->
link_to
(
testee
);
// will be invoked if we receive an unexpected response message
self
->
on_sync_failure
([]
{
self
->
on_sync_failure
([
=
]
{
aout
<<
"AUT (actor under test) failed"
<<
endl
;
self
->
quit
(
exit_reason
::
user_shutdown
);
});
// first test: 2 + 1 = 3
sync_send
(
testee
,
atom
(
"plus"
),
2
,
1
).
then
(
s
elf
->
s
ync_send
(
testee
,
atom
(
"plus"
),
2
,
1
).
then
(
on
(
atom
(
"result"
),
3
)
>>
[
=
]
{
// second test: 2 - 1 = 1
sync_send
(
testee
,
atom
(
"minus"
),
2
,
1
).
then
(
s
elf
->
s
ync_send
(
testee
,
atom
(
"minus"
),
2
,
1
).
then
(
on
(
atom
(
"result"
),
1
)
>>
[
=
]
{
// both tests succeeded
aout
<<
"AUT (actor under test) seems to be ok"
<<
endl
;
send
(
testee
,
atom
(
"quit"
));
se
lf
->
se
nd
(
testee
,
atom
(
"quit"
));
}
);
}
...
...
@@ -78,4 +78,3 @@ int main() {
shutdown
();
return
0
;
}
examples/message_passing/dancing_kirby.cpp
View file @
c91bf3fc
...
...
@@ -53,20 +53,20 @@ void draw_kirby(const animation_step& animation) {
}
// uses a message-based loop to iterate over all animation steps
void
dancing_kirby
()
{
void
dancing_kirby
(
untyped_actor
*
self
)
{
// let's get it started
send
(
self
,
atom
(
"Step"
),
size_t
{
0
});
become
(
on
(
atom
(
"Step"
),
array_size
(
animation_steps
))
>>
[]
{
se
lf
->
se
nd
(
self
,
atom
(
"Step"
),
size_t
{
0
});
self
->
become
(
on
(
atom
(
"Step"
),
array_size
(
animation_steps
))
>>
[
=
]
{
// we've printed all animation steps (done)
cout
<<
endl
;
self
->
quit
();
},
on
(
atom
(
"Step"
),
arg_match
)
>>
[](
size_t
step
)
{
on
(
atom
(
"Step"
),
arg_match
)
>>
[
=
](
size_t
step
)
{
// print given step
draw_kirby
(
animation_steps
[
step
]);
// animate next step in 150ms
delayed_send
(
self
,
std
::
chrono
::
milliseconds
(
150
),
atom
(
"Step"
),
step
+
1
);
self
->
delayed_send
(
self
,
std
::
chrono
::
milliseconds
(
150
),
atom
(
"Step"
),
step
+
1
);
}
);
}
...
...
examples/message_passing/dining_philosophers.cpp
View file @
c91bf3fc
...
...
@@ -17,21 +17,21 @@ using namespace std;
using
namespace
cppa
;
// either taken by a philosopher or available
void
chopstick
()
{
become
(
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
const
actor
_ptr
&
philos
)
{
void
chopstick
(
untyped_actor
*
self
)
{
self
->
become
(
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
const
actor
&
philos
)
{
// tell philosopher it took this chopstick
send
(
philos
,
atom
(
"taken"
),
self
);
se
lf
->
se
nd
(
philos
,
atom
(
"taken"
),
self
);
// await 'put' message and reject other 'take' messages
become
(
self
->
become
(
// allows us to return to the previous behavior
keep_behavior
,
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
const
actor
_ptr
&
other
)
{
send
(
other
,
atom
(
"busy"
),
self
);
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
const
actor
&
other
)
{
se
lf
->
se
nd
(
other
,
atom
(
"busy"
),
self
);
},
on
(
atom
(
"put"
),
philos
)
>>
[
=
]
{
// return to previous behaivor, i.e., await next 'take'
unbecome
();
self
->
unbecome
();
}
);
}
...
...
@@ -71,11 +71,11 @@ void chopstick() {
* [ X = right => Y = left ]
*/
struct
philosopher
:
event_bas
ed_actor
{
struct
philosopher
:
untyp
ed_actor
{
std
::
string
name
;
// the name of this philosopher
actor
_ptr
left
;
// left chopstick
actor
_ptr
right
;
// right chopstick
actor
left
;
// left chopstick
actor
right
;
// right chopstick
// note: we have to define all behaviors in the constructor because
// non-static member initialization are not (yet) implemented in GCC
...
...
@@ -85,7 +85,7 @@ struct philosopher : event_based_actor {
behavior
eating
;
// wait for second chopstick
behavior
waiting_for
(
const
actor
_ptr
&
what
)
{
behavior
waiting_for
(
const
actor
&
what
)
{
return
(
on
(
atom
(
"taken"
),
what
)
>>
[
=
]
{
aout
<<
name
...
...
@@ -106,7 +106,7 @@ struct philosopher : event_based_actor {
);
}
philosopher
(
const
std
::
string
&
n
,
const
actor
_ptr
&
l
,
const
actor_pt
r
&
r
)
philosopher
(
const
std
::
string
&
n
,
const
actor
&
l
,
const
acto
r
&
r
)
:
name
(
n
),
left
(
l
),
right
(
r
)
{
// a philosopher that receives {eat} stops thinking and becomes hungry
thinking
=
(
...
...
@@ -124,18 +124,18 @@ struct philosopher : event_based_actor {
on
(
atom
(
"taken"
),
right
)
>>
[
=
]
{
become
(
waiting_for
(
left
));
},
on
<
atom
(
"busy"
),
actor
_ptr
>
()
>>
[
=
]
{
on
<
atom
(
"busy"
),
actor
>
()
>>
[
=
]
{
become
(
denied
);
}
);
// philosopher was not able to obtain the first chopstick
denied
=
(
on
(
atom
(
"taken"
),
arg_match
)
>>
[
=
](
const
actor
_ptr
&
ptr
)
{
on
(
atom
(
"taken"
),
arg_match
)
>>
[
=
](
const
actor
&
ptr
)
{
send
(
ptr
,
atom
(
"put"
),
this
);
send
(
this
,
atom
(
"eat"
));
become
(
thinking
);
},
on
<
atom
(
"busy"
),
actor
_ptr
>
()
>>
[
=
]
{
on
<
atom
(
"busy"
),
actor
>
()
>>
[
=
]
{
send
(
this
,
atom
(
"eat"
));
become
(
thinking
);
}
...
...
@@ -153,17 +153,17 @@ struct philosopher : event_based_actor {
);
}
void
init
()
{
behavior
make_behavior
()
override
{
// start thinking
send
(
this
,
atom
(
"think"
));
// philosophers start to think after receiving {think}
become
(
return
(
on
(
atom
(
"think"
))
>>
[
=
]
{
aout
<<
name
<<
" starts to think
\n
"
;
delayed_send
(
this
,
seconds
(
5
),
atom
(
"eat"
));
become
(
thinking
);
}
);
// start thinking
send
(
this
,
atom
(
"think"
));
}
};
...
...
@@ -171,7 +171,7 @@ struct philosopher : event_based_actor {
int
main
(
int
,
char
**
)
{
// create five chopsticks
aout
<<
"chopstick ids are:"
;
std
::
vector
<
actor
_ptr
>
chopsticks
;
std
::
vector
<
actor
>
chopsticks
;
for
(
size_t
i
=
0
;
i
<
5
;
++
i
)
{
chopsticks
.
push_back
(
spawn
(
chopstick
));
aout
<<
" "
<<
chopsticks
.
back
()
->
id
();
...
...
examples/remote_actors/distributed_calculator.cpp
View file @
c91bf3fc
...
...
@@ -26,15 +26,15 @@ using namespace cppa;
using
namespace
cppa
::
placeholders
;
// our "service"
void
calculator
()
{
become
(
void
calculator
(
untyped_actor
*
self
)
{
self
->
become
(
on
(
atom
(
"plus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
->
any_tuple
{
return
{
atom
(
"result"
),
a
+
b
}
;
return
make_any_tuple
(
atom
(
"result"
),
a
+
b
)
;
},
on
(
atom
(
"minus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
->
any_tuple
{
return
{
atom
(
"result"
),
a
-
b
}
;
return
make_any_tuple
(
atom
(
"result"
),
a
-
b
)
;
},
on
(
atom
(
"quit"
))
>>
[
=
]
()
{
on
(
atom
(
"quit"
))
>>
[
=
]
{
self
->
quit
();
}
);
...
...
@@ -49,12 +49,12 @@ inline string trim(std::string s) {
return
s
;
}
void
client_bhvr
(
const
string
&
host
,
uint16_t
port
,
const
actor_pt
r
&
server
)
{
void
client_bhvr
(
untyped_actor
*
self
,
const
string
&
host
,
uint16_t
port
,
const
acto
r
&
server
)
{
// recover from sync failures by trying to reconnect to server
if
(
!
self
->
has_sync_failure_handler
())
{
self
->
on_sync_failure
([
=
]
{
aout
<<
"*** lost connection to "
<<
host
<<
":"
<<
port
<<
endl
;
client_bhvr
(
host
,
port
,
nullptr
);
client_bhvr
(
self
,
host
,
port
,
nullptr
);
});
}
// connect to server if needed
...
...
@@ -64,17 +64,17 @@ void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) {
auto
new_serv
=
remote_actor
(
host
,
port
);
self
->
monitor
(
new_serv
);
aout
<<
"reconnection succeeded"
<<
endl
;
client_bhvr
(
host
,
port
,
new_serv
);
client_bhvr
(
self
,
host
,
port
,
new_serv
);
return
;
}
catch
(
exception
&
)
{
aout
<<
"connection failed, try again in 3s"
<<
endl
;
delayed_send
(
self
,
chrono
::
seconds
(
3
),
atom
(
"reconnect"
));
self
->
delayed_send
(
self
,
chrono
::
seconds
(
3
),
atom
(
"reconnect"
));
}
}
become
(
self
->
become
(
on_arg_match
.
when
(
_x1
.
in
({
atom
(
"plus"
),
atom
(
"minus"
)})
&&
gval
(
server
)
!=
nullptr
)
>>
[
=
](
atom_value
op
,
int
lhs
,
int
rhs
)
{
sync_send_tuple
(
server
,
self
->
last_dequeued
()).
then
(
s
elf
->
s
ync_send_tuple
(
server
,
self
->
last_dequeued
()).
then
(
on
(
atom
(
"result"
),
arg_match
)
>>
[
=
](
int
result
)
{
aout
<<
lhs
<<
" "
<<
to_string
(
op
)
<<
" "
...
...
@@ -85,14 +85,14 @@ void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) {
},
on
(
atom
(
"DOWN"
),
arg_match
)
>>
[
=
](
uint32_t
)
{
aout
<<
"*** server down, try to reconnect ..."
<<
endl
;
client_bhvr
(
host
,
port
,
nullptr
);
client_bhvr
(
self
,
host
,
port
,
nullptr
);
},
on
(
atom
(
"rebind"
),
arg_match
)
>>
[
=
](
const
string
&
host
,
uint16_t
port
)
{
aout
<<
"*** rebind to new server: "
<<
host
<<
":"
<<
port
<<
endl
;
client_bhvr
(
host
,
port
,
nullptr
);
client_bhvr
(
self
,
host
,
port
,
nullptr
);
},
on
(
atom
(
"reconnect"
))
>>
[
=
]
{
client_bhvr
(
host
,
port
,
nullptr
);
client_bhvr
(
self
,
host
,
port
,
nullptr
);
}
);
}
...
...
@@ -112,7 +112,7 @@ void client_repl(const string& host, uint16_t port) {
line
=
trim
(
std
::
move
(
line
));
// ignore leading and trailing whitespaces
if
(
line
==
"quit"
)
{
// force client to quit
send_exit
(
client
,
exit_reason
::
user_shutdown
);
anon_
send_exit
(
client
,
exit_reason
::
user_shutdown
);
return
;
}
// the STL way of line.starts_with("connect")
...
...
@@ -123,7 +123,7 @@ void client_repl(const string& host, uint16_t port) {
auto
lport
=
std
::
stoul
(
sport
);
if
(
lport
<
std
::
numeric_limits
<
uint16_t
>::
max
())
{
auto
port
=
static_cast
<
uint16_t
>
(
lport
);
send
(
client
,
atom
(
"rebind"
),
move
(
host
),
port
);
anon_
send
(
client
,
atom
(
"rebind"
),
move
(
host
),
port
);
}
else
{
aout
<<
lport
<<
" is not a valid port"
<<
endl
;
...
...
@@ -159,7 +159,7 @@ void client_repl(const string& host, uint16_t port) {
auto
rhs
=
toint
(
rsub
);
if
(
lhs
&&
rhs
)
{
auto
op
=
(
*
pos
==
'+'
)
?
atom
(
"plus"
)
:
atom
(
"minus"
);
send
(
client
,
op
,
*
lhs
,
*
rhs
);
anon_
send
(
client
,
op
,
*
lhs
,
*
rhs
);
}
}
else
if
(
!
success
)
{
...
...
examples/remote_actors/group_chat.cpp
View file @
c91bf3fc
...
...
@@ -42,22 +42,22 @@ any_tuple split_line(const line& l) {
return
any_tuple
::
view
(
std
::
move
(
result
));
}
void
client
(
const
string
&
name
)
{
become
(
void
client
(
untyped_actor
*
self
,
const
string
&
name
)
{
self
->
become
(
on
(
atom
(
"broadcast"
),
arg_match
)
>>
[
=
](
const
string
&
message
)
{
for
(
auto
&
dest
:
self
->
joined_groups
())
{
send
(
dest
,
name
+
": "
+
message
);
se
lf
->
se
nd
(
dest
,
name
+
": "
+
message
);
}
},
on
(
atom
(
"join"
),
arg_match
)
>>
[
=
](
const
group_ptr
&
what
)
{
for
(
auto
g
:
self
->
joined_groups
())
{
cout
<<
"*** leave "
<<
to_string
(
g
)
<<
endl
;
se
nd
(
g
,
name
+
" has left the chatroom"
);
se
lf
->
send
(
self
,
g
,
name
+
" has left the chatroom"
);
self
->
leave
(
g
);
}
cout
<<
"*** join "
<<
to_string
(
what
)
<<
endl
;
self
->
join
(
what
);
se
nd
(
what
,
name
+
" has entered the chatroom"
);
se
lf
->
send
(
self
,
what
,
name
+
" has entered the chatroom"
);
},
on
<
string
>
()
>>
[
=
](
const
string
&
txt
)
{
// don't print own messages
...
...
@@ -104,7 +104,7 @@ int main(int argc, char** argv) {
try
{
auto
g
=
group
::
get
(
group_id
.
substr
(
0
,
p
),
group_id
.
substr
(
p
+
1
));
send
(
client_actor
,
atom
(
"join"
),
g
);
anon_
send
(
client_actor
,
atom
(
"join"
),
g
);
}
catch
(
exception
&
e
)
{
ostringstream
err
;
...
...
@@ -120,7 +120,7 @@ int main(int argc, char** argv) {
match_each
(
lines
,
eof
,
split_line
)
(
on
(
"/join"
,
arg_match
)
>>
[
&
](
const
string
&
mod
,
const
string
&
id
)
{
try
{
send
(
client_actor
,
atom
(
"join"
),
group
::
get
(
mod
,
id
));
anon_
send
(
client_actor
,
atom
(
"join"
),
group
::
get
(
mod
,
id
));
}
catch
(
exception
&
e
)
{
cerr
<<
"*** exception: "
<<
to_verbose_string
(
e
)
<<
endl
;
...
...
@@ -137,12 +137,12 @@ int main(int argc, char** argv) {
},
others
()
>>
[
&
]
{
if
(
!
s_last_line
.
empty
())
{
send
(
client_actor
,
atom
(
"broadcast"
),
s_last_line
);
anon_
send
(
client_actor
,
atom
(
"broadcast"
),
s_last_line
);
}
}
);
// force actor to quit
send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
anon_
send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
shutdown
();
return
0
;
...
...
examples/type_system/announce_1.cpp
View file @
c91bf3fc
...
...
@@ -42,12 +42,12 @@ bool operator==( const foo2& lhs, const foo2& rhs ) {
}
// receives `remaining` messages
void
testee
(
size_t
remaining
)
{
void
testee
(
untyped_actor
*
self
,
size_t
remaining
)
{
auto
set_next_behavior
=
[
=
]
{
if
(
remaining
>
1
)
testee
(
remaining
-
1
);
if
(
remaining
>
1
)
testee
(
self
,
remaining
-
1
);
else
self
->
quit
();
};
become
(
self
->
become
(
// note: we sent a foo_pair2, but match on foo_pair
// that's safe because both are aliases for std::pair<int, int>
on
<
foo_pair
>
()
>>
[
=
](
const
foo_pair
&
val
)
{
...
...
@@ -113,11 +113,13 @@ int main(int, char**) {
// spawn a testee that receives two messages
auto
t
=
spawn
(
testee
,
2
);
// send t a foo
send
(
t
,
foo
{
std
::
vector
<
int
>
{
1
,
2
,
3
,
4
},
5
});
// send t a foo_pair2
send
(
t
,
foo_pair2
{
3
,
4
});
{
scoped_actor
self
;
// send t a foo
self
->
send
(
t
,
foo
{
std
::
vector
<
int
>
{
1
,
2
,
3
,
4
},
5
});
// send t a foo_pair2
self
->
send
(
t
,
foo_pair2
{
3
,
4
});
}
await_all_actors_done
();
shutdown
();
return
0
;
...
...
examples/type_system/announce_2.cpp
View file @
c91bf3fc
...
...
@@ -39,9 +39,9 @@ bool operator==(const foo& lhs, const foo& rhs) {
&&
lhs
.
b
()
==
rhs
.
b
();
}
void
testee
()
{
become
(
on
<
foo
>
()
>>
[](
const
foo
&
val
)
{
void
testee
(
untyped_actor
*
self
)
{
self
->
become
(
on
<
foo
>
()
>>
[
=
](
const
foo
&
val
)
{
aout
<<
"foo("
<<
val
.
a
()
<<
", "
<<
val
.
b
()
<<
")"
...
...
@@ -56,8 +56,11 @@ int main(int, char**) {
// we pass those to the announce function as { getter, setter } pairs.
announce
<
foo
>
(
make_pair
(
&
foo
::
a
,
&
foo
::
set_a
),
make_pair
(
&
foo
::
b
,
&
foo
::
set_b
));
auto
t
=
spawn
(
testee
);
send
(
t
,
foo
{
1
,
2
});
{
scoped_actor
self
;
auto
t
=
spawn
(
testee
);
self
->
send
(
t
,
foo
{
1
,
2
});
}
await_all_actors_done
();
shutdown
();
return
0
;
...
...
examples/type_system/announce_3.cpp
View file @
c91bf3fc
...
...
@@ -46,9 +46,9 @@ typedef int (foo::*foo_getter)() const;
// a member function pointer to set an attribute of foo
typedef
void
(
foo
::*
foo_setter
)(
int
);
void
testee
()
{
become
(
on
<
foo
>
()
>>
[](
const
foo
&
val
)
{
void
testee
(
untyped_actor
*
self
)
{
self
->
become
(
on
<
foo
>
()
>>
[
=
](
const
foo
&
val
)
{
aout
<<
"foo("
<<
val
.
a
()
<<
", "
<<
val
.
b
()
<<
")"
...
...
@@ -78,7 +78,10 @@ int main(int, char**) {
static_cast
<
foo_setter
>
(
&
foo
::
b
)));
// spawn a new testee and send it a foo
send
(
spawn
(
testee
),
foo
{
1
,
2
});
{
scoped_actor
self
;
self
->
send
(
spawn
(
testee
),
foo
{
1
,
2
});
}
await_all_actors_done
();
shutdown
();
return
0
;
...
...
examples/type_system/announce_4.cpp
View file @
c91bf3fc
...
...
@@ -79,12 +79,12 @@ bool operator==(const baz& lhs, const baz& rhs) {
}
// receives `remaining` messages
void
testee
(
size_t
remaining
)
{
void
testee
(
untyped_actor
*
self
,
size_t
remaining
)
{
auto
set_next_behavior
=
[
=
]
{
if
(
remaining
>
1
)
testee
(
remaining
-
1
);
if
(
remaining
>
1
)
testee
(
self
,
remaining
-
1
);
else
self
->
quit
();
};
become
(
self
->
become
(
on
<
bar
>
()
>>
[
=
](
const
bar
&
val
)
{
aout
<<
"bar(foo("
<<
val
.
f
.
a
()
<<
", "
...
...
@@ -127,8 +127,11 @@ int main(int, char**) {
// spawn a testee that receives two messages
auto
t
=
spawn
(
testee
,
2
);
send
(
t
,
bar
{
foo
{
1
,
2
},
3
});
send
(
t
,
baz
{
foo
{
1
,
2
},
bar
{
foo
{
3
,
4
},
5
}});
{
scoped_actor
self
;
self
->
send
(
t
,
bar
{
foo
{
1
,
2
},
3
});
self
->
send
(
t
,
baz
{
foo
{
1
,
2
},
bar
{
foo
{
3
,
4
},
5
}});
}
await_all_actors_done
();
shutdown
();
return
0
;
...
...
examples/type_system/announce_5.cpp
View file @
c91bf3fc
...
...
@@ -131,12 +131,12 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> {
typedef
std
::
vector
<
tree
>
tree_vector
;
// receives `remaining` messages
void
testee
(
size_t
remaining
)
{
void
testee
(
untyped_actor
*
self
,
size_t
remaining
)
{
auto
set_next_behavior
=
[
=
]
{
if
(
remaining
>
1
)
testee
(
remaining
-
1
);
if
(
remaining
>
1
)
testee
(
self
,
remaining
-
1
);
else
self
->
quit
();
};
become
(
self
->
become
(
on_arg_match
>>
[
=
](
const
tree
&
tmsg
)
{
// prints the tree in its serialized format:
// @<> ( { tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) } )
...
...
@@ -188,18 +188,22 @@ int main() {
11 12 13 21 22
*/
// spawn a testee that receives two messages
auto
t
=
spawn
(
testee
,
2
)
;
{
// lifetime scope of self
scoped_actor
self
;
// send a tree
send
(
t
,
t0
);
// spawn a testee that receives two messages
auto
t
=
spawn
(
testee
,
2
);
// send a vector of trees
announce
<
tree_vector
>
();
tree_vector
tvec
;
tvec
.
push_back
(
t0
);
tvec
.
push_back
(
t0
);
send
(
t
,
tvec
);
// send a tree
self
->
send
(
t
,
t0
);
// send a vector of trees
announce
<
tree_vector
>
();
tree_vector
tvec
;
tvec
.
push_back
(
t0
);
tvec
.
push_back
(
t0
);
self
->
send
(
t
,
tvec
);
}
await_all_actors_done
();
shutdown
();
...
...
src/actor.cpp
View file @
c91bf3fc
...
...
@@ -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/>. *
\******************************************************************************/
\******************************************************************************/
#include <utility>
...
...
@@ -39,6 +39,8 @@ namespace cppa {
actor
::
actor
(
abstract_actor
*
ptr
)
:
m_ops
(
ptr
)
{
}
actor
::
actor
(
const
invalid_actor_t
&
)
:
m_ops
(
nullptr
)
{
}
void
actor
::
enqueue
(
const
message_header
&
hdr
,
any_tuple
msg
)
const
{
if
(
m_ops
.
m_ptr
)
m_ops
.
m_ptr
->
enqueue
(
hdr
,
std
::
move
(
msg
));
}
...
...
src/actor_addr.cpp
View file @
c91bf3fc
...
...
@@ -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/>. *
\******************************************************************************/
\******************************************************************************/
#include "cppa/actor.hpp"
...
...
src/actor_namespace.cpp
View file @
c91bf3fc
...
...
@@ -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/>. *
\******************************************************************************/
\******************************************************************************/
#include <utility>
...
...
src/blocking_untyped_actor.cpp
0 → 100644
View file @
c91bf3fc
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/singletons.hpp"
#include "cppa/blocking_untyped_actor.hpp"
#include "cppa/detail/actor_registry.hpp"
namespace
cppa
{
void
blocking_untyped_actor
::
await_all_other_actors_done
()
{
get_actor_registry
()
->
await_running_count_equal
(
1
);
}
}
// namespace cppa
src/broker.cpp
View file @
c91bf3fc
...
...
@@ -49,7 +49,8 @@ using std::cout;
using
std
::
endl
;
using
std
::
move
;
namespace
cppa
{
namespace
io
{
namespace
cppa
{
namespace
io
{
namespace
{
...
...
@@ -57,31 +58,20 @@ constexpr size_t default_max_buffer_size = 65535;
}
// namespace <anonymous>
class
default_broker
:
public
broker
{
public:
typedef
std
::
function
<
void
(
broker
*
)
>
function_type
;
template
<
typename
...
Ts
>
default_broker
(
function_type
&&
fun
,
Ts
&&
...
args
)
:
broker
{
std
::
forward
<
Ts
>
(
args
)...},
m_fun
{
move
(
fun
)}
{
}
void
init
()
override
{
enqueue
({
invalid_actor_addr
,
channel
{
this
}},
make_any_tuple
(
atom
(
"INITMSG"
)));
become
(
on
(
atom
(
"INITMSG"
))
>>
[
=
]
{
unbecome
();
m_fun
(
this
);
}
);
}
private:
function_type
m_fun
;
};
default_broker
::
default_broker
(
input_stream_ptr
in
,
output_stream_ptr
out
,
function_type
f
)
:
broker
(
std
::
move
(
in
),
std
::
move
(
out
)),
m_fun
(
std
::
move
(
f
))
{
}
behavior
default_broker
::
make_behavior
()
{
enqueue
({
invalid_actor_addr
,
channel
{
this
}},
make_any_tuple
(
atom
(
"INITMSG"
)));
return
(
on
(
atom
(
"INITMSG"
))
>>
[
=
]
{
unbecome
();
m_fun
(
this
);
}
);
}
class
broker
::
continuation
{
...
...
@@ -299,24 +289,23 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) {
try
{
using
detail
::
receive_policy
;
auto
bhvr
=
m_bhvr_stack
.
back
();
switch
(
m_recv_policy
.
handle_message
(
this
,
&
m_dummy_node
,
bhvr
,
m_bhvr_stack
.
back_id
(),
receive_policy
::
sequential
{}))
{
case
receive_policy
:
:
hm_msg_handled
:
{
switch
(
m_invoke
.
handle_message
(
this
,
&
m_dummy_node
,
bhvr
,
m_bhvr_stack
.
back_id
()))
{
case
policy
:
:
hm_msg_handled
:
{
if
(
not
m_bhvr_stack
.
empty
()
&&
bhvr
.
as_behavior_impl
()
==
m_bhvr_stack
.
back
().
as_behavior_impl
())
{
m_
recv_policy
.
invoke_from_cache
(
this
,
bhvr
,
m_bhvr_stack
.
back_id
());
m_
invoke
.
invoke_from_cache
(
this
,
bhvr
,
m_bhvr_stack
.
back_id
());
}
break
;
}
case
receive_
policy
:
:
hm_drop_msg
:
case
policy
:
:
hm_drop_msg
:
break
;
case
receive_
policy
:
:
hm_skip_msg
:
case
receive_
policy
:
:
hm_cache_msg
:
{
case
policy
:
:
hm_skip_msg
:
case
policy
:
:
hm_cache_msg
:
{
auto
e
=
mailbox_element
::
create
(
hdr
,
move
(
m_dummy_node
.
msg
));
m_
recv_policy
.
add_to_cache
(
e
);
m_
invoke
.
add_to_cache
(
e
);
break
;
}
default:
CPPA_CRITICAL
(
"illegal result of handle_message"
);
...
...
@@ -398,7 +387,7 @@ void broker::write(const connection_handle& hdl, util::buffer&& buf) {
}
local_actor_ptr
init_and_launch
(
broker_ptr
ptr
)
{
ptr
->
init
();
//
ptr->init();
// continue reader only if not inherited from default_broker_impl
CPPA_LOGF_WARNING_IF
(
!
ptr
->
has_behavior
(),
"broker w/o behavior spawned"
);
auto
mm
=
get_middleman
();
...
...
@@ -421,6 +410,7 @@ local_actor_ptr init_and_launch(broker_ptr ptr) {
return
ptr
;
}
/*
broker_ptr broker::from_impl(std::function<void (broker*)> fun,
input_stream_ptr in,
output_stream_ptr out) {
...
...
@@ -430,6 +420,7 @@ broker_ptr broker::from_impl(std::function<void (broker*)> fun,
broker_ptr broker::from(std::function<void (broker*)> fun, acceptor_uptr in) {
return make_counted<default_broker>(move(fun), move(in));
}
*/
void
broker
::
erase_io
(
int
id
)
{
...
...
@@ -454,16 +445,19 @@ accept_handle broker::add_doorman(acceptor_uptr ptr) {
return
id
;
}
actor
_addr
broker
::
fork_impl
(
std
::
function
<
void
(
broker
*
)
>
fun
,
connection_handle
hdl
)
{
actor
broker
::
fork_impl
(
std
::
function
<
void
(
broker
*
)
>
fun
,
connection_handle
hdl
)
{
auto
i
=
m_io
.
find
(
hdl
);
if
(
i
==
m_io
.
end
())
throw
std
::
invalid_argument
(
"invalid handle"
);
/*FIXME
scribe* sptr = i->second.get(); // non-owning pointer
auto result = make_counted<default_broker>(move(fun), move(i->second));
init_and_launch(result);
sptr->set_broker(result); // set new broker
m_io.erase(i);
return {result};
*/
return
nullptr
;
}
void
broker
::
receive_policy
(
const
connection_handle
&
hdl
,
...
...
@@ -473,4 +467,5 @@ void broker::receive_policy(const connection_handle& hdl,
if
(
i
!=
m_io
.
end
())
i
->
second
->
receive_policy
(
policy
,
buffer_size
);
}
}
}
// namespace cppa::network
}
// namespace io
}
// namespace cppa
src/common_actor_ops.cpp
View file @
c91bf3fc
...
...
@@ -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/>. *
\******************************************************************************/
\******************************************************************************/
#include "cppa/actor_addr.hpp"
...
...
src/context_switching_resume.cpp
View file @
c91bf3fc
...
...
@@ -36,12 +36,13 @@
#include "cppa/cppa.hpp"
#include "cppa/self.hpp"
namespace
cppa
{
namespace
policy
{
namespace
cppa
{
namespace
policy
{
void
context_switching_resume
::
trampoline
(
void
*
this_ptr
)
{
auto
_this
=
reinterpret_cast
<
context_switching_resume
*>
(
this_ptr
);
auto
_this
=
reinterpret_cast
<
blocking_untyped_actor
*>
(
this_ptr
);
bool
cleanup_called
=
false
;
try
{
_this
->
run
();
}
try
{
_this
->
act
();
}
catch
(
actor_exited
&
)
{
// cleanup already called by scheduled_actor::quit
cleanup_called
=
true
;
...
...
@@ -56,10 +57,21 @@ void context_switching_resume::trampoline(void* this_ptr) {
detail
::
yield
(
detail
::
yield_state
::
done
);
}
}
}
// namespace cppa::policy
}
// namespace policy
}
// namespace cppa
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace
cppa
{
namespace
policy
{
void
context_switching_resume
::
trampoline
(
void
*
)
{
throw
std
::
logic_error
(
"context_switching_resume::trampoline called"
);
}
}
// namespace policy
}
// namespace cppa
namespace
cppa
{
int
keep_compiler_happy_function
()
{
return
42
;
}
}
#endif // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
src/event_based_resume.cpp
deleted
100644 → 0
View file @
3eee072f
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include <iostream>
#include "cppa/to_string.hpp"
#include "cppa/cppa.hpp"
#include "cppa/logging.hpp"
#include "cppa/event_based_actor.hpp"
using
namespace
std
;
namespace
cppa
{
class
default_scheduled_actor
:
public
event_based_actor
{
typedef
event_based_actor
super
;
public:
typedef
std
::
function
<
behavior
(
event_based_actor
*
)
>
fun_type
;
default_scheduled_actor
(
fun_type
&&
fun
)
:
super
(
actor_state
::
ready
),
m_fun
(
std
::
move
(
fun
))
{
}
behavior
make_behavior
()
override
{
return
m_fun
(
this
);
}
scheduled_actor_type
impl_type
()
{
return
default_event_based_impl
;
}
private:
fun_type
m_fun
;
};
intrusive_ptr
<
event_based_actor
>
event_based_actor
::
from
(
std
::
function
<
behavior
()
>
fun
)
{
return
make_counted
<
default_scheduled_actor
>
([
=
](
event_based_actor
*
)
->
behavior
{
return
fun
();
});
}
intrusive_ptr
<
event_based_actor
>
event_based_actor
::
from
(
std
::
function
<
behavior
(
event_based_actor
*
)
>
fun
)
{
return
make_counted
<
default_scheduled_actor
>
(
std
::
move
(
fun
));
}
intrusive_ptr
<
event_based_actor
>
event_based_actor
::
from
(
std
::
function
<
void
(
event_based_actor
*
)
>
fun
)
{
auto
result
=
make_counted
<
default_scheduled_actor
>
([
=
](
event_based_actor
*
self
)
->
behavior
{
return
(
on
(
atom
(
"INIT"
))
>>
[
=
]
{
fun
(
self
);
}
);
});
result
->
enqueue
({
result
->
address
(),
result
},
make_any_tuple
(
atom
(
"INIT"
)));
return
result
;
}
intrusive_ptr
<
event_based_actor
>
event_based_actor
::
from
(
std
::
function
<
void
()
>
fun
)
{
return
from
([
=
](
event_based_actor
*
)
{
fun
();
});
}
event_based_actor
::
event_based_actor
(
actor_state
st
)
:
super
(
st
,
true
)
{
}
resume_result
event_based_resume
::
resume
(
untyped_actor
*
self
,
util
::
fiber
*
)
{
CPPA_LOG_TRACE
(
"id = "
<<
self
->
id
()
<<
", state = "
<<
static_cast
<
int
>
(
state
()));
CPPA_REQUIRE
(
self
->
state
()
==
actor_state
::
ready
||
self
->
state
()
==
actor_state
::
pending
);
auto
done_cb
=
[
&
]()
->
bool
{
CPPA_LOG_TRACE
(
""
);
if
(
self
->
exit_reason
()
==
self
->
exit_reason
::
not_exited
)
{
if
(
self
->
planned_exit_reason
()
==
self
->
exit_reason
::
not_exited
)
{
self
->
planned_exit_reason
(
exit_reason
::
normal
);
}
self
->
on_exit
();
if
(
!
m_bhvr_stack
.
empty
())
{
planned_exit_reason
(
exit_reason
::
not_exited
);
return
false
;
// on_exit did set a new behavior
}
cleanup
(
planned_exit_reason
());
}
set_state
(
actor_state
::
done
);
m_bhvr_stack
.
clear
();
m_bhvr_stack
.
cleanup
();
on_exit
();
CPPA_REQUIRE
(
next_job
==
nullptr
);
return
true
;
};
CPPA_REQUIRE
(
next_job
==
nullptr
);
try
{
//auto e = m_mailbox.try_pop();
for
(
auto
e
=
m_mailbox
.
try_pop
();
;
e
=
m_mailbox
.
try_pop
())
{
//e = m_mailbox.try_pop();
if
(
e
==
nullptr
)
{
CPPA_REQUIRE
(
next_job
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"no more element in mailbox; going to block"
);
set_state
(
actor_state
::
about_to_block
);
std
::
atomic_thread_fence
(
std
::
memory_order_seq_cst
);
if
(
this
->
m_mailbox
.
can_fetch_more
()
==
false
)
{
switch
(
compare_exchange_state
(
actor_state
::
about_to_block
,
actor_state
::
blocked
))
{
case
actor_state
:
:
ready
:
// interrupted by arriving message
// restore members
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"interrupted by arriving message"
);
break
;
case
actor_state
:
:
blocked
:
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"set state successfully to blocked"
);
// done setting actor to blocked
return
resume_result
::
actor_blocked
;
default:
CPPA_LOGMF
(
CPPA_ERROR
,
self
,
"invalid state"
);
CPPA_CRITICAL
(
"invalid state"
);
};
}
else
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"switched back to ready: "
"mailbox can fetch more"
);
set_state
(
actor_state
::
ready
);
CPPA_REQUIRE
(
m_chained_actor
==
nullptr
);
}
}
else
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"try to invoke message: "
<<
to_string
(
e
->
msg
));
if
(
m_bhvr_stack
.
invoke
(
m_recv_policy
,
this
,
e
))
{
CPPA_LOG_DEBUG_IF
(
m_chained_actor
,
"set actor with ID "
<<
m_chained_actor
->
id
()
<<
" as successor"
);
if
(
m_bhvr_stack
.
empty
()
&&
done_cb
())
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"behavior stack empty"
);
return
resume_result
::
actor_done
;
}
m_bhvr_stack
.
cleanup
();
}
}
}
}
catch
(
actor_exited
&
what
)
{
CPPA_LOG_INFO
(
"actor died because of exception: actor_exited, "
"reason = "
<<
what
.
reason
());
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
what
.
reason
());
}
}
catch
(
std
::
exception
&
e
)
{
CPPA_LOG_WARNING
(
"actor died because of exception: "
<<
detail
::
demangle
(
typeid
(
e
))
<<
", what() = "
<<
e
.
what
());
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
exit_reason
::
unhandled_exception
);
}
}
catch
(...)
{
CPPA_LOG_WARNING
(
"actor died because of an unknown exception"
);
if
(
exit_reason
()
==
exit_reason
::
not_exited
)
{
quit
(
exit_reason
::
unhandled_exception
);
}
}
done_cb
();
return
resume_result
::
actor_done
;
}
scheduled_actor_type
event_based_actor
::
impl_type
()
{
return
event_based_impl
;
}
}
// namespace cppa
src/
thread_mapp
ed_actor.cpp
→
src/
functor_bas
ed_actor.cpp
View file @
c91bf3fc
...
...
@@ -28,29 +28,21 @@
\******************************************************************************/
#include <chrono>
#include <memory>
#include <iostream>
#include <algorithm>
#include "cppa/to_string.hpp"
#include "cppa/exception.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/detail/matches.hpp"
#include "cppa/detail/functor_based_actor.hpp"
namespace
cppa
{
namespace
detail
{
thread_mapped_actor
::
thread_mapped_actor
()
:
m_initialized
(
true
)
{
}
thread_mapped_actor
::
thread_mapped_actor
(
std
::
function
<
void
()
>
fun
)
:
m_initialized
(
false
)
{
set_behavior
(
std
::
move
(
fun
))
;
void
functor_based_actor
::
create
(
untyped_actor
*
,
void_fun
fun
)
{
m_make_behavior
=
[
=
](
untyped_actor
*
self
)
->
behavior
{
fun
(
self
);
return
behavior
{};
}
;
}
b
ool
thread_mapped_actor
::
initialized
()
const
{
return
m_
initialized
;
b
ehavior
functor_based_actor
::
make_behavior
()
{
return
m_
make_behavior
(
this
)
;
}
}
// namespace cppa::detail
}
// namespace detail
}
// namespace cppa
src/
scheduled_actor_dummy
.cpp
→
src/
functor_based_blocking_actor
.cpp
View file @
c91bf3fc
...
...
@@ -28,25 +28,18 @@
\******************************************************************************/
#include "cppa/detail/
scheduled_actor_dummy
.hpp"
#include "cppa/detail/
functor_based_blocking_actor
.hpp"
namespace
cppa
{
namespace
detail
{
namespace
cppa
{
namespace
detail
{
scheduled_actor_dummy
::
scheduled_actor_dummy
()
:
scheduled_actor
(
actor_state
::
blocked
,
false
)
{
}
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
)
{
}
bool
scheduled_actor_dummy
::
has_behavior
()
{
return
false
;
}
resume_result
scheduled_actor_dummy
::
resume
(
util
::
fiber
*
)
{
return
resume_result
::
actor_blocked
;
void
functor_based_blocking_actor
::
create
(
blocking_untyped_actor
*
,
act_fun
fun
)
{
m_act
=
fun
;
}
scheduled_actor_type
scheduled_actor_dummy
::
impl_type
()
{
return
event_based_impl
;
void
functor_based_blocking_actor
::
act
()
{
m_act
(
this
)
;
}
}
}
// namespace cppa::detail
}
// namespace detail
}
// namespace cppa
src/group.cpp
View file @
c91bf3fc
...
...
@@ -87,7 +87,7 @@ const std::string& group::module_name() const {
return
get_module
()
->
name
();
}
struct
group_nameserver
:
event_bas
ed_actor
{
struct
group_nameserver
:
untyp
ed_actor
{
behavior
make_behavior
()
override
{
return
(
on
(
atom
(
"GET_GROUP"
),
arg_match
)
>>
[](
const
std
::
string
&
name
)
{
...
...
src/group_manager.cpp
View file @
c91bf3fc
...
...
@@ -42,7 +42,6 @@
#include "cppa/deserializer.hpp"
#include "cppa/untyped_actor.hpp"
#include "cppa/message_header.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/io/middleman.hpp"
...
...
@@ -133,13 +132,13 @@ class local_group : public group {
typedef
intrusive_ptr
<
local_group
>
local_group_ptr
;
class
local_broker
:
public
event_bas
ed_actor
{
class
local_broker
:
public
untyp
ed_actor
{
public:
local_broker
(
local_group_ptr
g
)
:
m_group
(
move
(
g
))
{
}
behavior
make_behavior
()
{
behavior
make_behavior
()
override
{
return
(
on
(
atom
(
"JOIN"
),
arg_match
)
>>
[
=
](
const
actor_addr
&
other
)
{
CPPA_LOGC_TRACE
(
"cppa::local_broker"
,
"init$JOIN"
,
...
...
@@ -256,7 +255,7 @@ class local_group_proxy : public local_group {
typedef
intrusive_ptr
<
local_group_proxy
>
local_group_proxy_ptr
;
class
proxy_broker
:
public
event_bas
ed_actor
{
class
proxy_broker
:
public
untyp
ed_actor
{
public:
...
...
@@ -496,7 +495,7 @@ class remote_group_module : public group::module {
}
}
}
self
->
timed_sync_send
(
chrono
::
seconds
(
10
),
nameserver
,
atom
(
"GET_GROUP"
),
name
).
then
(
self
->
timed_sync_send
(
nameserver
,
chrono
::
seconds
(
10
)
,
atom
(
"GET_GROUP"
),
name
).
then
(
on
(
atom
(
"GROUP"
),
arg_match
)
>>
[
&
](
const
group_ptr
&
g
)
{
auto
gg
=
dynamic_cast
<
local_group
*>
(
g
.
get
());
if
(
gg
)
{
...
...
src/local_actor.cpp
View file @
c91bf3fc
...
...
@@ -77,38 +77,12 @@ constexpr const char* s_default_debug_name = "actor";
}
// namespace <anonymous>
local_actor
::
local_actor
(
bool
sflag
)
local_actor
::
local_actor
()
:
m_trap_exit
(
false
)
,
m_is_scheduled
(
sflag
),
m_dummy_node
(),
m_current_node
(
&
m_dummy_node
)
,
m_planned_exit_reason
(
exit_reason
::
not_exited
)
{
# ifdef CPPA_DEBUG_MODE
new
(
&
m_debug_name
)
std
::
string
(
std
::
to_string
(
m_id
)
+
"@local"
);
# endif // CPPA_DEBUG_MODE
}
local_actor
::~
local_actor
()
{
using
std
::
string
;
# ifdef CPPA_DEBUG_MODE
m_debug_name
.
~
string
();
# endif // CPPA_DEBUG_MODE
}
const
char
*
local_actor
::
debug_name
()
const
{
# ifdef CPPA_DEBUG_MODE
return
m_debug_name
.
c_str
();
# else // CPPA_DEBUG_MODE
return
s_default_debug_name
;
# endif // CPPA_DEBUG_MODE
}
,
m_dummy_node
(),
m_current_node
(
&
m_dummy_node
)
,
m_planned_exit_reason
(
exit_reason
::
not_exited
)
{
}
void
local_actor
::
debug_name
(
std
::
string
str
)
{
# ifdef CPPA_DEBUG_MODE
m_debug_name
=
std
::
move
(
str
);
# else // CPPA_DEBUG_MODE
CPPA_LOG_WARNING
(
"unable to set debug name to "
<<
str
<<
" (compiled without debug mode enabled)"
);
# endif // CPPA_DEBUG_MODE
}
local_actor
::~
local_actor
()
{
}
void
local_actor
::
monitor
(
const
actor_addr
&
whom
)
{
if
(
!
whom
)
return
;
...
...
@@ -125,8 +99,6 @@ void local_actor::demonitor(const actor_addr& whom) {
void
local_actor
::
on_exit
()
{
}
void
local_actor
::
init
()
{
}
void
local_actor
::
join
(
const
group_ptr
&
what
)
{
if
(
what
&&
m_subscriptions
.
count
(
what
)
==
0
)
{
m_subscriptions
.
insert
(
std
::
make_pair
(
what
,
what
->
subscribe
(
this
)));
...
...
@@ -180,6 +152,10 @@ void local_actor::send_tuple(const channel& dest, any_tuple what) {
//TODO:
}
void
local_actor
::
send_exit
(
const
actor_addr
&
whom
,
std
::
uint32_t
reason
)
{
}
void
local_actor
::
remove_handler
(
message_id
)
{
}
...
...
@@ -194,6 +170,14 @@ message_future local_actor::timed_sync_send_tuple(const util::duration& rtime,
}
void
local_actor
::
send_tuple
(
message_priority
prio
,
const
channel
&
dest
,
any_tuple
what
)
{
}
message_future
local_actor
::
sync_send_tuple
(
const
actor
&
dest
,
any_tuple
what
)
{
}
response_handle
local_actor
::
make_response_handle
()
{
return
{};
}
...
...
src/logging.cpp
View file @
c91bf3fc
...
...
@@ -103,7 +103,7 @@ class logging_impl : public logging {
const
char
*
function_name
,
const
char
*
c_full_file_name
,
int
line_num
,
actor_addr
from
,
actor_addr
,
const
std
::
string
&
msg
)
{
string
class_name
=
c_class_name
;
replace_all
(
class_name
,
"::"
,
"."
);
...
...
src/middleman.cpp
View file @
c91bf3fc
...
...
@@ -46,7 +46,6 @@
#include "cppa/actor_proxy.hpp"
#include "cppa/binary_serializer.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/binary_deserializer.hpp"
#include "cppa/util/buffer.hpp"
...
...
@@ -347,9 +346,6 @@ class middleman_overseer : public continuable {
middleman
::~
middleman
()
{
}
void
middleman_loop
(
middleman_impl
*
impl
)
{
# ifdef CPPA_LOG_LEVEL
auto
mself
=
make_counted
<
thread_mapped_actor
>
();
# endif
middleman_event_handler
*
handler
=
impl
->
m_handler
.
get
();
CPPA_LOGF_TRACE
(
"run middleman loop"
);
CPPA_LOGF_INFO
(
"middleman runs at "
...
...
src/resumable.cpp
0 → 100644
View file @
c91bf3fc
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/resumable.hpp"
namespace
cppa
{
resumable
::~
resumable
()
{
}
}
// namespace cppa
src/scheduled_actor.cpp
deleted
100644 → 0
View file @
3eee072f
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/on.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/sync_request_bouncer.hpp"
namespace
cppa
{
scheduled_actor
::
scheduled_actor
(
actor_state
init_state
,
bool
chained_send
)
:
super
(
chained_send
),
next
(
nullptr
),
m_state
(
init_state
)
,
m_scheduler
(
nullptr
),
m_hidden
(
false
)
{
}
void
scheduled_actor
::
attach_to_scheduler
(
scheduler
*
sched
,
bool
hidden
)
{
CPPA_REQUIRE
(
sched
!=
nullptr
);
m_scheduler
=
sched
;
m_hidden
=
hidden
;
// initialize this actor
try
{
init
();
}
catch
(...)
{
}
}
bool
scheduled_actor
::
initialized
()
const
{
return
m_scheduler
!=
nullptr
;
}
scheduled_actor
::~
scheduled_actor
()
{
if
(
!
m_mailbox
.
closed
())
{
detail
::
sync_request_bouncer
f
{
exit_reason
()};
m_mailbox
.
close
(
f
);
}
}
void
scheduled_actor
::
run_detached
()
{
throw
std
::
logic_error
(
"scheduled_actor::run_detached called"
);
}
void
scheduled_actor
::
cleanup
(
std
::
uint32_t
reason
)
{
detail
::
sync_request_bouncer
f
{
reason
};
m_mailbox
.
close
(
f
);
super
::
cleanup
(
reason
);
}
bool
scheduled_actor
::
enqueue_impl
(
actor_state
next_state
,
const
message_header
&
hdr
,
any_tuple
&&
msg
)
{
CPPA_REQUIRE
(
next_state
==
actor_state
::
ready
||
next_state
==
actor_state
::
pending
);
auto
e
=
new_mailbox_element
(
hdr
,
std
::
move
(
msg
));
switch
(
m_mailbox
.
enqueue
(
e
))
{
case
intrusive
:
:
first_enqueued
:
{
auto
state
=
m_state
.
load
();
for
(;;)
{
switch
(
state
)
{
case
actor_state
:
:
blocked
:
{
if
(
m_state
.
compare_exchange_weak
(
state
,
next_state
))
{
CPPA_REQUIRE
(
m_scheduler
!=
nullptr
);
if
(
next_state
==
actor_state
::
ready
)
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"enqueued actor with id "
<<
id
()
<<
" to job queue"
);
m_scheduler
->
enqueue
(
this
);
return
false
;
}
return
true
;
}
break
;
}
case
actor_state
:
:
about_to_block
:
{
if
(
m_state
.
compare_exchange_weak
(
state
,
actor_state
::
ready
))
{
return
false
;
}
break
;
}
default:
return
false
;
}
}
break
;
}
case
intrusive
:
:
queue_closed
:
{
if
(
hdr
.
id
.
is_request
())
{
detail
::
sync_request_bouncer
f
{
exit_reason
()};
f
(
hdr
.
sender
,
hdr
.
id
);
}
break
;
}
default:
break
;
}
return
false
;
}
actor_state
scheduled_actor
::
compare_exchange_state
(
actor_state
expected
,
actor_state
desired
)
{
auto
e
=
expected
;
do
{
if
(
m_state
.
compare_exchange_weak
(
e
,
desired
))
return
desired
;
}
while
(
e
==
expected
);
return
e
;
}
void
scheduled_actor
::
enqueue
(
const
message_header
&
hdr
,
any_tuple
msg
)
{
enqueue_impl
(
actor_state
::
ready
,
hdr
,
std
::
move
(
msg
));
}
}
// namespace cppa
src/scheduler.cpp
View file @
c91bf3fc
...
...
@@ -39,8 +39,7 @@
#include "cppa/to_string.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/scoped_actor.hpp"
#include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp"
...
...
@@ -90,38 +89,31 @@ class scheduler_helper {
public:
typedef
intrusive_ptr
<
thread_mapped_actor
>
ptr_type
;
void
start
()
{
auto
mt
=
make_counted
<
thread_mapped_actor
>
();
auto
mp
=
make_counted
<
thread_mapped_actor
>
();
// launch threads
m_timer_thread
=
std
::
thread
{
&
scheduler_helper
::
timer_loop
,
mt
.
get
()};
m_printer_thread
=
std
::
thread
{
&
scheduler_helper
::
printer_loop
,
mp
.
get
()};
// set member variables
m_timer
=
std
::
move
(
mt
);
m_printer
=
std
::
move
(
mp
);
m_timer_thread
=
std
::
thread
{
&
scheduler_helper
::
timer_loop
,
m_timer
.
get
()};
m_printer_thread
=
std
::
thread
{
&
scheduler_helper
::
printer_loop
,
m_printer
.
get
()};
}
void
stop
()
{
auto
msg
=
make_any_tuple
(
atom
(
"DIE"
));
m_timer
.
enqueue
({
invalid_actor_addr
,
nullptr
},
msg
);
m_printer
.
enqueue
({
invalid_actor_addr
,
nullptr
},
msg
);
m_timer
->
enqueue
({
invalid_actor_addr
,
nullptr
},
msg
);
m_printer
->
enqueue
({
invalid_actor_addr
,
nullptr
},
msg
);
m_timer_thread
.
join
();
m_printer_thread
.
join
();
}
actor
m_timer
;
scoped_
actor
m_timer
;
std
::
thread
m_timer_thread
;
actor
m_printer
;
scoped_
actor
m_printer
;
std
::
thread
m_printer_thread
;
private:
static
void
timer_loop
(
thread_map
ped_actor
*
self
);
static
void
timer_loop
(
blocking_unty
ped_actor
*
self
);
static
void
printer_loop
(
thread_map
ped_actor
*
self
);
static
void
printer_loop
(
blocking_unty
ped_actor
*
self
);
};
...
...
@@ -136,7 +128,7 @@ inline void insert_dmsg(Map& storage,
storage
.
insert
(
std
::
make_pair
(
std
::
move
(
tout
),
std
::
move
(
dmsg
)));
}
void
scheduler_helper
::
timer_loop
(
thread_map
ped_actor
*
self
)
{
void
scheduler_helper
::
timer_loop
(
blocking_unty
ped_actor
*
self
)
{
// setup & local variables
bool
done
=
false
;
std
::
unique_ptr
<
mailbox_element
,
detail
::
disposer
>
msg_ptr
;
...
...
@@ -163,7 +155,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) {
// loop
while
(
!
done
)
{
while
(
!
msg_ptr
)
{
if
(
messages
.
empty
())
msg_ptr
.
reset
(
self
->
pop
());
if
(
messages
.
empty
())
msg_ptr
.
reset
(
self
->
dequeue
());
else
{
tout
=
hrc
::
now
();
// handle timeouts (send messages)
...
...
@@ -175,7 +167,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) {
}
// wait for next message or next timeout
if
(
it
!=
messages
.
end
())
{
msg_ptr
.
reset
(
self
->
try_
pop
(
it
->
first
));
msg_ptr
.
reset
(
self
->
try_
dequeue
(
it
->
first
));
}
}
}
...
...
@@ -184,7 +176,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) {
}
}
void
scheduler_helper
::
printer_loop
(
thread_map
ped_actor
*
self
)
{
void
scheduler_helper
::
printer_loop
(
blocking_unty
ped_actor
*
self
)
{
std
::
map
<
actor_addr
,
std
::
string
>
out
;
auto
flush_output
=
[
&
out
](
const
actor_addr
&
s
)
{
auto
i
=
out
.
find
(
s
);
...
...
@@ -257,8 +249,8 @@ scheduler::~scheduler() {
delete
m_helper
;
}
actor
&
scheduler
::
delayed_send_helper
()
{
return
m_helper
->
m_timer
;
actor
scheduler
::
delayed_send_helper
()
{
return
m_helper
->
m_timer
.
get
()
;
}
void
scheduler
::
register_converted_context
(
abstract_actor
*
what
)
{
...
...
@@ -287,8 +279,8 @@ scheduler* scheduler::create_singleton() {
return
new
detail
::
thread_pool_scheduler
;
}
const
actor
&
scheduler
::
printer
()
const
{
return
m_helper
->
m_printer
;
actor
scheduler
::
printer
()
const
{
return
m_helper
->
m_printer
.
get
()
;
}
}
// namespace cppa
src/scoped_actor.cpp
View file @
c91bf3fc
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/policy.hpp"
#include "cppa/scoped_actor.hpp"
#include "cppa/detail/proper_actor.hpp"
namespace
cppa
{
namespace
{
struct
impl
:
blocking_untyped_actor
{
void
act
()
override
{
}
};
blocking_untyped_actor
*
alloc
()
{
using
namespace
policy
;
return
new
detail
::
proper_actor
<
impl
,
no_scheduling
,
not_prioritizing
,
no_resume
,
nestable_invoke
>
;
}
}
// namespace <anonymous>
scoped_actor
::
scoped_actor
()
:
m_self
(
alloc
())
{
}
scoped_actor
::~
scoped_actor
()
{
}
}
// namespace cppa
src/singleton_manager.cpp
View file @
c91bf3fc
...
...
@@ -36,7 +36,6 @@
#include "cppa/exception.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/io/middleman.hpp"
...
...
src/sync_request_bouncer.cpp
View file @
c91bf3fc
...
...
@@ -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/>. *
\******************************************************************************/
\******************************************************************************/
#include "cppa/atom.hpp"
...
...
src/thread_pool_scheduler.cpp
View file @
c91bf3fc
...
...
@@ -36,12 +36,8 @@
#include "cppa/on.hpp"
#include "cppa/logging.hpp"
#include "cppa/prioritizing.hpp"
#include "cppa/untyped_actor.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/blocking_untyped_actor.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/util/fiber.hpp"
#include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/thread_pool_scheduler.hpp"
...
...
@@ -51,9 +47,13 @@ using std::endl;
namespace
cppa
{
namespace
detail
{
resumable
::
resume_result
thread_pool_scheduler
::
dummy
::
resume
(
util
::
fiber
*
)
{
throw
std
::
logic_error
(
"thread_pool_scheduler::dummy::resume"
);
}
struct
thread_pool_scheduler
::
worker
{
typedef
scheduled_actor
*
job_ptr
;
typedef
resumable
*
job_ptr
;
job_queue
*
m_job_queue
;
job_ptr
m_dummy
;
...
...
@@ -109,11 +109,11 @@ struct thread_pool_scheduler::worker {
return
;
// and say goodbye
}
CPPA_LOG_DEBUG
(
"resume actor with ID "
<<
job
->
id
());
if
(
job
->
resume
(
&
fself
)
==
resum
e_result
::
actor_
done
)
{
if
(
job
->
resume
(
&
fself
)
==
resum
able
::
done
)
{
CPPA_LOGMF
(
CPPA_DEBUG
,
self
,
"actor is done"
);
bool
hidden
=
job
->
is_hidden
();
/*FIXME
bool hidden = job->is_hidden();
job->deref();
if
(
!
hidden
)
get_actor_registry
()
->
dec_running
();
if (!hidden)
*/
get_actor_registry
()
->
dec_running
();
}
job
=
nullptr
;
}
...
...
@@ -134,7 +134,7 @@ thread_pool_scheduler::thread_pool_scheduler(size_t num_worker_threads) {
}
void
thread_pool_scheduler
::
supervisor_loop
(
job_queue
*
jqueue
,
scheduled_actor
*
dummy
,
resumable
*
dummy
,
size_t
num_threads
)
{
std
::
vector
<
std
::
unique_ptr
<
thread_pool_scheduler
::
worker
>
>
workers
;
for
(
size_t
i
=
0
;
i
<
num_threads
;
++
i
)
{
...
...
@@ -164,116 +164,18 @@ void thread_pool_scheduler::destroy() {
auto
ptr
=
m_queue
.
try_pop
();
while
(
ptr
!=
nullptr
)
{
if
(
ptr
!=
&
m_dummy
)
{
bool
hidden
=
ptr
->
is_hidden
();
/*FIXME
bool hidden = ptr->is_hidden();
ptr->deref();
std::atomic_thread_fence(std::memory_order_seq_cst);
if
(
!
hidden
)
get_actor_registry
()
->
dec_running
();
if (!hidden)
*/
get_actor_registry
()
->
dec_running
();
}
ptr
=
m_queue
.
try_pop
();
}
super
::
destroy
();
}
void
thread_pool_scheduler
::
enqueue
(
scheduled_actor
*
what
)
{
void
thread_pool_scheduler
::
enqueue
(
resumable
*
what
)
{
m_queue
.
push_back
(
what
);
}
void
exec_as_thread
(
bool
is_hidden
,
intrusive_ptr
<
untyped_actor
>
ptr
)
{
/*TODO:
if (!is_hidden) get_actor_registry()->inc_running();
std::thread([=] {
try { ptr->exec_bhvr_stack(); }
catch (...) { }
if (!is_hidden) {
std::atomic_thread_fence(std::memory_order_seq_cst);
get_actor_registry()->dec_running();
}
}).detach();
*/
}
local_actor_ptr
thread_pool_scheduler
::
exec
(
spawn_options
os
,
scheduled_actor_ptr
p
)
{
/*TODO:
CPPA_REQUIRE(p != nullptr);
bool is_hidden = has_hide_flag(os);
if (has_detach_flag(os)) {
exec_as_thread(is_hidden, p [p] {
p->run_detached();
});
return p;
}
p->attach_to_scheduler(this, is_hidden);
if (p->has_behavior() || p->impl_type() == default_event_based_impl) {
if (!is_hidden) get_actor_registry()->inc_running();
p->ref(); // implicit reference that's released if actor dies
if (p->impl_type() != event_based_impl) m_queue.push_back(p.get());
}
else p->on_exit();
return p;
*/
}
local_actor_ptr
thread_pool_scheduler
::
exec
(
spawn_options
os
,
init_callback
cb
,
actor_fun
f
)
{
local_actor_ptr
result
;
auto
set_result
=
[
&
](
local_actor_ptr
value
)
{
CPPA_REQUIRE
(
result
==
nullptr
&&
value
!=
nullptr
);
result
=
std
::
move
(
value
);
if
(
cb
)
cb
(
result
.
get
());
};
if
(
has_priority_aware_flag
(
os
))
{
using
impl
=
extend
<
local_actor
>::
with
<
stackless
,
threaded
,
prioritizing
>
;
set_result
(
make_counted
<
impl
>
());
/*TODO:
exec_as_thread(has_hide_flag(os), [result, f] {
try {
f();
}
catch (actor_exited& e) { }
catch (std::exception& e) {
CPPA_LOGF_ERROR("actor with ID " << result->id()
<< " terminated due to an unhandled exception; "
<< detail::demangle(typeid(e)) << ": "
<< e.what());
}
catch (...) {
CPPA_LOGF_ERROR("actor with ID " << result->id()
<< " terminated due to an unknown exception");
}
result->on_exit();
});
*/
}
else
if
(
has_blocking_api_flag
(
os
))
{
# ifndef CPPA_DISABLE_CONTEXT_SWITCHING
if
(
!
has_detach_flag
(
os
))
{
auto
p
=
make_counted
<
context_switching_actor
>
(
std
::
move
(
f
));
set_result
(
p
);
exec
(
os
,
std
::
move
(
p
));
}
else
# endif
/* else tree */
{
//auto p = make_counted<thread_mapped_actor>(std::move(f));
//set_result(p);
/*TODO:
exec_as_thread(has_hide_flag(os), [p] {
p->run();
p->on_exit();
});
*/
}
}
else
{
/*TODO:
auto p = event_based_actor::from(std::move(f));
set_result(p);
exec(os, p);
*/
}
CPPA_REQUIRE
(
result
!=
nullptr
);
return
result
;
}
}
}
// namespace cppa::detail
src/untyped_actor.cpp
0 → 100644
View file @
c91bf3fc
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/untyped_actor.hpp"
namespace
cppa
{
void
untyped_actor
::
forward_to
(
const
actor
&
)
{
}
}
// namespace cppa
unit_testing/ping_pong.cpp
View file @
c91bf3fc
...
...
@@ -15,21 +15,21 @@ namespace {
size_t
s_pongs
=
0
;
behavior
ping_behavior
(
size_t
num_pings
)
{
behavior
ping_behavior
(
local_actor
*
self
,
size_t
num_pings
)
{
return
(
on
(
atom
(
"pong"
),
arg_match
)
>>
[
num_pings
](
int
value
)
->
any_tuple
{
on
(
atom
(
"pong"
),
arg_match
)
>>
[
=
](
int
value
)
->
any_tuple
{
CPPA_LOGF_ERROR_IF
(
!
self
->
last_sender
(),
"last_sender() == nullptr"
);
CPPA_LOGF_INFO
(
"received {'pong', "
<<
value
<<
"}"
);
//cout << to_string(self->last_dequeued()) << endl;
if
(
++
s_pongs
>=
num_pings
)
{
CPPA_LOGF_INFO
(
"reached maximum, send {'EXIT', user_defined} "
<<
"to last sender and quit with normal reason"
);
send_exit
(
self
->
last_sender
(),
exit_reason
::
user_shutdown
);
se
lf
->
se
nd_exit
(
self
->
last_sender
(),
exit_reason
::
user_shutdown
);
self
->
quit
();
}
return
{
atom
(
"ping"
),
value
}
;
return
make_any_tuple
(
atom
(
"ping"
),
value
)
;
},
others
()
>>
[]
{
others
()
>>
[
=
]
{
CPPA_LOGF_ERROR
(
"unexpected message; "
<<
to_string
(
self
->
last_dequeued
()));
self
->
quit
(
exit_reason
::
user_shutdown
);
...
...
@@ -37,13 +37,13 @@ behavior ping_behavior(size_t num_pings) {
);
}
behavior
pong_behavior
()
{
behavior
pong_behavior
(
local_actor
*
self
)
{
return
(
on
(
atom
(
"ping"
),
arg_match
)
>>
[](
int
value
)
->
any_tuple
{
CPPA_LOGF_INFO
(
"received {'ping', "
<<
value
<<
"}"
);
return
{
atom
(
"pong"
),
value
+
1
}
;
return
make_any_tuple
(
atom
(
"pong"
),
value
+
1
)
;
},
others
()
>>
[]
{
others
()
>>
[
=
]
{
CPPA_LOGF_ERROR
(
"unexpected message; "
<<
to_string
(
self
->
last_dequeued
()));
self
->
quit
(
exit_reason
::
user_shutdown
);
...
...
@@ -57,27 +57,27 @@ size_t pongs() {
return
s_pongs
;
}
void
ping
(
size_t
num_pings
)
{
void
ping
(
blocking_untyped_actor
*
self
,
size_t
num_pings
)
{
CPPA_LOGF_TRACE
(
"num_pings = "
<<
num_pings
);
s_pongs
=
0
;
receive_loop
(
ping_behavior
(
num_pings
));
self
->
receive_loop
(
ping_behavior
(
self
,
num_pings
));
}
void
event_based_ping
(
size_t
num_pings
)
{
void
event_based_ping
(
untyped_actor
*
self
,
size_t
num_pings
)
{
CPPA_LOGF_TRACE
(
"num_pings = "
<<
num_pings
);
s_pongs
=
0
;
become
(
ping_behavior
(
num_pings
));
self
->
become
(
ping_behavior
(
self
,
num_pings
));
}
void
pong
(
actor_pt
r
ping_actor
)
{
void
pong
(
blocking_untyped_actor
*
self
,
acto
r
ping_actor
)
{
CPPA_LOGF_TRACE
(
"ping_actor = "
<<
to_string
(
ping_actor
));
send
(
ping_actor
,
atom
(
"pong"
),
0
);
// kickoff
receive_loop
(
pong_behavior
(
));
se
lf
->
se
nd
(
ping_actor
,
atom
(
"pong"
),
0
);
// kickoff
self
->
receive_loop
(
pong_behavior
(
self
));
}
void
event_based_pong
(
actor_pt
r
ping_actor
)
{
void
event_based_pong
(
untyped_actor
*
self
,
acto
r
ping_actor
)
{
CPPA_LOGF_TRACE
(
"ping_actor = "
<<
to_string
(
ping_actor
));
CPPA_REQUIRE
(
ping_actor
!=
nullptr
);
send
(
ping_actor
,
atom
(
"pong"
),
0
);
// kickoff
become
(
pong_behavior
(
));
se
lf
->
se
nd
(
ping_actor
,
atom
(
"pong"
),
0
);
// kickoff
self
->
become
(
pong_behavior
(
self
));
}
unit_testing/ping_pong.hpp
View file @
c91bf3fc
...
...
@@ -10,9 +10,9 @@ void ping(cppa::blocking_untyped_actor*, size_t num_pings);
void
event_based_ping
(
cppa
::
untyped_actor
*
,
size_t
num_pings
);
void
pong
(
cppa
::
blocking_untyped_actor
*
,
cppa
::
actor
_ptr
ping_actor
);
void
pong
(
cppa
::
blocking_untyped_actor
*
,
cppa
::
actor
ping_actor
);
void
event_based_pong
(
cppa
::
untyped_actor
*
,
cppa
::
actor
_ptr
ping_actor
);
void
event_based_pong
(
cppa
::
untyped_actor
*
,
cppa
::
actor
ping_actor
);
// returns the number of messages ping received
size_t
pongs
();
...
...
unit_testing/test.hpp
View file @
c91bf3fc
...
...
@@ -60,6 +60,10 @@ inline std::string cppa_stream_arg(const cppa::actor& ptr) {
return
cppa
::
to_string
(
ptr
);
}
inline
std
::
string
cppa_stream_arg
(
const
cppa
::
actor_addr
&
ptr
)
{
return
cppa
::
to_string
(
ptr
);
}
inline
std
::
string
cppa_stream_arg
(
const
bool
&
value
)
{
return
value
?
"true"
:
"false"
;
}
...
...
unit_testing/test_atom.cpp
View file @
c91bf3fc
...
...
@@ -5,6 +5,7 @@
#include "test.hpp"
#include "cppa/cppa.hpp"
#include "cppa/scoped_actor.hpp"
namespace
cppa
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
const
atom_value
&
a
)
{
...
...
@@ -27,6 +28,15 @@ void foo() {
<<
" = "
<<
to_string
(
AtomValue
)
<<
")"
);
}
struct
mirror
{
mirror
(
local_actor
*
self
)
:
m_self
(
self
)
{
}
template
<
typename
...
Ts
>
void
operator
()(
Ts
&&
...
args
)
{
m_self
->
send
(
m_self
,
make_any_tuple
(
std
::
forward
<
Ts
>
(
args
)...));
}
local_actor
*
m_self
;
};
int
main
()
{
bool
matched_pattern
[
3
]
=
{
false
,
false
,
false
};
CPPA_TEST
(
test_atom
);
...
...
@@ -38,12 +48,14 @@ int main() {
CPPA_CHECK_EQUAL
(
atom
(
" "
),
atom
(
"@!?"
));
// check to_string impl.
CPPA_CHECK_EQUAL
(
to_string
(
s_foo
),
"FooBar"
);
self
<<
make_cow_tuple
(
atom
(
"foo"
),
static_cast
<
std
::
uint32_t
>
(
42
))
<<
make_cow_tuple
(
atom
(
":Attach"
),
atom
(
":Baz"
),
"cstring"
)
<<
make_cow_tuple
(
atom
(
"b"
),
atom
(
"a"
),
atom
(
"c"
),
23.
f
)
<<
make_cow_tuple
(
atom
(
"a"
),
atom
(
"b"
),
atom
(
"c"
),
23.
f
);
scoped_actor
self
;
mirror
m
(
self
.
get
());
m
(
atom
(
"foo"
),
static_cast
<
std
::
uint32_t
>
(
42
));
m
(
atom
(
":Attach"
),
atom
(
":Baz"
),
"cstring"
);
m
(
atom
(
"b"
),
atom
(
"a"
),
atom
(
"c"
),
23.
f
);
m
(
atom
(
"a"
),
atom
(
"b"
),
atom
(
"c"
),
23.
f
);
int
i
=
0
;
receive_for
(
i
,
3
)
(
self
->
receive_for
(
i
,
3
)
(
on
<
atom
(
"foo"
),
std
::
uint32_t
>
()
>>
[
&
](
std
::
uint32_t
value
)
{
matched_pattern
[
0
]
=
true
;
CPPA_CHECK_EQUAL
(
value
,
42
);
...
...
@@ -58,7 +70,7 @@ int main() {
}
);
CPPA_CHECK
(
matched_pattern
[
0
]
&&
matched_pattern
[
1
]
&&
matched_pattern
[
2
]);
receive
(
self
->
receive
(
// "erase" message { atom("b"), atom("a"), atom("c"), 23.f }
others
()
>>
CPPA_CHECKPOINT_CB
(),
after
(
std
::
chrono
::
seconds
(
0
))
>>
CPPA_UNEXPECTED_TOUT_CB
()
...
...
unit_testing/test_broker.cpp
View file @
c91bf3fc
...
...
@@ -135,7 +135,8 @@ int main(int argc, char** argv) {
CPPA_CHECKPOINT
();
auto
p
=
spawn
(
ping
,
10
);
CPPA_CHECKPOINT
();
auto
cl
=
spawn_io
(
peer
,
"localhost"
,
port
,
p
);
//FIXME auto cl = spawn_io(peer, "localhost", port, p);
actor
cl
;
CPPA_CHECKPOINT
();
send_as
(
nullptr
,
p
,
atom
(
"kickoff"
),
cl
);
CPPA_CHECKPOINT
();
...
...
@@ -154,7 +155,7 @@ int main(int argc, char** argv) {
uint16_t
port
=
4242
;
for
(;;)
{
try
{
spawn_io_server
(
peer_acceptor
,
port
,
p
);
//FIXME:
spawn_io_server(peer_acceptor, port, p);
CPPA_CHECKPOINT
();
ostringstream
oss
;
oss
<<
app_path
<<
" mode=client port="
<<
port
<<
" &>/dev/null"
;
...
...
unit_testing/test_local_group.cpp
View file @
c91bf3fc
...
...
@@ -9,7 +9,6 @@
#include "test.hpp"
#include "cppa/on.hpp"
#include "cppa/self.hpp"
#include "cppa/cppa.hpp"
#include "cppa/actor.hpp"
#include "cppa/group.hpp"
...
...
@@ -22,14 +21,14 @@ using std::endl;
using
std
::
string
;
using
namespace
cppa
;
void
testee
(
int
current_value
,
int
final_result
)
{
become
(
void
testee
(
untyped_actor
*
self
,
int
current_value
,
int
final_result
)
{
self
->
become
(
on_arg_match
>>
[
=
](
int
result
)
{
auto
next
=
result
+
current_value
;
if
(
next
>=
final_result
)
self
->
quit
();
else
testee
(
next
,
final_result
);
else
testee
(
self
,
next
,
final_result
);
},
after
(
std
::
chrono
::
seconds
(
2
))
>>
[]
{
after
(
std
::
chrono
::
seconds
(
2
))
>>
[
=
]
{
CPPA_UNEXPECTED_TOUT
();
self
->
quit
(
exit_reason
::
user_shutdown
);
}
...
...
@@ -38,8 +37,9 @@ void testee(int current_value, int final_result) {
int
main
()
{
CPPA_TEST
(
test_local_group
);
/*
auto foo_group = group::get("local", "foo");
a
ctor_ptr
master
=
spawn_in_group
(
foo_group
,
testee
,
0
,
10
);
a
uto
master = spawn_in_group(foo_group, testee, 0, 10);
for (int i = 0; i < 5; ++i) {
// spawn five workers and let them join local/foo
spawn_in_group(foo_group, [master] {
...
...
@@ -52,5 +52,6 @@ int main() {
send(foo_group, 2);
await_all_actors_done();
shutdown();
*/
return
CPPA_TEST_RESULT
();
}
unit_testing/test_remote_actor.cpp
View file @
c91bf3fc
...
...
@@ -18,10 +18,10 @@ namespace {
typedef
std
::
pair
<
std
::
string
,
std
::
string
>
string_pair
;
typedef
vector
<
actor
_ptr
>
actor_vector
;
typedef
vector
<
actor
>
actor_vector
;
void
reflector
()
{
become
(
void
reflector
(
untyped_actor
*
self
)
{
self
->
become
(
others
()
>>
[
=
]
{
CPPA_LOGF_INFO
(
"reflect and quit"
);
self
->
quit
();
...
...
@@ -30,26 +30,26 @@ void reflector() {
);
}
void
spawn5_server_impl
(
actor_pt
r
client
,
group_ptr
grp
)
{
void
spawn5_server_impl
(
untyped_actor
*
self
,
acto
r
client
,
group_ptr
grp
)
{
CPPA_LOGF_TRACE
(
CPPA_TARG
(
client
,
to_string
)
<<
", "
<<
CPPA_TARG
(
grp
,
to_string
));
spawn_in_group
(
grp
,
reflector
);
spawn_in_group
(
grp
,
reflector
);
//FIXME
spawn_in_group(grp, reflector);
//FIXME
spawn_in_group(grp, reflector);
CPPA_LOGF_INFO
(
"send {'Spawn5'} and await {'ok', actor_vector}"
);
sync_send
(
client
,
atom
(
"Spawn5"
),
grp
).
then
(
s
elf
->
s
ync_send
(
client
,
atom
(
"Spawn5"
),
grp
).
then
(
on
(
atom
(
"ok"
),
arg_match
)
>>
[
=
](
const
actor_vector
&
vec
)
{
CPPA_LOGF_INFO
(
"received vector with "
<<
vec
.
size
()
<<
" elements"
);
send
(
grp
,
"Hello reflectors!"
,
5.0
);
se
lf
->
se
nd
(
grp
,
"Hello reflectors!"
,
5.0
);
if
(
vec
.
size
()
!=
5
)
{
CPPA_PRINTERR
(
"remote client did not spawn five reflectors!"
);
}
for
(
auto
&
a
:
vec
)
self
->
monitor
(
a
);
},
others
()
>>
[]
{
others
()
>>
[
=
]
{
CPPA_UNEXPECTED_MSG
();
self
->
quit
(
exit_reason
::
unhandled_exception
);
},
after
(
chrono
::
seconds
(
10
))
>>
[]
{
after
(
chrono
::
seconds
(
10
))
>>
[
=
]
{
CPPA_UNEXPECTED_TOUT
();
self
->
quit
(
exit_reason
::
unhandled_exception
);
}
...
...
@@ -58,34 +58,34 @@ void spawn5_server_impl(actor_ptr client, group_ptr grp) {
CPPA_PRINT
(
"wait for reflected messages"
);
// receive seven reply messages (2 local, 5 remote)
auto
replies
=
std
::
make_shared
<
int
>
(
0
);
become
(
self
->
become
(
on
(
"Hello reflectors!"
,
5.0
)
>>
[
=
]
{
if
(
++*
replies
==
7
)
{
CPPA_PRINT
(
"wait for DOWN messages"
);
auto
downs
=
std
::
make_shared
<
int
>
(
0
);
become
(
self
->
become
(
on
(
atom
(
"DOWN"
),
arg_match
)
>>
[
=
](
std
::
uint32_t
reason
)
{
if
(
reason
!=
exit_reason
::
normal
)
{
CPPA_PRINTERR
(
"reflector exited for non-normal exit reason!"
);
}
if
(
++*
downs
==
5
)
{
CPPA_CHECKPOINT
();
send
(
client
,
atom
(
"Spawn5Done"
));
se
lf
->
se
nd
(
client
,
atom
(
"Spawn5Done"
));
self
->
quit
();
}
},
others
()
>>
[]
{
others
()
>>
[
=
]
{
CPPA_UNEXPECTED_MSG
();
self
->
quit
(
exit_reason
::
unhandled_exception
);
},
after
(
chrono
::
seconds
(
2
))
>>
[]
{
after
(
chrono
::
seconds
(
2
))
>>
[
=
]
{
CPPA_UNEXPECTED_TOUT
();
self
->
quit
(
exit_reason
::
unhandled_exception
);
}
);
}
},
after
(
std
::
chrono
::
seconds
(
2
))
>>
[]
{
after
(
std
::
chrono
::
seconds
(
2
))
>>
[
=
]
{
CPPA_UNEXPECTED_TOUT
();
self
->
quit
(
exit_reason
::
unhandled_exception
);
}
...
...
@@ -94,33 +94,33 @@ void spawn5_server_impl(actor_ptr client, group_ptr grp) {
}
// receive seven reply messages (2 local, 5 remote)
void
spawn5_server
(
actor_pt
r
client
,
bool
inverted
)
{
if
(
!
inverted
)
spawn5_server_impl
(
client
,
group
::
get
(
"local"
,
"foobar"
));
void
spawn5_server
(
untyped_actor
*
self
,
acto
r
client
,
bool
inverted
)
{
if
(
!
inverted
)
spawn5_server_impl
(
self
,
client
,
group
::
get
(
"local"
,
"foobar"
));
else
{
CPPA_LOGF_INFO
(
"request group"
);
sync_send
(
client
,
atom
(
"GetGroup"
)).
then
(
s
elf
->
s
ync_send
(
client
,
atom
(
"GetGroup"
)).
then
(
[
=
](
const
group_ptr
&
remote_group
)
{
spawn5_server_impl
(
client
,
remote_group
);
spawn5_server_impl
(
self
,
client
,
remote_group
);
}
);
}
}
void
spawn5_client
()
{
become
(
void
spawn5_client
(
untyped_actor
*
self
)
{
self
->
become
(
on
(
atom
(
"GetGroup"
))
>>
[]()
->
group_ptr
{
CPPA_LOGF_INFO
(
"received {'GetGroup'}"
);
return
group
::
get
(
"local"
,
"foobar"
);
},
on
(
atom
(
"Spawn5"
),
arg_match
)
>>
[
=
](
const
group_ptr
&
grp
)
->
any_tuple
{
on
(
atom
(
"Spawn5"
),
arg_match
)
>>
[
=
](
const
group_ptr
&
)
->
any_tuple
{
CPPA_LOGF_INFO
(
"received {'Spawn5'}"
);
actor_vector
vec
;
for
(
int
i
=
0
;
i
<
5
;
++
i
)
{
vec
.
push_back
(
spawn_in_group
(
grp
,
reflector
));
//FIXME
vec.push_back(spawn_in_group(grp, reflector));
}
return
{
atom
(
"ok"
),
std
::
move
(
vec
)}
;
return
make_any_tuple
(
atom
(
"ok"
),
std
::
move
(
vec
))
;
},
on
(
atom
(
"Spawn5Done"
))
>>
[]
{
on
(
atom
(
"Spawn5Done"
))
>>
[
=
]
{
CPPA_LOGF_INFO
(
"received {'Spawn5Done'}"
);
self
->
quit
();
}
...
...
@@ -129,8 +129,9 @@ void spawn5_client() {
}
// namespace <anonymous>
template
<
typename
T
>
void
await_down
(
actor_ptr
ptr
,
T
continuation
)
{
template
<
typename
F
>
void
await_down
(
actor
,
F
)
{
/*
become (
on(atom("DOWN"), arg_match) >> [=](uint32_t) -> bool {
if (self->last_sender() == ptr) {
...
...
@@ -140,27 +141,28 @@ void await_down(actor_ptr ptr, T continuation) {
return false; // not the 'DOWN' message we are waiting for
}
);
*/
}
static
constexpr
size_t
num_pings
=
10
;
class
client
:
public
event_bas
ed_actor
{
class
client
:
public
untyp
ed_actor
{
public:
client
(
actor
_ptr
server
)
:
m_server
(
std
::
move
(
server
))
{
}
client
(
actor
server
)
:
m_server
(
std
::
move
(
server
))
{
}
void
init
()
{
spawn_ping
();
behavior
make_behavior
()
override
{
return
spawn_ping
();
}
private:
void
spawn_ping
()
{
behavior
spawn_ping
()
{
CPPA_PRINT
(
"send {'SpawnPing'}"
);
send
(
m_server
,
atom
(
"SpawnPing"
));
become
(
on
(
atom
(
"PingPtr"
),
arg_match
)
>>
[
=
](
const
actor
_ptr
&
ping
)
{
return
(
on
(
atom
(
"PingPtr"
),
arg_match
)
>>
[
=
](
const
actor
&
ping
)
{
auto
pptr
=
spawn
<
monitored
+
detached
+
blocking_api
>
(
pong
,
ping
);
await_down
(
pptr
,
[
=
]
{
send_sync_msg
();
...
...
@@ -195,7 +197,7 @@ class client : public event_based_actor {
void
test_group_comm
()
{
CPPA_PRINT
(
"test group communication via network"
);
sync_send
(
m_server
,
atom
(
"GClient"
)).
then
(
on
(
atom
(
"GClient"
),
arg_match
)
>>
[
=
](
actor
_ptr
gclient
)
{
on
(
atom
(
"GClient"
),
arg_match
)
>>
[
=
](
actor
gclient
)
{
auto
s5a
=
spawn
<
monitored
>
(
spawn5_server
,
gclient
,
false
);
await_down
(
s5a
,
[
=
]{
test_group_comm_inverted
();
...
...
@@ -208,38 +210,38 @@ class client : public event_based_actor {
CPPA_PRINT
(
"test group communication via network (inverted setup)"
);
become
(
on
(
atom
(
"GClient"
))
>>
[
=
]()
->
any_tuple
{
auto
cptr
=
self
->
last_sender
();
auto
cptr
=
last_sender
();
auto
s5c
=
spawn
<
monitored
>
(
spawn5_client
);
// set next behavior
await_down
(
s5c
,
[
=
]
{
CPPA_CHECKPOINT
();
self
->
quit
();
quit
();
});
return
{
atom
(
"GClient"
),
s5c
}
;
return
make_any_tuple
(
atom
(
"GClient"
),
s5c
)
;
}
);
}
actor
_ptr
m_server
;
actor
m_server
;
};
class
server
:
public
event_bas
ed_actor
{
class
server
:
public
untyp
ed_actor
{
public:
void
init
()
{
await_spawn_ping
();
behavior
make_behavior
()
override
{
return
await_spawn_ping
();
}
private:
void
await_spawn_ping
()
{
behavior
await_spawn_ping
()
{
CPPA_PRINT
(
"await {'SpawnPing'}"
);
become
(
return
(
on
(
atom
(
"SpawnPing"
))
>>
[
=
]()
->
any_tuple
{
CPPA_PRINT
(
"received {'SpawnPing'}"
);
auto
client
=
self
->
last_sender
();
auto
client
=
last_sender
();
CPPA_LOGF_ERROR_IF
(
!
client
,
"last_sender() == nullptr"
);
CPPA_LOGF_INFO
(
"spawn event-based ping actor"
);
auto
pptr
=
spawn
<
monitored
>
(
event_based_ping
,
num_pings
);
...
...
@@ -248,7 +250,7 @@ class server : public event_based_actor {
CPPA_CHECK_EQUAL
(
pongs
(),
num_pings
);
await_sync_msg
();
});
return
{
atom
(
"PingPtr"
),
pptr
}
;
return
make_any_tuple
(
atom
(
"PingPtr"
),
pptr
)
;
}
);
}
...
...
@@ -275,7 +277,7 @@ class server : public event_based_actor {
CPPA_CHECK_EQUAL
(
*
foobars
,
100
);
test_group_comm
();
}
return
self
->
last_dequeued
();
return
last_dequeued
();
}
);
}
...
...
@@ -284,23 +286,23 @@ class server : public event_based_actor {
CPPA_PRINT
(
"test group communication via network"
);
become
(
on
(
atom
(
"GClient"
))
>>
[
=
]()
->
any_tuple
{
auto
cptr
=
self
->
last_sender
();
auto
cptr
=
last_sender
();
auto
s5c
=
spawn
<
monitored
>
(
spawn5_client
);
await_down
(
s5c
,
[
=
]
{
test_group_comm_inverted
(
cptr
);
//
test_group_comm_inverted(cptr);
});
return
{
atom
(
"GClient"
),
s5c
}
;
return
make_any_tuple
(
atom
(
"GClient"
),
s5c
)
;
}
);
}
void
test_group_comm_inverted
(
actor
_ptr
cptr
)
{
void
test_group_comm_inverted
(
actor
cptr
)
{
CPPA_PRINT
(
"test group communication via network (inverted setup)"
);
sync_send
(
cptr
,
atom
(
"GClient"
)).
then
(
on
(
atom
(
"GClient"
),
arg_match
)
>>
[
=
](
actor
_ptr
gclient
)
{
on
(
atom
(
"GClient"
),
arg_match
)
>>
[
=
](
actor
gclient
)
{
await_down
(
spawn
<
monitored
>
(
spawn5_server
,
gclient
,
true
),
[
=
]
{
CPPA_CHECKPOINT
();
self
->
quit
();
quit
();
});
}
);
...
...
@@ -321,6 +323,7 @@ int main(int argc, char** argv) {
}
else
{
run_client_part
(
get_kv_pairs
(
argc
,
argv
),
[](
uint16_t
port
)
{
scoped_actor
self
;
auto
serv
=
remote_actor
(
"localhost"
,
port
);
// remote_actor is supposed to return the same server
// when connecting to the same host again
...
...
@@ -331,8 +334,8 @@ int main(int argc, char** argv) {
auto
server3
=
remote_actor
(
localhost
,
port
);
CPPA_CHECK
(
serv
==
server3
);
}
auto
c
=
spawn
<
client
,
monitored
>
(
serv
);
receive
(
auto
c
=
s
elf
->
s
pawn
<
client
,
monitored
>
(
serv
);
self
->
receive
(
on
(
atom
(
"DOWN"
),
arg_match
)
>>
[
=
](
uint32_t
rsn
)
{
CPPA_CHECK_EQUAL
(
self
->
last_sender
(),
c
);
CPPA_CHECK_EQUAL
(
rsn
,
exit_reason
::
normal
);
...
...
@@ -343,44 +346,47 @@ int main(int argc, char** argv) {
}
}
CPPA_TEST
(
test_remote_actor
);
auto
serv
=
spawn
<
server
,
monitored
>
();
uint16_t
port
=
4242
;
bool
success
=
false
;
do
{
try
{
publish
(
serv
,
port
,
"127.0.0.1"
);
success
=
true
;
CPPA_LOGF_DEBUG
(
"running on port "
<<
port
);
}
catch
(
bind_failure
&
)
{
// try next port
++
port
;
}
}
while
(
!
success
);
thread
child
;
ostringstream
oss
;
if
(
run_remote_actor
)
{
oss
<<
app_path
<<
" run=remote_actor port="
<<
port
<<
" &>/dev/null"
;
// execute client_part() in a separate process,
// connected via localhost socket
child
=
thread
([
&
oss
]()
{
CPPA_LOGC_TRACE
(
"NONE"
,
"main$thread_launcher"
,
""
);
string
cmdstr
=
oss
.
str
();
if
(
system
(
cmdstr
.
c_str
())
!=
0
)
{
CPPA_PRINTERR
(
"FATAL: command
\"
"
<<
cmdstr
<<
"
\"
failed!"
);
abort
();
{
// lifetime scope of self
scoped_actor
self
;
auto
serv
=
self
->
spawn
<
server
,
monitored
>
();
uint16_t
port
=
4242
;
bool
success
=
false
;
do
{
try
{
publish
(
serv
,
port
,
"127.0.0.1"
);
success
=
true
;
CPPA_LOGF_DEBUG
(
"running on port "
<<
port
);
}
catch
(
bind_failure
&
)
{
// try next port
++
port
;
}
});
}
else
{
CPPA_PRINT
(
"actor published at port "
<<
port
);
}
CPPA_CHECKPOINT
();
receive
(
on
(
atom
(
"DOWN"
),
arg_match
)
>>
[
=
](
uint32_t
rsn
)
{
CPPA_CHECK_EQUAL
(
self
->
last_sender
(),
serv
);
CPPA_CHECK_EQUAL
(
rsn
,
exit_reason
::
normal
);
}
);
while
(
!
success
);
ostringstream
oss
;
if
(
run_remote_actor
)
{
oss
<<
app_path
<<
" run=remote_actor port="
<<
port
<<
" &>/dev/null"
;
// execute client_part() in a separate process,
// connected via localhost socket
child
=
thread
([
&
oss
]()
{
CPPA_LOGC_TRACE
(
"NONE"
,
"main$thread_launcher"
,
""
);
string
cmdstr
=
oss
.
str
();
if
(
system
(
cmdstr
.
c_str
())
!=
0
)
{
CPPA_PRINTERR
(
"FATAL: command
\"
"
<<
cmdstr
<<
"
\"
failed!"
);
abort
();
}
});
}
else
{
CPPA_PRINT
(
"actor published at port "
<<
port
);
}
CPPA_CHECKPOINT
();
self
->
receive
(
on
(
atom
(
"DOWN"
),
arg_match
)
>>
[
&
](
uint32_t
rsn
)
{
CPPA_CHECK_EQUAL
(
self
->
last_sender
(),
serv
);
CPPA_CHECK_EQUAL
(
rsn
,
exit_reason
::
normal
);
}
);
}
// lifetime scope of self
// wait until separate process (in sep. thread) finished execution
await_all_actors_done
();
CPPA_CHECKPOINT
();
...
...
unit_testing/test_serialization.cpp
View file @
c91bf3fc
...
...
@@ -26,7 +26,6 @@
#include "test.hpp"
#include "cppa/self.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/announce.hpp"
...
...
@@ -227,7 +226,8 @@ int main() {
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
try
{
auto
ttup
=
make_any_tuple
(
1
,
2
,
actor_ptr
(
self
));
scoped_actor
self
;
auto
ttup
=
make_any_tuple
(
1
,
2
,
actor
{
self
.
get
()});
util
::
buffer
wr_buf
;
binary_serializer
bs
(
&
wr_buf
,
&
addressing
);
bs
<<
ttup
;
...
...
@@ -239,7 +239,8 @@ int main() {
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
try
{
auto
ttup
=
make_any_tuple
(
1
,
2
,
actor_ptr
(
self
));
scoped_actor
self
;
auto
ttup
=
make_any_tuple
(
1
,
2
,
actor
{
self
.
get
()});
util
::
buffer
wr_buf
;
binary_serializer
bs
(
&
wr_buf
,
&
addressing
);
bs
<<
ttup
;
...
...
@@ -275,47 +276,6 @@ int main() {
}
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
try
{
/*
any_tuple msg1 = cppa::make_cow_tuple(42, string("Hello \"World\"!"));
auto msg1_tostring = to_string(msg1);
if (msg1str != msg1_tostring) {
CPPA_FAILURE("msg1str != to_string(msg1)");
cerr << "to_string(msg1) = " << msg1_tostring << endl;
cerr << "to_string(msg1str) = " << msg1str << endl;
}
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << msg1;
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
object obj1;
bd >> obj1;
object obj2 = from_string(to_string(msg1));
CPPA_CHECK(obj1 == obj2);
if (typeid(any_tuple) == *(obj1.type()) && obj2.type() == obj1.type()) {
auto& content1 = get<any_tuple>(obj1);
auto& content2 = get<any_tuple>(obj2);
auto opt1 = tuple_cast<decltype(42), string>(content1);
auto opt2 = tuple_cast<decltype(42), string>(content2);
CPPA_CHECK(opt1.valid() && opt2.valid());
if (opt1.valid() && opt2.valid()) {
auto& tup1 = *opt1;
auto& tup2 = *opt2;
CPPA_CHECK_EQUAL(tup1.size(), 2);
CPPA_CHECK_EQUAL(tup2.size(), 2);
CPPA_CHECK_EQUAL(get<0>(tup1), 42);
CPPA_CHECK_EQUAL(get<0>(tup2), 42);
CPPA_CHECK_EQUAL(get<1>(tup1), "Hello \"World\"!");
CPPA_CHECK_EQUAL(get<1>(tup2), "Hello \"World\"!");
}
}
else {
CPPA_FAILURE("obj.type() != typeid(message)");
}
*/
}
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
CPPA_CHECK
((
is_iterable
<
int
>::
value
)
==
false
);
// string is primitive and thus not identified by is_iterable
CPPA_CHECK
((
is_iterable
<
string
>::
value
)
==
false
);
...
...
@@ -333,71 +293,5 @@ int main() {
}
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
try
{
// test serializers / deserializers with struct_b
// get meta object for struct_b
/*
announce<struct_b>(compound_member(&struct_b::a,
&struct_a::x,
&struct_a::y),
&struct_b::z,
&struct_b::ints);
// testees
struct_b b1 = { { 1, 2 }, 3, list<int>{ 4, 5, 6, 7, 8, 9, 10 } };
struct_b b2;
struct_b b3;
// expected result of to_string(&b1, meta_b)
auto b1str = "struct_b ( struct_a ( 1, 2 ), 3, "
"{ 4, 5, 6, 7, 8, 9, 10 } )";
// verify
CPPA_CHECK_EQUAL((to_string(b1)), b1str); {
// serialize b1 to buf
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << b1;
// deserialize b2 from buf
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
object res;
bd >> res;
CPPA_CHECK_EQUAL(res.type()->name(), "struct_b");
b2 = get<struct_b>(res);
}
// verify result of serialization / deserialization
CPPA_CHECK(b1 == b2);
CPPA_CHECK_EQUAL(to_string(b2), b1str);
{ // deserialize b3 from string
object res = from_string(b1str);
CPPA_CHECK_EQUAL(res.type()->name(), "struct_b");
b3 = get<struct_b>(res);
}
CPPA_CHECK(b1 == b3);
*/
}
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
try
{
// test serializers / deserializers with struct_c
// get meta type of struct_c and "announce"
/*
announce<struct_c>(&struct_c::strings, &struct_c::ints);
// testees
struct_c c1{strmap{{"abc", u"cba" }, { "x", u"y" }}, set<int>{9, 4, 5}};
struct_c c2; {
// serialize c1 to buf
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << c1;
// serialize c2 from buf
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
object res;
bd >> res;
CPPA_CHECK_EQUAL(res.type()->name(), "struct_c");
c2 = get<struct_c>(res);
}
// verify result of serialization / deserialization
CPPA_CHECK(c1 == c2);
*/
}
catch
(
exception
&
e
)
{
CPPA_FAILURE
(
to_verbose_string
(
e
));
}
return
CPPA_TEST_RESULT
();
}
unit_testing/test_spawn.cpp
View file @
c91bf3fc
...
...
@@ -6,16 +6,7 @@
#include "test.hpp"
#include "ping_pong.hpp"
#include "cppa/on.hpp"
#include "cppa/cppa.hpp"
#include "cppa/actor.hpp"
#include "cppa/factory.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/sb_actor.hpp"
#include "cppa/to_string.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/event_based_actor.hpp"
using
namespace
std
;
using
namespace
cppa
;
...
...
@@ -64,7 +55,7 @@ class event_testee : public sb_actor<event_testee> {
};
// quits after 5 timeouts
actor
_ptr
spawn_event_testee2
()
{
actor
spawn_event_testee2
()
{
struct
impl
:
sb_actor
<
impl
>
{
behavior
wait4timeout
(
int
remaining
)
{
return
(
...
...
@@ -84,7 +75,7 @@ actor_ptr spawn_event_testee2() {
struct
chopstick
:
public
sb_actor
<
chopstick
>
{
behavior
taken_by
(
actor
_ptr
whom
)
{
behavior
taken_by
(
actor
whom
)
{
return
(
on
<
atom
(
"take"
)
>
()
>>
[
=
]
{
return
atom
(
"busy"
);
...
...
@@ -92,7 +83,7 @@ struct chopstick : public sb_actor<chopstick> {
on
(
atom
(
"put"
),
whom
)
>>
[
=
]
{
become
(
available
);
},
on
(
atom
(
"break"
))
>>
[
=
]
()
{
on
(
atom
(
"break"
))
>>
[
=
]
{
quit
();
}
);
...
...
@@ -104,7 +95,7 @@ struct chopstick : public sb_actor<chopstick> {
chopstick
()
{
available
=
(
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
actor
_ptr
whom
)
->
atom_value
{
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
actor
whom
)
->
atom_value
{
become
(
taken_by
(
whom
));
return
atom
(
"taken"
);
},
...
...
@@ -118,9 +109,9 @@ struct chopstick : public sb_actor<chopstick> {
class
testee_actor
{
void
wait4string
()
{
void
wait4string
(
blocking_untyped_actor
*
self
)
{
bool
string_received
=
false
;
do_receive
(
self
->
do_receive
(
on
<
string
>
()
>>
[
&
]
{
string_received
=
true
;
},
...
...
@@ -131,9 +122,9 @@ class testee_actor {
.
until
(
gref
(
string_received
));
}
void
wait4float
()
{
void
wait4float
(
blocking_untyped_actor
*
self
)
{
bool
float_received
=
false
;
do_receive
(
self
->
do_receive
(
on
<
float
>
()
>>
[
&
]
{
float_received
=
true
;
},
...
...
@@ -142,15 +133,15 @@ class testee_actor {
}
)
.
until
(
gref
(
float_received
));
wait4string
();
wait4string
(
self
);
}
public:
void
operator
()()
{
receive_loop
(
void
operator
()(
blocking_untyped_actor
*
self
)
{
self
->
receive_loop
(
on
<
int
>
()
>>
[
&
]
{
wait4float
();
wait4float
(
self
);
},
on
<
atom
(
"get_state"
)
>
()
>>
[
&
]
{
return
"wait4int"
;
...
...
@@ -160,40 +151,43 @@ class testee_actor {
};
// receives one timeout and quits
void
testee1
()
{
become
(
after
(
chrono
::
milliseconds
(
10
))
>>
[]
{
unbecome
();
});
//
self->
receives one timeout and quits
void
testee1
(
untyped_actor
*
self
)
{
self
->
become
(
after
(
chrono
::
milliseconds
(
10
))
>>
[
=
]
{
self
->
unbecome
();
});
}
void
testee2
(
actor_pt
r
other
)
{
void
testee2
(
untyped_actor
*
self
,
acto
r
other
)
{
self
->
link_to
(
other
);
send
(
other
,
uint32_t
(
1
));
become
(
on
<
uint32_t
>
()
>>
[](
uint32_t
sleep_time
)
{
se
lf
->
se
nd
(
other
,
uint32_t
(
1
));
self
->
become
(
on
<
uint32_t
>
()
>>
[
=
](
uint32_t
sleep_time
)
{
// "sleep" for sleep_time milliseconds
become
(
self
->
become
(
keep_behavior
,
after
(
chrono
::
milliseconds
(
sleep_time
))
>>
[]
{
unbecome
();
}
after
(
chrono
::
milliseconds
(
sleep_time
))
>>
[
=
]
{
self
->
unbecome
();
}
);
}
);
}
template
<
class
Testee
>
string
behavior_test
(
actor_ptr
et
)
{
string
behavior_test
(
actor
et
)
{
scoped_actor
self
;
string
result
;
string
testee_name
=
detail
::
to_uniform_name
(
typeid
(
Testee
));
send
(
et
,
1
);
send
(
et
,
2
);
send
(
et
,
3
);
send
(
et
,
.1
f
);
send
(
et
,
"hello "
+
testee_name
);
send
(
et
,
.2
f
);
send
(
et
,
.3
f
);
send
(
et
,
"hello again "
+
testee_name
);
send
(
et
,
"goodbye "
+
testee_name
);
send
(
et
,
atom
(
"get_state"
));
receive
(
se
lf
->
se
nd
(
et
,
1
);
se
lf
->
se
nd
(
et
,
2
);
se
lf
->
se
nd
(
et
,
3
);
se
lf
->
se
nd
(
et
,
.1
f
);
se
lf
->
se
nd
(
et
,
"hello "
+
testee_name
);
se
lf
->
se
nd
(
et
,
.2
f
);
se
lf
->
se
nd
(
et
,
.3
f
);
se
lf
->
se
nd
(
et
,
"hello again "
+
testee_name
);
se
lf
->
se
nd
(
et
,
"goodbye "
+
testee_name
);
se
lf
->
se
nd
(
et
,
atom
(
"get_state"
));
self
->
receive
(
on_arg_match
>>
[
&
](
const
string
&
str
)
{
result
=
str
;
},
...
...
@@ -202,7 +196,7 @@ string behavior_test(actor_ptr et) {
throw
runtime_error
(
testee_name
+
" does not reply"
);
}
);
send_exit
(
et
,
exit_reason
::
user_shutdown
);
se
lf
->
se
nd_exit
(
et
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
return
result
;
}
...
...
@@ -259,9 +253,9 @@ class fixed_stack : public sb_actor<fixed_stack> {
};
void
echo_actor
(
)
{
become
(
others
()
>>
[]()
->
any_tuple
{
behavior
echo_actor
(
untyped_actor
*
self
)
{
return
(
others
()
>>
[
=
]()
->
any_tuple
{
self
->
quit
(
exit_reason
::
normal
);
return
self
->
last_dequeued
();
}
...
...
@@ -272,26 +266,26 @@ void echo_actor() {
struct
simple_mirror
:
sb_actor
<
simple_mirror
>
{
behavior
init_state
=
(
others
()
>>
[]
{
return
self
->
last_dequeued
();
others
()
>>
[
=
]
{
return
last_dequeued
();
}
);
};
void
high_priority_testee
(
)
{
send
(
self
,
atom
(
"b"
));
se
nd
({
self
,
message_priority
::
high
}
,
atom
(
"a"
));
// 'a' must be received before 'b'
become
(
on
(
atom
(
"b"
))
>>
[]
{
behavior
high_priority_testee
(
untyped_actor
*
self
)
{
se
lf
->
se
nd
(
self
,
atom
(
"b"
));
se
lf
->
send
(
message_priority
::
high
,
self
,
atom
(
"a"
));
// 'a' must be
self->
received before 'b'
return
(
on
(
atom
(
"b"
))
>>
[
=
]
{
CPPA_FAILURE
(
"received 'b' before 'a'"
);
self
->
quit
();
},
on
(
atom
(
"a"
))
>>
[]
{
on
(
atom
(
"a"
))
>>
[
=
]
{
CPPA_CHECKPOINT
();
become
(
on
(
atom
(
"b"
))
>>
[]
{
self
->
become
(
on
(
atom
(
"b"
))
>>
[
=
]
{
CPPA_CHECKPOINT
();
self
->
quit
();
},
...
...
@@ -302,65 +296,65 @@ void high_priority_testee() {
);
}
struct
high_priority_testee_class
:
event_bas
ed_actor
{
void
init
()
{
high_priority_testee
(
);
struct
high_priority_testee_class
:
untyp
ed_actor
{
behavior
make_behavior
()
override
{
return
high_priority_testee
(
this
);
}
};
struct
master
:
event_bas
ed_actor
{
void
init
()
override
{
become
(
on
(
atom
(
"done"
))
>>
[
]()
{
self
->
quit
(
exit_reason
::
user_shutdown
);
struct
master
:
untyp
ed_actor
{
behavior
make_behavior
()
override
{
return
(
on
(
atom
(
"done"
))
>>
[
=
]
{
quit
(
exit_reason
::
user_shutdown
);
}
);
}
};
struct
slave
:
event_bas
ed_actor
{
struct
slave
:
untyp
ed_actor
{
slave
(
actor
_ptr
master
)
:
master
{
master
}
{
}
slave
(
actor
master
)
:
master
{
master
}
{
}
void
init
()
override
{
behavior
make_behavior
()
override
{
link_to
(
master
);
become
(
return
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
}
actor
_ptr
master
;
actor
master
;
};
void
test_serial_reply
()
{
auto
mirror_behavior
=
[
](
int
num
)
{
become
(
others
()
>>
[
=
]()
->
any_tuple
{
auto
mirror_behavior
=
[
=
](
untyped_actor
*
self
,
int
num
)
{
self
->
become
(
others
()
>>
[
=
]()
->
any_tuple
{
cout
<<
"right back at you from "
<<
num
<<
"; ID: "
<<
self
->
id
()
<<
endl
;
return
self
->
last_dequeued
();
});
};
auto
master
=
spawn
([
=
]
{
auto
master
=
spawn
([
=
]
(
untyped_actor
*
self
)
{
cout
<<
"ID of master: "
<<
self
->
id
()
<<
endl
;
// produce 5 mirror actors
auto
c0
=
spawn
<
linked
>
(
mirror_behavior
,
0
);
auto
c1
=
spawn
<
linked
>
(
mirror_behavior
,
1
);
auto
c2
=
spawn
<
linked
>
(
mirror_behavior
,
2
);
auto
c3
=
spawn
<
linked
>
(
mirror_behavior
,
3
);
auto
c4
=
spawn
<
linked
>
(
mirror_behavior
,
4
);
become
(
auto
c0
=
s
elf
->
s
pawn
<
linked
>
(
mirror_behavior
,
0
);
auto
c1
=
s
elf
->
s
pawn
<
linked
>
(
mirror_behavior
,
1
);
auto
c2
=
s
elf
->
s
pawn
<
linked
>
(
mirror_behavior
,
2
);
auto
c3
=
s
elf
->
s
pawn
<
linked
>
(
mirror_behavior
,
3
);
auto
c4
=
s
elf
->
s
pawn
<
linked
>
(
mirror_behavior
,
4
);
self
->
become
(
on
(
atom
(
"hi there"
))
>>
[
=
]
{
// *
return
sync_send
(
c0
,
atom
(
"sub0"
)).
then
(
return
s
elf
->
s
ync_send
(
c0
,
atom
(
"sub0"
)).
then
(
on
(
atom
(
"sub0"
))
>>
[
=
]
{
return
sync_send
(
c1
,
atom
(
"sub1"
)).
then
(
return
s
elf
->
s
ync_send
(
c1
,
atom
(
"sub1"
)).
then
(
on
(
atom
(
"sub1"
))
>>
[
=
]
{
return
sync_send
(
c2
,
atom
(
"sub2"
)).
then
(
return
s
elf
->
s
ync_send
(
c2
,
atom
(
"sub2"
)).
then
(
on
(
atom
(
"sub2"
))
>>
[
=
]
{
return
sync_send
(
c3
,
atom
(
"sub3"
)).
then
(
return
s
elf
->
s
ync_send
(
c3
,
atom
(
"sub3"
)).
then
(
on
(
atom
(
"sub3"
))
>>
[
=
]
{
return
sync_send
(
c4
,
atom
(
"sub4"
)).
then
(
return
s
elf
->
s
ync_send
(
c4
,
atom
(
"sub4"
)).
then
(
on
(
atom
(
"sub4"
))
>>
[
=
]
{
return
atom
(
"hiho"
);
}
...
...
@@ -373,24 +367,25 @@ void test_serial_reply() {
);
}
);
//*/
//return atom("hiho");
}
);
});
cout
<<
"ID of main: "
<<
self
->
id
()
<<
endl
;
sync_send
(
master
,
atom
(
"hi there"
)).
await
(
on
(
atom
(
"hiho"
))
>>
[]
{
CPPA_CHECKPOINT
();
},
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
send_exit
(
master
,
exit_reason
::
user_shutdown
);
{
// lifetime scope of self
scoped_actor
self
;
cout
<<
"ID of main: "
<<
self
->
id
()
<<
endl
;
self
->
sync_send
(
master
,
atom
(
"hi there"
)).
await
(
on
(
atom
(
"hiho"
))
>>
[]
{
CPPA_CHECKPOINT
();
},
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
self
->
send_exit
(
master
,
exit_reason
::
user_shutdown
);
}
await_all_actors_done
();
}
void
test_or_else
()
{
scoped_actor
self
;
partial_function
handle_a
{
on
(
"a"
)
>>
[]
{
return
1
;
}
};
...
...
@@ -400,32 +395,28 @@ void test_or_else() {
partial_function
handle_c
{
on
(
"c"
)
>>
[]
{
return
3
;
}
};
auto
run_testee
([
](
actor_pt
r
testee
)
{
sync_send
(
testee
,
"a"
).
await
([](
int
i
)
{
auto
run_testee
([
&
](
acto
r
testee
)
{
s
elf
->
s
ync_send
(
testee
,
"a"
).
await
([](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
1
);
});
sync_send
(
testee
,
"b"
).
await
([](
int
i
)
{
s
elf
->
s
ync_send
(
testee
,
"b"
).
await
([](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
2
);
});
sync_send
(
testee
,
"c"
).
await
([](
int
i
)
{
s
elf
->
s
ync_send
(
testee
,
"c"
).
await
([](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
3
);
});
send_exit
(
testee
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
self
->
send_exit
(
testee
,
exit_reason
::
user_shutdown
);
self
->
await_all_other_actors_done
();
});
run_testee
(
spawn
([
=
]
{
become
(
handle_a
.
or_else
(
handle_b
).
or_else
(
handle_c
)
);
return
handle_a
.
or_else
(
handle_b
).
or_else
(
handle_c
);
})
);
run_testee
(
spawn
([
=
]
{
become
(
handle_a
,
handle_b
,
handle_c
);
})
);
run_testee
(
spawn
([
=
]
{
become
(
return
(
handle_a
.
or_else
(
handle_b
),
on
(
"c"
)
>>
[]
{
return
3
;
}
);
...
...
@@ -433,7 +424,7 @@ void test_or_else() {
);
run_testee
(
spawn
([
=
]
{
become
(
return
(
on
(
"a"
)
>>
[]
{
return
1
;
},
handle_b
.
or_else
(
handle_c
)
);
...
...
@@ -443,8 +434,8 @@ void test_or_else() {
void
test_continuation
()
{
auto
mirror
=
spawn
<
simple_mirror
>
();
spawn
([
=
]
{
sync_send
(
mirror
,
42
).
then
(
spawn
([
=
]
(
untyped_actor
*
self
)
{
s
elf
->
s
ync_send
(
mirror
,
42
).
then
(
on
(
42
)
>>
[]
{
return
"fourty-two"
;
}
...
...
@@ -456,7 +447,7 @@ void test_continuation() {
).
continue_with
(
[
=
](
float
f
)
{
CPPA_CHECK_EQUAL
(
f
,
4.2
f
);
send_exit
(
mirror
,
exit_reason
::
user_shutdown
);
se
lf
->
se
nd_exit
(
mirror
,
exit_reason
::
user_shutdown
);
self
->
quit
();
}
);
...
...
@@ -464,8 +455,8 @@ void test_continuation() {
await_all_actors_done
();
}
int
mai
n
()
{
CPPA_TEST
(
test_spawn
)
;
void
test_spaw
n
()
{
scoped_actor
self
;
test_serial_reply
();
test_or_else
();
...
...
@@ -475,36 +466,36 @@ int main() {
auto
m
=
spawn
<
master
,
detached
>
();
spawn
<
slave
>
(
m
);
spawn
<
slave
>
(
m
);
send
(
m
,
atom
(
"done"
));
se
lf
->
se
nd
(
m
,
atom
(
"done"
));
await_all_actors_done
();
CPPA_CHECKPOINT
();
CPPA_PRINT
(
"test send()"
);
send
(
self
,
1
,
2
,
3
,
true
);
receive
(
on
(
1
,
2
,
3
,
true
)
>>
[]
{
});
self
<<
any_tuple
{}
;
receive
(
on
()
>>
[]
{
});
CPPA_PRINT
(
"test se
lf->se
nd()"
);
se
lf
->
se
nd
(
self
,
1
,
2
,
3
,
true
);
self
->
receive
(
on
(
1
,
2
,
3
,
true
)
>>
[]
{
});
self
->
send
(
self
,
any_tuple
{})
;
self
->
receive
(
on
()
>>
[]
{
});
CPPA_CHECKPOINT
();
self
<<
any_tuple
{}
;
receive
(
on
()
>>
[]
{
});
self
->
send
(
self
,
any_tuple
{})
;
self
->
receive
(
on
()
>>
[]
{
});
CPPA_PRINT
(
"test receive with zero timeout"
);
receive
(
CPPA_PRINT
(
"test
self->
receive with zero timeout"
);
self
->
receive
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
(),
after
(
chrono
::
seconds
(
0
))
>>
[]
{
/* mailbox empty */
}
);
CPPA_CHECKPOINT
();
CPPA_PRINT
(
"test mirror"
);
{
auto
mirror
=
spawn
<
simple_mirror
,
monitored
>
();
send
(
mirror
,
"hello mirror"
);
receive
(
auto
mirror
=
s
elf
->
s
pawn
<
simple_mirror
,
monitored
>
();
se
lf
->
se
nd
(
mirror
,
"hello mirror"
);
self
->
receive
(
on
(
"hello mirror"
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
send_exit
(
mirror
,
exit_reason
::
user_shutdown
);
receive
(
se
lf
->
se
nd_exit
(
mirror
,
exit_reason
::
user_shutdown
);
self
->
receive
(
on
(
atom
(
"DOWN"
),
exit_reason
::
user_shutdown
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
...
...
@@ -513,14 +504,14 @@ int main() {
}
CPPA_PRINT
(
"test detached mirror"
);
{
auto
mirror
=
spawn
<
simple_mirror
,
monitored
+
detached
>
();
send
(
mirror
,
"hello mirror"
);
receive
(
auto
mirror
=
s
elf
->
s
pawn
<
simple_mirror
,
monitored
+
detached
>
();
se
lf
->
se
nd
(
mirror
,
"hello mirror"
);
self
->
receive
(
on
(
"hello mirror"
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
send_exit
(
mirror
,
exit_reason
::
user_shutdown
);
receive
(
se
lf
->
se
nd_exit
(
mirror
,
exit_reason
::
user_shutdown
);
self
->
receive
(
on
(
atom
(
"DOWN"
),
exit_reason
::
user_shutdown
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
...
...
@@ -529,15 +520,15 @@ int main() {
}
CPPA_PRINT
(
"test priority aware mirror"
);
{
auto
mirror
=
spawn
<
simple_mirror
,
monitored
+
priority_aware
>
();
auto
mirror
=
s
elf
->
s
pawn
<
simple_mirror
,
monitored
+
priority_aware
>
();
CPPA_CHECKPOINT
();
send
(
mirror
,
"hello mirror"
);
receive
(
se
lf
->
se
nd
(
mirror
,
"hello mirror"
);
self
->
receive
(
on
(
"hello mirror"
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
send_exit
(
mirror
,
exit_reason
::
user_shutdown
);
receive
(
se
lf
->
se
nd_exit
(
mirror
,
exit_reason
::
user_shutdown
);
self
->
receive
(
on
(
atom
(
"DOWN"
),
exit_reason
::
user_shutdown
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
...
...
@@ -547,8 +538,8 @@ int main() {
CPPA_PRINT
(
"test echo actor"
);
auto
mecho
=
spawn
(
echo_actor
);
send
(
mecho
,
"hello echo"
);
receive
(
se
lf
->
se
nd
(
mecho
,
"hello echo"
);
self
->
receive
(
on
(
"hello echo"
)
>>
[]
{
},
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
...
...
@@ -556,12 +547,12 @@ int main() {
CPPA_CHECKPOINT
();
CPPA_PRINT
(
"test delayed_send()"
);
delayed_send
(
self
,
chrono
::
seconds
(
1
),
1
,
2
,
3
);
receive
(
on
(
1
,
2
,
3
)
>>
[]
{
});
self
->
delayed_send
(
self
,
chrono
::
seconds
(
1
),
1
,
2
,
3
);
self
->
receive
(
on
(
1
,
2
,
3
)
>>
[]
{
});
CPPA_CHECKPOINT
();
CPPA_PRINT
(
"test timeout"
);
receive
(
after
(
chrono
::
seconds
(
1
))
>>
[]
{
});
self
->
receive
(
after
(
chrono
::
seconds
(
1
))
>>
[]
{
});
CPPA_CHECKPOINT
();
spawn
(
testee1
);
...
...
@@ -573,42 +564,11 @@ int main() {
CPPA_CHECKPOINT
();
auto
cstk
=
spawn
<
chopstick
>
();
send
(
cstk
,
atom
(
"take"
),
self
);
receive
(
se
lf
->
se
nd
(
cstk
,
atom
(
"take"
),
self
);
self
->
receive
(
on
(
atom
(
"taken"
))
>>
[
&
]()
{
send
(
cstk
,
atom
(
"put"
),
self
);
send
(
cstk
,
atom
(
"break"
));
}
);
await_all_actors_done
();
CPPA_CHECKPOINT
();
auto
factory
=
factory
::
event_based
([
&
](
int
*
i
,
float
*
,
string
*
)
{
become
(
on
(
atom
(
"get_int"
))
>>
[
i
]
{
return
*
i
;
},
on
(
atom
(
"set_int"
),
arg_match
)
>>
[
i
](
int
new_value
)
{
*
i
=
new_value
;
},
on
(
atom
(
"done"
))
>>
[]
{
self
->
quit
();
}
);
});
auto
foobaz_actor
=
factory
.
spawn
(
23
);
send
(
foobaz_actor
,
atom
(
"get_int"
));
send
(
foobaz_actor
,
atom
(
"set_int"
),
42
);
send
(
foobaz_actor
,
atom
(
"get_int"
));
send
(
foobaz_actor
,
atom
(
"done"
));
receive
(
on_arg_match
>>
[
&
](
int
value
)
{
CPPA_CHECK_EQUAL
(
value
,
23
);
}
);
receive
(
on_arg_match
>>
[
&
](
int
value
)
{
CPPA_CHECK_EQUAL
(
value
,
42
);
self
->
send
(
cstk
,
atom
(
"put"
),
self
);
self
->
send
(
cstk
,
atom
(
"break"
));
}
);
await_all_actors_done
();
...
...
@@ -616,13 +576,13 @@ int main() {
auto
st
=
spawn
<
fixed_stack
>
(
10
);
// push 20 values
for
(
int
i
=
0
;
i
<
20
;
++
i
)
send
(
st
,
atom
(
"push"
),
i
);
for
(
int
i
=
0
;
i
<
20
;
++
i
)
se
lf
->
se
nd
(
st
,
atom
(
"push"
),
i
);
// pop 20 times
for
(
int
i
=
0
;
i
<
20
;
++
i
)
send
(
st
,
atom
(
"pop"
));
for
(
int
i
=
0
;
i
<
20
;
++
i
)
se
lf
->
se
nd
(
st
,
atom
(
"pop"
));
// expect 10 failure messages
{
int
i
=
0
;
receive_for
(
i
,
10
)
(
self
->
receive_for
(
i
,
10
)
(
on
(
atom
(
"failure"
))
>>
[]
{
}
);
CPPA_CHECKPOINT
();
...
...
@@ -631,7 +591,7 @@ int main() {
{
vector
<
int
>
values
;
int
i
=
0
;
receive_for
(
i
,
10
)
(
self
->
receive_for
(
i
,
10
)
(
on
(
atom
(
"ok"
),
arg_match
)
>>
[
&
](
int
value
)
{
values
.
push_back
(
value
);
}
...
...
@@ -640,31 +600,31 @@ int main() {
CPPA_CHECK_EQUAL
(
util
::
join
(
values
,
","
),
util
::
join
(
values
,
","
));
}
// terminate st
send_exit
(
st
,
exit_reason
::
user_shutdown
);
se
lf
->
se
nd_exit
(
st
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
CPPA_CHECKPOINT
();
auto
sync_testee1
=
spawn
<
blocking_api
>
([]
{
receive
(
auto
sync_testee1
=
spawn
<
blocking_api
>
([]
(
blocking_untyped_actor
*
self
)
{
self
->
receive
(
on
(
atom
(
"get"
))
>>
[]
{
return
make_cow_tuple
(
42
,
2
);
}
);
});
send
(
self
,
0
,
0
);
auto
handle
=
sync_send
(
sync_testee1
,
atom
(
"get"
));
se
lf
->
se
nd
(
self
,
0
,
0
);
auto
handle
=
s
elf
->
s
ync_send
(
sync_testee1
,
atom
(
"get"
));
// wait for some time (until sync response arrived in mailbox)
receive
(
after
(
chrono
::
milliseconds
(
50
))
>>
[]
{
});
// enqueue async messages (must be skipped by receive_response)
send
(
self
,
42
,
1
);
self
->
receive
(
after
(
chrono
::
milliseconds
(
50
))
>>
[]
{
});
// enqueue async messages (must be skipped by
self->
receive_response)
se
lf
->
se
nd
(
self
,
42
,
1
);
// must skip sync message
receive
(
self
->
receive
(
on
(
42
,
arg_match
)
>>
[
&
](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
1
);
}
);
// must skip remaining async message
receive_response
(
handle
)
(
self
->
receive_response
(
handle
)
(
on_arg_match
>>
[
&
](
int
a
,
int
b
)
{
CPPA_CHECK_EQUAL
(
a
,
42
);
CPPA_CHECK_EQUAL
(
b
,
2
);
...
...
@@ -673,56 +633,52 @@ int main() {
after
(
chrono
::
seconds
(
10
))
>>
CPPA_UNEXPECTED_TOUT_CB
()
);
// dequeue remaining async. message
receive
(
on
(
0
,
0
)
>>
CPPA_CHECKPOINT_CB
());
self
->
receive
(
on
(
0
,
0
)
>>
CPPA_CHECKPOINT_CB
());
// make sure there's no other message in our mailbox
receive
(
self
->
receive
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
(),
after
(
chrono
::
seconds
(
0
))
>>
[]
{
}
);
await_all_actors_done
();
CPPA_CHECKPOINT
();
CPPA_PRINT
(
"test sync send with factory spawned actor"
);
auto
sync_testee_factory
=
factory
::
event_based
(
[
&
]()
{
become
(
on
(
"hi"
)
>>
[
&
]()
{
auto
handle
=
sync_send
(
self
->
last_sender
(),
"whassup?"
);
handle_response
(
handle
)
(
on_arg_match
>>
[
&
](
const
string
&
str
)
{
CPPA_CHECK
(
self
->
last_sender
()
!=
nullptr
);
CPPA_CHECK_EQUAL
(
str
,
"nothing"
);
self
->
quit
();
// TODO: should return the value instead
send
(
self
->
last_sender
(),
"goodbye!"
);
},
after
(
chrono
::
minutes
(
1
))
>>
[]
{
cerr
<<
"PANIC!!!!"
<<
endl
;
abort
();
}
);
},
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
}
);
CPPA_PRINT
(
"test sync send"
);
CPPA_CHECKPOINT
();
auto
sync_testee
=
sync_testee_factory
.
spawn
();
auto
sync_testee
=
spawn
<
blocking_api
>
([](
blocking_untyped_actor
*
self
)
{
self
->
receive
(
on
(
"hi"
,
arg_match
)
>>
[
&
](
actor
from
)
{
self
->
sync_send
(
from
,
"whassup?"
,
self
).
await
(
on_arg_match
>>
[
&
](
const
string
&
str
)
->
string
{
CPPA_CHECK
(
self
->
last_sender
()
!=
nullptr
);
CPPA_CHECK_EQUAL
(
str
,
"nothing"
);
self
->
quit
();
return
"goodbye!"
;
},
after
(
chrono
::
minutes
(
1
))
>>
[]
{
cerr
<<
"PANIC!!!!"
<<
endl
;
abort
();
}
);
},
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
});
self
->
monitor
(
sync_testee
);
se
nd
(
sync_testee
,
"hi"
);
receive
(
on
(
"whassup?"
)
>>
[
&
](
)
->
std
::
string
{
se
lf
->
send
(
sync_testee
,
"hi"
,
self
);
self
->
receive
(
on
(
"whassup?"
,
arg_match
)
>>
[
&
](
actor
other
)
->
std
::
string
{
CPPA_CHECKPOINT
();
// this is NOT a reply, it's just an asynchronous message
se
nd
(
self
->
last_sender
()
,
"a lot!"
);
se
lf
->
send
(
other
,
"a lot!"
);
return
"nothing"
;
}
);
receive
(
self
->
receive
(
on
(
"goodbye!"
)
>>
CPPA_CHECKPOINT_CB
(),
after
(
std
::
chrono
::
seconds
(
5
))
>>
CPPA_UNEXPECTED_TOUT_CB
()
);
receive
(
self
->
receive
(
on
(
atom
(
"DOWN"
),
exit_reason
::
normal
)
>>
[
&
]
{
CPPA_CHECK_EQUAL
(
self
->
last_sender
(),
sync_testee
);
}
...
...
@@ -730,125 +686,83 @@ int main() {
await_all_actors_done
();
CPPA_CHECKPOINT
();
sync_send
(
sync_testee
,
"!?"
).
await
(
s
elf
->
s
ync_send
(
sync_testee
,
"!?"
).
await
(
on
(
atom
(
"EXITED"
),
any_vals
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
(),
after
(
chrono
::
milliseconds
(
5
))
>>
CPPA_UNEXPECTED_TOUT_CB
()
);
auto
inflater
=
factory
::
event_based
(
[](
string
*
,
actor_ptr
*
receiver
)
{
become
(
on_arg_match
>>
[
=
](
int
n
,
const
string
&
s
)
{
send
(
*
receiver
,
n
*
2
,
s
);
},
on
(
atom
(
"done"
))
>>
[]
{
self
->
quit
();
}
);
}
);
auto
joe
=
inflater
.
spawn
(
"Joe"
,
self
);
auto
bob
=
inflater
.
spawn
(
"Bob"
,
joe
);
send
(
bob
,
1
,
"hello actor"
);
receive
(
auto
inflater
=
[](
untyped_actor
*
self
,
const
string
&
,
actor
buddy
)
{
self
->
become
(
on_arg_match
>>
[
=
](
int
n
,
const
string
&
s
)
{
self
->
send
(
buddy
,
n
*
2
,
s
);
},
on
(
atom
(
"done"
))
>>
[
=
]
{
self
->
quit
();
}
);
};
auto
joe
=
spawn
(
inflater
,
"Joe"
,
self
);
auto
bob
=
spawn
(
inflater
,
"Bob"
,
joe
);
self
->
send
(
bob
,
1
,
"hello actor"
);
self
->
receive
(
on
(
4
,
"hello actor"
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
// kill joe and bob
auto
poison_pill
=
make_any_tuple
(
atom
(
"done"
));
joe
<<
poison_pill
;
bob
<<
poison_pill
;
anon_send
(
joe
,
poison_pill
)
;
anon_send
(
bob
,
poison_pill
)
;
await_all_actors_done
();
function
<
actor_ptr
(
const
string
&
,
const
actor_ptr
&
)
>
spawn_next
;
auto
kr34t0r
=
factory
::
event_based
(
// it's safe to pass spawn_next as reference here, because
// - it is guaranteeed to outlive kr34t0r by general scoping rules
// - the lambda is always executed in the current actor's thread
// but using spawn_next in a message handler could
// still cause undefined behavior!
[
&
spawn_next
](
string
*
name
,
actor_ptr
*
pal
)
{
if
(
*
name
==
"Joe"
&&
!*
pal
)
{
*
pal
=
spawn_next
(
"Bob"
,
self
);
}
become
(
others
()
>>
[
pal
]()
{
// forward message and die
*
pal
<<
self
->
last_dequeued
();
self
->
quit
();
}
);
function
<
actor
(
const
string
&
,
const
actor
&
)
>
spawn_next
;
// it's safe to capture spawn_next as reference here, because
// - it is guaranteeed to outlive kr34t0r by general scoping rules
// - the lambda is always executed in the current actor's thread
// but using spawn_next in a message handler could
// still cause undefined behavior!
auto
kr34t0r
=
[
&
spawn_next
](
untyped_actor
*
self
,
const
string
&
name
,
actor
pal
)
{
if
(
name
==
"Joe"
&&
!
pal
)
{
pal
=
spawn_next
(
"Bob"
,
self
);
}
);
spawn_next
=
[
&
kr34t0r
](
const
string
&
name
,
const
actor_ptr
&
pal
)
{
return
kr34t0r
.
spawn
(
name
,
pal
);
self
->
become
(
others
()
>>
[
=
]
{
// forward message and die
self
->
send_tuple
(
pal
,
self
->
last_dequeued
());
self
->
quit
();
}
);
};
auto
joe_the_second
=
kr34t0r
.
spawn
(
"Joe"
);
send
(
joe_the_second
,
atom
(
"done"
));
spawn_next
=
[
&
kr34t0r
](
const
string
&
name
,
const
actor
&
pal
)
{
return
spawn
(
kr34t0r
,
name
,
pal
);
};
auto
joe_the_second
=
spawn
(
kr34t0r
,
"Joe"
,
invalid_actor
);
self
->
send
(
joe_the_second
,
atom
(
"done"
));
await_all_actors_done
();
int
zombie_init_called
=
0
;
int
zombie_on_exit_called
=
0
;
factory
::
event_based
([
&
]()
{
++
zombie_init_called
;
},
[
&
]()
{
++
zombie_on_exit_called
;
}).
spawn
();
CPPA_CHECK_EQUAL
(
zombie_init_called
,
1
);
CPPA_CHECK_EQUAL
(
zombie_on_exit_called
,
1
);
factory
::
event_based
([
&
](
int
*
i
)
{
CPPA_CHECK_EQUAL
(
*
i
,
42
);
++
zombie_init_called
;
},
[
&
](
int
*
i
)
{
CPPA_CHECK_EQUAL
(
*
i
,
42
);
++
zombie_on_exit_called
;
})
.
spawn
(
42
);
CPPA_CHECK_EQUAL
(
zombie_init_called
,
2
);
CPPA_CHECK_EQUAL
(
zombie_on_exit_called
,
2
);
factory
::
event_based
([
&
](
int
*
i
)
{
CPPA_CHECK_EQUAL
(
*
i
,
23
);
++
zombie_init_called
;
},
[
&
]()
{
++
zombie_on_exit_called
;
})
.
spawn
(
23
);
CPPA_CHECK_EQUAL
(
zombie_init_called
,
3
);
CPPA_CHECK_EQUAL
(
zombie_on_exit_called
,
3
);
auto
f
=
factory
::
event_based
([](
string
*
name
)
{
become
(
auto
f
=
[](
const
string
&
name
)
->
behavior
{
return
(
on
(
atom
(
"get_name"
))
>>
[
name
]
{
return
make_cow_tuple
(
atom
(
"name"
),
*
name
);
return
make_cow_tuple
(
atom
(
"name"
),
name
);
}
);
}
)
;
auto
a1
=
f
.
spawn
(
"alice"
);
auto
a2
=
f
.
spawn
(
"bob"
);
send
(
a1
,
atom
(
"get_name"
));
receive
(
};
auto
a1
=
spawn
(
f
,
"alice"
);
auto
a2
=
spawn
(
f
,
"bob"
);
se
lf
->
se
nd
(
a1
,
atom
(
"get_name"
));
self
->
receive
(
on
(
atom
(
"name"
),
arg_match
)
>>
[
&
](
const
string
&
name
)
{
CPPA_CHECK_EQUAL
(
name
,
"alice"
);
}
);
send
(
a2
,
atom
(
"get_name"
));
receive
(
se
lf
->
se
nd
(
a2
,
atom
(
"get_name"
));
self
->
receive
(
on
(
atom
(
"name"
),
arg_match
)
>>
[
&
](
const
string
&
name
)
{
CPPA_CHECK_EQUAL
(
name
,
"bob"
);
}
);
send_exit
(
a1
,
exit_reason
::
user_shutdown
);
send_exit
(
a2
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
factory
::
event_based
([](
int
*
i
)
{
become
(
after
(
chrono
::
milliseconds
(
50
))
>>
[
=
]()
{
if
(
++
(
*
i
)
>=
5
)
self
->
quit
();
}
);
}).
spawn
();
self
->
send_exit
(
a1
,
exit_reason
::
user_shutdown
);
self
->
send_exit
(
a2
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
auto
res1
=
behavior_test
<
testee_actor
>
(
spawn
<
blocking_api
>
(
testee_actor
{}));
...
...
@@ -857,25 +771,25 @@ int main() {
// create some actors linked to one single actor
// and kill them all through killing the link
auto
legion
=
spawn
([]
{
auto
legion
=
spawn
([]
(
untyped_actor
*
self
)
{
CPPA_LOGF_INFO
(
"spawn 1, 000 actors"
);
for
(
int
i
=
0
;
i
<
1000
;
++
i
)
{
spawn
<
event_testee
,
linked
>
();
s
elf
->
s
pawn
<
event_testee
,
linked
>
();
}
become
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
());
self
->
become
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
());
});
send_exit
(
legion
,
exit_reason
::
user_shutdown
);
se
lf
->
se
nd_exit
(
legion
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
CPPA_CHECKPOINT
();
self
->
trap_exit
(
true
);
auto
ping_actor
=
spawn
<
monitored
+
blocking_api
>
(
ping
,
10
);
auto
pong_actor
=
spawn
<
monitored
+
blocking_api
>
(
pong
,
ping_actor
);
auto
ping_actor
=
s
elf
->
s
pawn
<
monitored
+
blocking_api
>
(
ping
,
10
);
auto
pong_actor
=
s
elf
->
s
pawn
<
monitored
+
blocking_api
>
(
pong
,
ping_actor
);
self
->
link_to
(
pong_actor
);
int
i
=
0
;
int
flags
=
0
;
delayed_send
(
self
,
chrono
::
seconds
(
1
),
atom
(
"FooBar"
));
self
->
delayed_send
(
self
,
chrono
::
seconds
(
1
),
atom
(
"FooBar"
));
// wait for DOWN and EXIT messages of pong
receive_for
(
i
,
4
)
(
self
->
receive_for
(
i
,
4
)
(
on
(
atom
(
"EXIT"
),
arg_match
)
>>
[
&
](
uint32_t
reason
)
{
CPPA_CHECK_EQUAL
(
exit_reason
::
user_shutdown
,
reason
);
CPPA_CHECK
(
self
->
last_sender
()
==
pong_actor
);
...
...
@@ -915,20 +829,17 @@ int main() {
spawn
<
high_priority_testee_class
,
priority_aware
>
();
await_all_actors_done
();
// don't try this at home, kids
send
(
self
,
atom
(
"check"
));
try
{
become
(
on
(
atom
(
"check"
))
>>
[]
{
CPPA_CHECKPOINT
();
self
->
quit
();
}
);
self
->
exec_behavior_stack
();
CPPA_FAILURE
(
"line "
<<
__LINE__
<<
" should be unreachable"
);
}
catch
(
actor_exited
&
)
{
CPPA_CHECKPOINT
();
}
self
->
send
(
self
,
atom
(
"check"
));
self
->
receive
(
on
(
atom
(
"check"
))
>>
[]
{
CPPA_CHECKPOINT
();
}
);
}
int
main
()
{
CPPA_TEST
(
test_spawn
);
test_spawn
();
shutdown
();
return
CPPA_TEST_RESULT
();
}
unit_testing/test_sync_send.cpp
View file @
c91bf3fc
...
...
@@ -7,7 +7,7 @@ using namespace cppa::placeholders;
struct
sync_mirror
:
sb_actor
<
sync_mirror
>
{
behavior
init_state
=
(
others
()
>>
[
]
{
return
self
->
last_dequeued
();
}
others
()
>>
[
=
]
{
return
last_dequeued
();
}
);
};
...
...
@@ -19,13 +19,13 @@ struct float_or_int : sb_actor<float_or_int> {
);
};
struct
popular_actor
:
event_bas
ed_actor
{
// popular actors have a buddy
actor
_ptr
m_buddy
;
popular_actor
(
const
actor
_ptr
&
buddy
)
:
m_buddy
(
buddy
)
{
}
inline
const
actor
_ptr
&
buddy
()
const
{
return
m_buddy
;
}
struct
popular_actor
:
untyp
ed_actor
{
// popular actors have a buddy
actor
m_buddy
;
popular_actor
(
const
actor
&
buddy
)
:
m_buddy
(
buddy
)
{
}
inline
const
actor
&
buddy
()
const
{
return
m_buddy
;
}
void
report_failure
()
{
send
(
buddy
(),
atom
(
"failure"
));
self
->
quit
();
quit
();
}
};
...
...
@@ -45,10 +45,10 @@ struct popular_actor : event_based_actor { // popular actors have a buddy
\******************************************************************************/
struct
A
:
popular_actor
{
A
(
const
actor
_ptr
&
buddy
)
:
popular_actor
(
buddy
)
{
}
void
init
()
{
become
(
on
(
atom
(
"go"
),
arg_match
)
>>
[
=
](
const
actor
_ptr
&
next
)
{
A
(
const
actor
&
buddy
)
:
popular_actor
(
buddy
)
{
}
behavior
make_behavior
()
override
{
return
(
on
(
atom
(
"go"
),
arg_match
)
>>
[
=
](
const
actor
&
next
)
{
CPPA_CHECKPOINT
();
sync_send
(
next
,
atom
(
"gogo"
)).
then
([
=
]
{
CPPA_CHECKPOINT
();
...
...
@@ -62,9 +62,9 @@ struct A : popular_actor {
};
struct
B
:
popular_actor
{
B
(
const
actor
_ptr
&
buddy
)
:
popular_actor
(
buddy
)
{
}
void
init
()
{
become
(
B
(
const
actor
&
buddy
)
:
popular_actor
(
buddy
)
{
}
behavior
make_behavior
()
override
{
return
(
others
()
>>
[
=
]
{
CPPA_CHECKPOINT
();
forward_to
(
buddy
());
...
...
@@ -77,7 +77,7 @@ struct B : popular_actor {
struct
C
:
sb_actor
<
C
>
{
behavior
init_state
=
(
on
(
atom
(
"gogo"
))
>>
[
=
]()
->
atom_value
{
self
->
quit
();
quit
();
return
atom
(
"gogogo"
);
}
);
...
...
@@ -100,8 +100,8 @@ struct C : sb_actor<C> {
\******************************************************************************/
struct
D
:
popular_actor
{
D
(
const
actor
_ptr
&
buddy
)
:
popular_actor
(
buddy
)
{
}
void
init
()
{
D
(
const
actor
&
buddy
)
:
popular_actor
(
buddy
)
{
}
behavior
make_behavior
()
override
{
become
(
others
()
>>
[
=
]
{
/*
...
...
@@ -136,13 +136,12 @@ struct D : popular_actor {
* X *
\******************************************************************************/
struct
server
:
event_bas
ed_actor
{
struct
server
:
untyp
ed_actor
{
void
init
()
{
behavior
make_behavior
()
override
{
auto
die
=
[
=
]
{
quit
(
exit_reason
::
user_shutdown
);
};
become
(
on
(
atom
(
"idle"
))
>>
[
=
]
{
auto
worker
=
last_sender
();
on
(
atom
(
"idle"
),
arg_match
)
>>
[
=
](
actor
worker
)
{
become
(
keep_behavior
,
on
(
atom
(
"request"
))
>>
[
=
]
{
...
...
@@ -160,33 +159,29 @@ struct server : event_based_actor {
};
int
main
()
{
CPPA_TEST
(
test_sync_send
);
self
->
on_sync_failure
([]
{
void
test_sync_send
()
{
scoped_actor
self
;
self
->
on_sync_failure
([
&
]
{
CPPA_FAILURE
(
"received: "
<<
to_string
(
self
->
last_dequeued
()));
});
s
pawn
<
monitored
+
blocking_api
>
([]
{
s
elf
->
spawn
<
monitored
+
blocking_api
>
([](
blocking_untyped_actor
*
self
)
{
CPPA_LOGC_TRACE
(
"NONE"
,
"main$sync_failure_test"
,
"id = "
<<
self
->
id
());
int
invocations
=
0
;
auto
foi
=
spawn
<
float_or_int
,
linked
>
();
send
(
foi
,
atom
(
"i"
));
receive
(
on_arg_match
>>
[](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
0
);
});
self
->
on_sync_failure
([]
{
auto
foi
=
s
elf
->
s
pawn
<
float_or_int
,
linked
>
();
se
lf
->
se
nd
(
foi
,
atom
(
"i"
));
self
->
receive
(
on_arg_match
>>
[](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
0
);
});
self
->
on_sync_failure
([
=
]
{
CPPA_FAILURE
(
"received: "
<<
to_string
(
self
->
last_dequeued
()));
});
s
ync_send
(
foi
,
atom
(
"i"
)).
then
(
s
elf
->
sync_send
(
foi
,
atom
(
"i"
)).
await
(
[
&
](
int
i
)
{
CPPA_CHECK_EQUAL
(
i
,
0
);
++
invocations
;
},
[
&
](
float
)
{
CPPA_UNEXPECTED_MSG
();
}
)
.
continue_with
([
&
]
{
sync_send
(
foi
,
atom
(
"f"
)).
then
(
[
&
](
int
)
{
CPPA_UNEXPECTED_MSG
();
},
[
&
](
float
f
)
{
CPPA_CHECK_EQUAL
(
f
,
0
);
++
invocations
;
}
);
});
self
->
exec_behavior_stack
();
);
self
->
sync_send
(
foi
,
atom
(
"f"
)).
await
(
[
&
](
int
)
{
CPPA_UNEXPECTED_MSG
();
},
[
&
](
float
f
)
{
CPPA_CHECK_EQUAL
(
f
,
0
);
++
invocations
;
}
);
//self->exec_behavior_stack();
CPPA_CHECK_EQUAL
(
invocations
,
2
);
CPPA_PRINT
(
"trigger sync failure"
);
// provoke invocation of self->handle_sync_failure()
...
...
@@ -195,7 +190,7 @@ int main() {
self
->
on_sync_failure
([
&
]
{
sync_failure_called
=
true
;
});
sync_send
(
foi
,
atom
(
"f"
)).
await
(
s
elf
->
s
ync_send
(
foi
,
atom
(
"f"
)).
await
(
on
<
int
>
()
>>
[
&
]
{
int_handler_called
=
true
;
}
...
...
@@ -204,22 +199,20 @@ int main() {
CPPA_CHECK_EQUAL
(
int_handler_called
,
false
);
self
->
quit
(
exit_reason
::
user_shutdown
);
});
receive
(
self
->
receive
(
on
(
atom
(
"DOWN"
),
exit_reason
::
user_shutdown
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
auto
mirror
=
spawn
<
sync_mirror
>
();
bool
continuation_called
=
false
;
sync_send
(
mirror
,
42
)
.
then
([](
int
value
)
{
CPPA_CHECK_EQUAL
(
value
,
42
);
})
.
continue_with
([
&
]
{
continuation_called
=
true
;
});
self
->
exec_behavior_stack
();
self
->
sync_send
(
mirror
,
42
)
.
await
([](
int
value
)
{
CPPA_CHECK_EQUAL
(
value
,
42
);
});
CPPA_CHECK_EQUAL
(
continuation_called
,
true
);
send_exit
(
mirror
,
exit_reason
::
user_shutdown
);
se
lf
->
se
nd_exit
(
mirror
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
CPPA_CHECKPOINT
();
auto
await_success_message
=
[
&
]
{
receive
(
self
->
receive
(
on
(
atom
(
"success"
))
>>
CPPA_CHECKPOINT_CB
(),
on
(
atom
(
"failure"
))
>>
CPPA_FAILURE_CB
(
"A didn't receive sync response"
),
on
(
atom
(
"DOWN"
),
arg_match
).
when
(
_x2
!=
exit_reason
::
normal
)
...
...
@@ -228,23 +221,23 @@ int main() {
}
);
};
se
nd
(
spawn
<
A
,
monitored
>
(
self
),
atom
(
"go"
),
spawn
<
B
>
(
spawn
<
C
>
()));
se
lf
->
send
(
self
->
spawn
<
A
,
monitored
>
(
self
),
atom
(
"go"
),
spawn
<
B
>
(
spawn
<
C
>
()));
await_success_message
();
CPPA_CHECKPOINT
();
await_all_actors_done
();
se
nd
(
spawn
<
A
,
monitored
>
(
self
),
atom
(
"go"
),
spawn
<
D
>
(
spawn
<
C
>
()));
se
lf
->
send
(
self
->
spawn
<
A
,
monitored
>
(
self
),
atom
(
"go"
),
spawn
<
D
>
(
spawn
<
C
>
()));
await_success_message
();
CPPA_CHECKPOINT
();
await_all_actors_done
();
CPPA_CHECKPOINT
();
timed_sync_send
(
self
,
std
::
chrono
::
milliseconds
(
50
),
atom
(
"NoWay"
)).
await
(
self
->
timed_sync_send
(
self
,
std
::
chrono
::
milliseconds
(
50
),
atom
(
"NoWay"
)).
await
(
on
(
atom
(
"TIMEOUT"
))
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
// we should have received two DOWN messages with normal exit reason
// plus 'NoWay'
int
i
=
0
;
receive_for
(
i
,
3
)
(
self
->
receive_for
(
i
,
3
)
(
on
(
atom
(
"DOWN"
),
exit_reason
::
normal
)
>>
CPPA_CHECKPOINT_CB
(),
on
(
atom
(
"NoWay"
))
>>
[]
{
CPPA_CHECKPOINT
();
...
...
@@ -256,7 +249,7 @@ int main() {
);
CPPA_CHECKPOINT
();
// mailbox should be empty now
receive
(
self
->
receive
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
(),
after
(
std
::
chrono
::
seconds
(
0
))
>>
CPPA_CHECKPOINT_CB
()
);
...
...
@@ -266,28 +259,24 @@ int main() {
bool
timeout_occured
=
false
;
self
->
on_sync_timeout
([
&
]
{
timeout_occured
=
true
;
});
self
->
on_sync_failure
(
CPPA_UNEXPECTED_MSG_CB
());
timed_sync_send
(
c
,
std
::
chrono
::
milliseconds
(
500
),
atom
(
"HiThere"
))
.
then
(
CPPA_FAILURE_CB
(
"C replied to 'HiThere'!"
))
.
continue_with
(
CPPA_FAILURE_CB
(
"continuation erroneously invoked"
));
self
->
exec_behavior_stack
();
self
->
timed_sync_send
(
c
,
std
::
chrono
::
milliseconds
(
500
),
atom
(
"HiThere"
))
.
await
(
CPPA_FAILURE_CB
(
"C replied to 'HiThere'!"
));
CPPA_CHECK_EQUAL
(
timeout_occured
,
true
);
self
->
on_sync_failure
(
CPPA_UNEXPECTED_MSG_CB
());
sync_send
(
c
,
atom
(
"gogo"
)).
then
(
CPPA_CHECKPOINT_CB
())
.
continue_with
(
CPPA_CHECKPOINT_CB
());
self
->
exec_behavior_stack
();
send_exit
(
c
,
exit_reason
::
user_shutdown
);
self
->
sync_send
(
c
,
atom
(
"gogo"
)).
await
(
CPPA_CHECKPOINT_CB
());
self
->
send_exit
(
c
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
CPPA_CHECKPOINT
();
// test use case 3
s
pawn
<
monitored
+
blocking_api
>
([]
{
// client
auto
s
=
s
pawn
<
server
,
linked
>
();
// server
auto
w
=
s
pawn
<
linked
>
([]
{
// worker
become
(
on
(
atom
(
"request"
))
>>
[]{
return
atom
(
"response"
);
});
s
elf
->
spawn
<
monitored
+
blocking_api
>
([](
blocking_untyped_actor
*
self
)
{
// client
auto
s
=
s
elf
->
spawn
<
server
,
linked
>
();
// server
auto
w
=
s
elf
->
spawn
<
linked
>
([](
untyped_actor
*
self
)
{
// worker
self
->
become
(
on
(
atom
(
"request"
))
>>
[]{
return
atom
(
"response"
);
});
});
// first 'idle', then 'request'
send_as
(
w
,
s
,
atom
(
"idle"
));
sync_send
(
s
,
atom
(
"request"
)).
await
(
s
elf
->
s
ync_send
(
s
,
atom
(
"request"
)).
await
(
on
(
atom
(
"response"
))
>>
[
=
]
{
CPPA_CHECKPOINT
();
CPPA_CHECK_EQUAL
(
self
->
last_sender
(),
w
);
...
...
@@ -295,23 +284,28 @@ int main() {
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
// first 'request', then 'idle'
auto
handle
=
sync_send
(
s
,
atom
(
"request"
));
auto
handle
=
s
elf
->
s
ync_send
(
s
,
atom
(
"request"
));
send_as
(
w
,
s
,
atom
(
"idle"
));
receive_response
(
handle
)
(
self
->
receive_response
(
handle
)
(
on
(
atom
(
"response"
))
>>
[
=
]
{
CPPA_CHECKPOINT
();
CPPA_CHECK_EQUAL
(
self
->
last_sender
(),
w
);
},
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
send
(
s
,
"Ever danced with the devil in the pale moonlight?"
);
se
lf
->
se
nd
(
s
,
"Ever danced with the devil in the pale moonlight?"
);
// response: {'EXIT', exit_reason::user_shutdown}
receive_loop
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
());
self
->
receive_loop
(
others
()
>>
CPPA_UNEXPECTED_MSG_CB
());
});
receive
(
self
->
receive
(
on
(
atom
(
"DOWN"
),
exit_reason
::
user_shutdown
)
>>
CPPA_CHECKPOINT_CB
(),
others
()
>>
CPPA_UNEXPECTED_MSG_CB
()
);
}
int
main
()
{
CPPA_TEST
(
test_sync_send
);
test_sync_send
();
await_all_actors_done
();
CPPA_CHECKPOINT
();
shutdown
();
...
...
unit_testing/test_tuple.cpp
View file @
c91bf3fc
...
...
@@ -87,9 +87,9 @@ optional<int> str2int(const std::string& str) {
CPPA_FAILURE(#FunName " erroneously invoked"); \
} else { CPPA_CHECKPOINT(); } static_cast<void>(42)
struct
dummy_receiver
:
event_bas
ed_actor
{
void
init
()
{
become
(
struct
dummy_receiver
:
untyp
ed_actor
{
behavior
make_behavior
()
override
{
return
(
on_arg_match
>>
[
=
](
expensive_copy_struct
&
ecs
)
->
expensive_copy_struct
{
ecs
.
value
=
42
;
quit
();
...
...
@@ -425,8 +425,9 @@ void check_move_ops() {
check_move_optional
();
CPPA_PRINT
(
__func__
);
CPPA_CHECK_EQUAL
(
s_expensive_copies
.
load
(),
0
);
send
(
spawn
<
dummy_receiver
>
(),
expensive_copy_struct
());
receive
(
scoped_actor
self
;
self
->
send
(
spawn
<
dummy_receiver
>
(),
expensive_copy_struct
());
self
->
receive
(
on_arg_match
>>
[
&
](
expensive_copy_struct
&
ecs
)
{
CPPA_CHECK_EQUAL
(
42
,
ecs
.
value
);
}
...
...
unit_testing/test_typed_spawn.cpp
View file @
c91bf3fc
...
...
@@ -41,6 +41,7 @@ bool operator==(const my_request& lhs, const my_request& rhs) {
return
lhs
.
a
==
rhs
.
a
&&
lhs
.
b
==
rhs
.
b
;
}
/*
typed_actor_ptr<replies_to<my_request>::with<bool>>
spawn_typed_server() {
return spawn_typed(
...
...
@@ -63,10 +64,11 @@ class typed_testee : public typed_actor<replies_to<my_request>::with<bool>> {
}
};
*/
int
main
()
{
CPPA_TEST
(
test_typed_spawn
);
/*
announce<my_request>(&my_request::a, &my_request::b);
auto sptr = spawn_typed_server();
sync_send(sptr, my_request{2, 2}).await(
...
...
@@ -176,5 +178,6 @@ int main() {
await_all_actors_done();
CPPA_CHECKPOINT();
shutdown();
*/
return
CPPA_TEST_RESULT
();
}
unit_testing/test_uniform_type.cpp
View file @
c91bf3fc
...
...
@@ -134,7 +134,7 @@ int main() {
std
::
string
,
std
::
u16string
,
std
::
u32string
,
float
,
double
,
atom_value
,
any_tuple
,
message_header
,
actor
_ptr
,
group_ptr
,
actor
,
group_ptr
,
channel
,
node_id_ptr
>::
arr
;
...
...
@@ -157,7 +157,7 @@ int main() {
uniform_typeid
<
atom_value
>
(),
uniform_typeid
<
any_tuple
>
(),
uniform_typeid
<
message_header
>
(),
uniform_typeid
<
actor
_ptr
>
(),
uniform_typeid
<
actor
>
(),
uniform_typeid
<
group_ptr
>
(),
uniform_typeid
<
channel
>
(),
uniform_typeid
<
node_id_ptr
>
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment