Commit 635412a2 authored by Matthias Vallentin's avatar Matthias Vallentin

Merge remote-tracking branch 'origin/unstable' into topic/libprocess

Conflicts:
	benchmarks/Makefile.am
parents 1a2d7619 823b722f
html/
.DS_Store
*.o
*.dylib
test
*.png
*.beam
*.class
*.dat
*.dump
*.dylib
*.ii
*.s
*.tmp
*.la
*.lo
*.dump
*.beam
*.class
benchmarks/mailbox_performance
benchmarks/actor_creation
benchmarks/mixed_case
benchmarks/matching
theron_mailbox_performance
.libs/
*.o
*.png
*.s
*.tmp
.DS_Store
.deps/
libcppa.pc
.libs/
4threads
8threads
INSTALL
Makefile
Makefile.in
a.out*
aclocal.m4
autom4te.cache/
benchmarks/actor_creation
benchmarks/distributed
benchmarks/mailbox_performance
benchmarks/matching
benchmarks/mixed_case
blob/cppatest
callgrind.out*
config.*
configure
cppa.creator.user
depcomp
examples/announce_example_1
examples/announce_example_2
examples/announce_example_3
examples/announce_example_4
examples/announce_example_5
examples/dancing_kirby
examples/dining_philosophers
examples/hello_world_example
examples/math_actor_example
gen_server/parallel_send
gen_server/sequential_send
gen_server/test.dSYM/
depcomp
html/
install-sh
libcppa.Makefile
libcppa.pc
libcppa.so*
libtool
ltmain.sh
missing
unit_testing/Makefile.in
unit_testing/unit_tests
unit_testing/.deps/
config.*
configure
INSTALL
m4/libtool.m4
m4/lt*.m4
a.out*
missing
queue_test
cppa.creator.user
8threads
4threads
libcppa.Makefile
test
theron_mailbox_performance
unit_testing/.deps/
unit_testing/Makefile
unit_testing/Makefile.in
unit_testing/unit_tests
variadic_templates_test
variadic_templates_test.dSYM/
Makefile
unit_testing/Makefile
libcppa.so*
blob/cppatest
callgrind.out*
examples/announce_example_1
examples/announce_example_2
examples/announce_example_3
examples/announce_example_4
examples/announce_example_5
examples/hello_world_example
examples/math_actor_example
examples/dining_philosophers
examples/dancing_kirby
......@@ -4,7 +4,6 @@ lib_LTLIBRARIES = libcppa.la
libcppa_la_SOURCES = \
src/abstract_event_based_actor.cpp \
src/abstract_scheduled_actor.cpp \
src/abstract_tuple.cpp \
src/actor.cpp \
src/actor_count.cpp \
......@@ -40,12 +39,12 @@ libcppa_la_SOURCES = \
src/partial_function.cpp \
src/pattern.cpp \
src/post_office.cpp \
src/post_office_msg.cpp \
src/primitive_variant.cpp \
src/process_information.cpp \
src/receive.cpp \
src/ripemd_160.cpp \
src/scheduled_actor.cpp \
src/scheduled_actor_dummy.cpp \
src/scheduler.cpp \
src/self.cpp \
src/serializer.cpp \
......@@ -102,6 +101,7 @@ nobase_library_include_HEADERS = \
cppa/detail/demangle.hpp \
cppa/detail/disablable_delete.hpp \
cppa/detail/empty_tuple.hpp \
cppa/detail/filter_result.hpp \
cppa/detail/get_behavior.hpp \
cppa/detail/group_manager.hpp \
cppa/detail/implicit_conversions.hpp \
......@@ -112,18 +112,20 @@ nobase_library_include_HEADERS = \
cppa/detail/matches.hpp \
cppa/detail/mock_scheduler.hpp \
cppa/detail/native_socket.hpp \
cppa/detail/nestable_receive_actor.hpp \
cppa/detail/network_manager.hpp \
cppa/detail/object_array.hpp \
cppa/detail/object_impl.hpp \
cppa/detail/pair_member.hpp \
cppa/detail/post_office.hpp \
cppa/detail/post_office_msg.hpp \
cppa/detail/primitive_member.hpp \
cppa/detail/projection.hpp \
cppa/detail/pseudo_tuple.hpp \
cppa/detail/ptype_to_type.hpp \
cppa/detail/receive_loop_helper.hpp \
cppa/detail/recursive_queue_node.hpp \
cppa/detail/ref_counted_impl.hpp \
cppa/detail/scheduled_actor_dummy.hpp \
cppa/detail/serialize_tuple.hpp \
cppa/detail/singleton_manager.hpp \
cppa/detail/swap_bytes.hpp \
......
......@@ -104,14 +104,12 @@ object ActorCreation {
if (args(0) == "threaded") {
val newMax = (1 << n) + 100
System.setProperty("actors.maxPoolSize", newMax.toString)
//actor {
(new ThreadedTestee(self)).start ! Spread(n)
receive {
case Result(v) =>
if (v != (1 << n))
Console.println("ERROR: expected " + (1 << n) + ", received " + v)
}
//}
(new ThreadedTestee(self)).start ! Spread(n)
receive {
case Result(v) =>
if (v != (1 << n))
Console.println("ERROR: expected " + (1 << n) + ", received " + v)
}
}
else if (args(0) == "threadless") {
actor {
......
This diff is collapsed.
......@@ -3,13 +3,14 @@ ACLOCAL_AMFLAGS = -I ../m4
AM_CXXFLAGS = -I../ --std=c++0x -pedantic -Wall -Wextra
noinst_PROGRAMS = actor_creation mailbox_performance mixed_case_libcppa mixed_case_libprocess matching
noinst_PROGRAMS = actor_creation mailbox_performance mixed_case_libcppa mixed_case_libprocess matching distributed
actor_creation_SOURCES = actor_creation.cpp
mailbox_performance_SOURCES = mailbox_performance.cpp
mixed_case_libcppa_SOURCES = mixed_case_libcppa.cpp
mixed_case_libprocess_SOURCES = mixed_case_libprocess.cpp
matching_SOURCES = matching.cpp
distributed_SOURCES = distributed.cpp
EXAMPLES_LIBS = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB)
......@@ -18,3 +19,4 @@ mailbox_performance_LDADD = $(EXAMPLES_LIBS)
mixed_case_libcppa_LDADD = $(EXAMPLES_LIBS)
mixed_case_libprocess_LDADD = -L../.libs/ -lglog $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB)
matching_LDADD = $(EXAMPLES_LIBS)
distributed_LDADD = $(EXAMPLES_LIBS)
......@@ -44,32 +44,23 @@ using std::uint32_t;
using namespace cppa;
struct testee : fsm_actor<testee>
{
struct testee : fsm_actor<testee> {
actor_ptr parent;
behavior init_state;
testee(const actor_ptr& pptr) : parent(pptr)
{
init_state =
(
on(atom("spread"), 0) >> [=]()
{
testee(const actor_ptr& pptr) : parent(pptr) {
init_state = (
on(atom("spread"), 0) >> [=]() {
send(parent, atom("result"), (uint32_t) 1);
become_void();
},
on<atom("spread"), int>() >> [=](int x)
{
on<atom("spread"), int>() >> [=](int x) {
any_tuple msg = make_cow_tuple(atom("spread"), x - 1);
spawn(new testee(this)) << msg;
spawn(new testee(this)) << msg;
become
(
on<atom("result"), uint32_t>() >> [=](uint32_t r1)
{
become
(
on<atom("result"), uint32_t>() >> [=](uint32_t r2)
{
become (
on<atom("result"), uint32_t>() >> [=](uint32_t r1) {
become (
on<atom("result"), uint32_t>() >> [=](uint32_t r2) {
send(parent, atom("result"), r1 + r2);
become_void();
}
......@@ -81,27 +72,19 @@ struct testee : fsm_actor<testee>
}
};
void stacked_testee(actor_ptr parent)
{
receive
(
on(atom("spread"), 0) >> [&]()
{
void stacked_testee(actor_ptr parent) {
receive (
on(atom("spread"), 0) >> [&]() {
send(parent, atom("result"), (uint32_t) 1);
},
on<atom("spread"), int>() >> [&](int x)
{
on<atom("spread"), int>() >> [&](int x) {
any_tuple msg = make_cow_tuple(atom("spread"), x-1);
spawn(stacked_testee, self) << msg;
spawn(stacked_testee, self) << msg;
receive
(
on<atom("result"), uint32_t>() >> [&](uint32_t v1)
{
receive
(
on<atom("result"),uint32_t>() >> [&](uint32_t v2)
{
receive (
on<atom("result"), uint32_t>() >> [&](uint32_t v1) {
receive (
on<atom("result"),uint32_t>() >> [&](uint32_t v2) {
send(parent, atom("result"), v1 + v2);
}
);
......@@ -111,45 +94,38 @@ void stacked_testee(actor_ptr parent)
);
}
void usage()
{
void usage() {
cout << "usage: actor_creation (stacked|event-based) POW" << endl
<< " creates 2^POW actors" << endl
<< endl;
}
int main(int argc, char** argv)
{
if (argc == 3)
{
int main(int argc, char** argv) {
if (argc == 3) {
int num = rd<int>(argv[2]);
if (strcmp(argv[1], "stacked") == 0)
{
if (strcmp(argv[1], "stacked") == 0) {
send(spawn(stacked_testee, self), atom("spread"), num);
}
else if (strcmp(argv[1], "event-based") == 0)
{
else if (strcmp(argv[1], "event-based") == 0) {
send(spawn(new testee(self)), atom("spread"), num);
}
else
{
else {
usage();
return 1;
}
receive
(
on<atom("result"),uint32_t>() >> [=](uint32_t value)
{
receive (
on<atom("result"),uint32_t>() >> [=](uint32_t value) {
//cout << "value = " << value << endl
// << "expected => 2^" << num << " = "
// << (1 << num) << endl;
assert(value == (((uint32_t) 1) << num));
if (value != (((uint32_t) 1) << num)) {
cerr << "ERROR: received wrong result!\n";
}
}
);
await_all_others_done();
}
else
{
else {
usage();
return 1;
}
......
pongServer {
akka {
loglevel = ERROR
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
untrusted-mode = on
remote-daemon-ack-timeout = 300s
netty {
backoff-timeout = 0ms
connection-timeout = 300s
hostname = "mobi10"
port = 2244
}
}
}
}
This diff is collapsed.
-module(distributed).
-export([start/1, ping_loop/2]).
ping_loop(Parent, Pong) ->
receive
{pong, 0} -> Parent ! done;
{pong, X} ->
Pong ! {ping, self(), X - 1},
ping_loop(Parent, Pong);
{kickoff, X} ->
Pong ! {ping, self(), X},
ping_loop(Parent, Pong);
_ -> ping_loop(Parent, Pong)
end.
server_loop(Pongs) ->
receive
{ping, Pid, X} ->
Pid ! {pong, X},
server_loop(Pongs);
{add_pong, Pid, Node} ->
case lists:any(fun({N, _}) -> N == Node end, Pongs) of
true ->
Pid ! {ok, cached},
server_loop(Pongs);
false ->
case rpc:call(Node, erlang, whereis, [pong]) of
{badrpc, Reason} ->
Pid ! {error, Reason},
server_loop(Pongs);
undefined ->
Pid ! {error, 'pong is undefined'},
server_loop(Pongs);
Pong ->
Pid ! {ok, added},
server_loop(Pongs ++ [{Node, Pong}])
end
end;
{purge} -> server_loop([]);
{get_pongs, Pid} ->
Pid ! Pongs,
server_loop(Pongs);
{kickoff, Pid, NumPings} ->
lists:foreach(fun({_, P}) -> spawn(distributed, ping_loop, [Pid, P]) ! {kickoff, NumPings} end, Pongs),
server_loop(Pongs);
_ -> server_loop(Pongs)
end.
server_mode() ->
register(pong, self()),
server_loop([]).
add_pong_fun(_, _, []) -> true;
add_pong_fun(Pong, Node, [Node|T]) -> add_pong_fun(Pong, Node, T);
add_pong_fun(Pong, Node, [H|T]) ->
Pong ! {add_pong, self(), H},
receive
{ok, _} -> add_pong_fun(Pong, Node, T);
{error, Reason} -> error(Reason)
after 10000 -> error(timeout)
end.
client_mode_receive_done_msgs(0) -> true;
client_mode_receive_done_msgs(Left) ->
receive done -> client_mode_receive_done_msgs(Left - 1) end.
% receive a {done} message for each node
client_mode([], [], [], _) -> error("no node, no fun");
client_mode([], [], Nodes, _) ->
client_mode_receive_done_msgs(length(Nodes) * (length(Nodes) - 1));
% send kickoff messages
client_mode([Pong|Pongs], [], Nodes, NumPings) ->
Pong ! {kickoff, self(), NumPings},
client_mode(Pongs, [], Nodes, NumPings);
client_mode(Pongs, [H|T], Nodes, NumPings) ->
case rpc:call(H, erlang, whereis, [pong]) of
{badrpc, Reason} ->
io:format("cannot connect to ~s~n", [atom_to_list(H)]),
error(Reason);
undefined ->
io:format("no 'pong' defined on node ~s~n", [atom_to_list(H)]);
P ->
add_pong_fun(P, H, Nodes),
client_mode(Pongs ++ [P], T, Nodes, NumPings)
end.
run(_, undefined, []) -> error("NumPings is undefined");
run(Hosts, _, []) when length(Hosts) < 2 -> error("less than two nodes specified");
run(Hosts, NumPings, []) -> client_mode([], Hosts, Hosts, NumPings);
run(Hosts, NumPings, [H|T]) ->
Arg = atom_to_list(H),
case lists:prefix("num_pings=", Arg) of
true when NumPings /= undefined -> error("NumPings already set");
true -> run(Hosts, list_to_integer(lists:sublist(Arg, 11, length(Arg))), T);
false -> run(Hosts ++ [H], NumPings, T)
end.
start(X) ->
case X of
['mode=server'|[]] -> server_mode();
['mode=server'|_] -> io:format("too much arguments~n", []);
['mode=benchmark'|T] -> run([], undefined, T);
_ -> io:format("invalid arguments~n", [])
end.
#!/bin/bash
echo "erl -noshell -noinput +P 20000000 -s $@ -s init stop" | ./exec.sh
echo "erl -noshell -noinput +P 20000000 -setcookie abc123 -sname benchmark -s $@ -s init stop" | ./exec.sh
......@@ -45,19 +45,14 @@ using std::int64_t;
using namespace cppa;
struct fsm_receiver : fsm_actor<fsm_receiver>
{
struct fsm_receiver : fsm_actor<fsm_receiver> {
int64_t m_value;
behavior init_state;
fsm_receiver(int64_t max) : m_value(0)
{
init_state =
(
on(atom("msg")) >> [=]()
{
fsm_receiver(int64_t max) : m_value(0) {
init_state = (
on(atom("msg")) >> [=]() {
++m_value;
if (m_value == max)
{
if (m_value == max) {
become_void();
}
}
......@@ -65,63 +60,49 @@ struct fsm_receiver : fsm_actor<fsm_receiver>
}
};
void receiver(int64_t max)
{
void receiver(int64_t max) {
int64_t value;
receive_while(gref(value) < max)
//receive_while([&]() { return value < max; })
(
on(atom("msg")) >> [&]()
{
receive_while(gref(value) < max) (
on(atom("msg")) >> [&]() {
++value;
}
);
}
void sender(actor_ptr whom, int64_t count)
{
void sender(actor_ptr whom, int64_t count) {
any_tuple msg = make_cow_tuple(atom("msg"));
for (int64_t i = 0; i < count; ++i)
{
for (int64_t i = 0; i < count; ++i) {
whom->enqueue(nullptr, msg);
}
}
void usage()
{
void usage() {
cout << "usage: mailbox_performance "
"(stacked|event-based) (sending threads) (msg per thread)" << endl
<< endl;
}
int main(int argc, char** argv)
{
if (argc == 4)
{
int main(int argc, char** argv) {
if (argc == 4) {
int64_t num_sender = rd<int64_t>(argv[2]);
int64_t num_msgs = rd<int64_t>(argv[3]);
actor_ptr testee;
if (strcmp(argv[1], "stacked") == 0)
{
if (strcmp(argv[1], "stacked") == 0) {
testee = spawn(receiver, num_sender * num_msgs);
}
else if (strcmp(argv[1], "event-based") == 0)
{
else if (strcmp(argv[1], "event-based") == 0) {
testee = spawn(new fsm_receiver(num_sender * num_msgs));
}
else
{
else {
usage();
return 1;
}
for (int64_t i = 0; i < num_sender; ++i)
{
for (int64_t i = 0; i < num_sender; ++i) {
detail::thread(sender, testee, num_msgs).detach();
}
await_all_others_done();
}
else
{
else {
usage();
return 1;
}
......
......@@ -53,12 +53,10 @@ using std::int64_t;
using namespace cppa;
template<typename T>
T rd(char const* cstr)
{
T rd(char const* cstr) {
char* endptr = nullptr;
T result = static_cast<T>(strtol(cstr, &endptr, 10));
if (endptr == nullptr || *endptr != '\0')
{
if (endptr == nullptr || *endptr != '\0') {
std::string errstr;
errstr += "\"";
errstr += cstr;
......@@ -68,29 +66,71 @@ T rd(char const* cstr)
return result;
}
int main(int argc, char** argv)
{
void usage() {
cerr << "usage: matching (cow_tuple|object_array) {NUM_LOOPS}" << endl;
exit(1);
}
int main(int argc, char** argv) {
announce<list<int>>();
if (argc != 2)
{
cerr << "usage: matching {NUM_LOOPS}" << endl;
return 1;
if (argc != 3) usage();
auto num_loops = rd<int64_t>(argv[2]);
any_tuple m1;
any_tuple m2;
any_tuple m3;
any_tuple m4;
any_tuple m5;
any_tuple m6;
if (strcmp(argv[1], "cow_tuple") == 0) {
m1 = make_cow_tuple(atom("msg1"), 0);
m2 = make_cow_tuple(atom("msg2"), 0.0);
m3 = make_cow_tuple(atom("msg3"), list<int>{0});
m4 = make_cow_tuple(atom("msg4"), 0, "0");
m5 = make_cow_tuple(atom("msg5"), 0, 0, 0);
m6 = make_cow_tuple(atom("msg6"), 0, 0.0, "0");
}
else if (strcmp(argv[1], "object_array") == 0) {
auto m1o = new detail::object_array;
m1o->push_back(object::from(atom("msg1")));
m1o->push_back(object::from(0));
m1 = any_tuple{m1o};
auto m2o = new detail::object_array;
m2o->push_back(object::from(atom("msg2")));
m2o->push_back(object::from(0.0));
m2 = any_tuple{m2o};
auto m3o = new detail::object_array;
m3o->push_back(object::from(atom("msg3")));
m3o->push_back(object::from(list<int>{0}));
m3 = any_tuple{m3o};
auto m4o = new detail::object_array;
m4o->push_back(object::from(atom("msg4")));
m4o->push_back(object::from(0));
m4o->push_back(object::from(std::string("0")));
m4 = any_tuple{m4o};
auto m5o = new detail::object_array;
m5o->push_back(object::from(atom("msg5")));
m5o->push_back(object::from(0));
m5o->push_back(object::from(0));
m5o->push_back(object::from(0));
m5 = any_tuple{m5o};
auto m6o = new detail::object_array;
m6o->push_back(object::from(atom("msg6")));
m6o->push_back(object::from(0));
m6o->push_back(object::from(0.0));
m6o->push_back(object::from(std::string("0")));
m6 = any_tuple{m6o};
}
else {
usage();
}
auto num_loops = rd<int64_t>(argv[1]);
any_tuple m1 = make_cow_tuple(atom("msg1"), 0);
any_tuple m2 = make_cow_tuple(atom("msg2"), 0.0);
any_tuple m3 = cppa::make_cow_tuple(atom("msg3"), list<int>{0});
any_tuple m4 = make_cow_tuple(atom("msg4"), 0, "0");
any_tuple m5 = make_cow_tuple(atom("msg5"), 0, 0, 0);
any_tuple m6 = make_cow_tuple(atom("msg6"), 0, 0.0, "0");
int64_t m1matched = 0;
int64_t m2matched = 0;
int64_t m3matched = 0;
int64_t m4matched = 0;
int64_t m5matched = 0;
int64_t m6matched = 0;
auto part_fun =
(
auto part_fun = (
on<atom("msg1"), int>() >> [&]() { ++m1matched; },
on<atom("msg2"), double>() >> [&]() { ++m2matched; },
on<atom("msg3"), list<int> >() >> [&]() { ++m3matched; },
......@@ -98,8 +138,7 @@ int main(int argc, char** argv)
on<atom("msg5"), int, int, int>() >> [&]() { ++m5matched; },
on<atom("msg6"), int, double, string>() >> [&]() { ++m6matched; }
);
for (int64_t i = 0; i < num_loops; ++i)
{
for (int64_t i = 0; i < num_loops; ++i) {
part_fun(m1);
part_fun(m2);
part_fun(m3);
......@@ -107,4 +146,10 @@ int main(int argc, char** argv)
part_fun(m5);
part_fun(m6);
}
assert(m1matched == num_loops);
assert(m2matched == num_loops);
assert(m3matched == num_loops);
assert(m4matched == num_loops);
assert(m5matched == num_loops);
assert(m6matched == num_loops);
}
This diff is collapsed.
#!/bin/bash
if [[ $# -eq 0 ]] ; then
for i in *.scala; do
echo "scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar \"$i\""
scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar "$i"
echo "compile \"$i\""
scalac -unchecked -cp $AKKA_LIBS "$i"
done
elif [[ $# -eq 1 ]] ; then
echo "scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar \"$1.scala\""
scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar "$1.scala"
echo "compile \"$1.scala\""
scalac -unchecked -cp $AKKA_LIBS "$1.scala"
fi
echo done
#!/bin/bash
#export JAVA_OPTS="-Xmx1024"
#echo "scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh
echo "scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh
JARS=/home/neverlord/akka-microkernel-1.2/lib/akka/activation-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-tests-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-amqp-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-beanstalk-mailbox-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-camel-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-camel-typed-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-dispatcher-extras-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-file-mailbox-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-http-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-kernel-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-mailboxes-common-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-redis-mailbox-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-remote-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-scalaz-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-slf4j-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-spring-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-stm-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-testkit-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-typed-actor-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/amqp-client-2.5.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/aopalliance-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/asm-3.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/aspectwerkz-2.2.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/beanstalk_client-1.4.5.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/camel-core-2.7.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-cli-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-codec-1.4.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-io-2.0.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-logging-1.1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-management-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-pool-1.5.5.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/dispatch-json_2.9.0-0.8.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/guice-all-2.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/h2-lzf-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/hawtdispatch-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/hawtdispatch-scala-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jackson-core-asl-1.8.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jackson-mapper-asl-1.8.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jaxb-api-2.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jaxb-impl-2.1.12.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-core-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-json-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-scala-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-server-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jettison-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-continuation-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-http-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-io-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-security-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-server-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-servlet-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-util-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-xml-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jsr250-api-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jsr311-api-1.1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jsr311-api-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/junit-4.8.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/log4j-1.2.16.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/multiverse-alpha-0.6.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/netty-3.2.5.Final.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/objenesis-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/protobuf-java-2.4.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/redisclient_2.9.0-2.3.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/scalaz-core_2.9.0-1-6.0.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/servlet-api-2.5.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/sjson_2.9.0-0.11.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/slf4j-api-1.5.8.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/slf4j-api-1.6.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/slf4j-log4j12-1.5.8.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-aop-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-asm-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-beans-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-context-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-core-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-expression-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/stax-api-1.0.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/stax-api-1.0-2.jar
echo "scala -cp $JARS $@" | ./exec.sh
......@@ -18,41 +18,33 @@ struct result { uint32_t value; };
using namespace Theron;
struct testee : Actor
{
struct testee : Actor {
Address m_parent;
bool m_first_result_received;
uint32_t m_first_result;
std::vector<ActorRef> m_children;
void spread_handler(const spread& arg, const Address)
{
if (arg.value == 0)
{
void spread_handler(const spread& arg, const Address) {
if (arg.value == 0) {
Send(result{1}, m_parent);
}
else
{
else {
spread msg = {arg.value-1};
Parameters params = {GetAddress()};
for (int i = 0; i < 2; ++i)
{
for (int i = 0; i < 2; ++i) {
m_children.push_back(GetFramework().CreateActor<testee>(params));
m_children.back().Push(msg, GetAddress());
}
}
}
void result_handler(const result& arg, const Address)
{
if (!m_first_result_received)
{
void result_handler(const result& arg, const Address) {
if (!m_first_result_received) {
m_first_result_received = true;
m_first_result = arg.value;
}
else
{
else {
m_children.clear();
Send(result{m_first_result + arg.value}, m_parent);
}
......@@ -60,25 +52,21 @@ struct testee : Actor
typedef struct { Address arg0; } Parameters;
testee(const Parameters& p) : m_parent(p.arg0), m_first_result_received(false)
{
testee(const Parameters& p) : m_parent(p.arg0), m_first_result_received(false) {
RegisterHandler(this, &testee::spread_handler);
RegisterHandler(this, &testee::result_handler);
}
};
void usage()
{
void usage() {
cout << "usage: theron_actor_creation _ POW" << endl
<< " creates 2^POW actors" << endl
<< endl;
}
int main(int argc, char** argv)
{
if (argc != 3)
{
int main(int argc, char** argv) {
if (argc != 3) {
usage();
return 1;
}
......
......@@ -18,47 +18,39 @@ using namespace Theron;
int64_t t_max = 0;
struct receiver : Actor
{
struct receiver : Actor {
int64_t m_num;
void handler(const int64_t&, const Address from)
{
void handler(const int64_t&, const Address from) {
if (++m_num == t_max)
Send(t_max, from);
}
receiver() : m_num(0)
{
receiver() : m_num(0) {
RegisterHandler(this, &receiver::handler);
}
};
void send_sender(Framework& f, ActorRef ref, Address waiter, int64_t num)
{
void send_sender(Framework& f, ActorRef ref, Address waiter, int64_t num) {
auto addr = ref.GetAddress();
int64_t msg;
for (int64_t i = 0; i < num; ++i) f.Send(msg, waiter, addr);
}
void push_sender(Framework& f, ActorRef ref, Address waiter, int64_t num)
{
void push_sender(Framework& f, ActorRef ref, Address waiter, int64_t num) {
int64_t msg;
for (int64_t i = 0; i < num; ++i) ref.Push(msg, waiter);
}
void usage()
{
void usage() {
cout << "usage ('push'|'send') (num_threads) (num_messages)" << endl;
exit(1);
}
int main(int argc, char** argv)
{
if (argc != 4)
{
int main(int argc, char** argv) {
if (argc != 4) {
usage();
}
enum { invalid_impl, push_impl, send_impl } impl = invalid_impl;
......@@ -74,8 +66,7 @@ int main(int argc, char** argv)
ActorRef aref(framework.CreateActor<receiver>());
std::list<std::thread> threads;
auto impl_fun = (impl == push_impl) ? send_sender : push_sender;
for (int64_t i = 0; i < num_sender; ++i)
{
for (int64_t i = 0; i < num_sender; ++i) {
threads.push_back(std::thread(impl_fun, std::ref(framework), aref, receiverAddr, num_msgs));
}
r.Wait();
......
......@@ -30,40 +30,32 @@ struct master_done { };
struct worker_done { };
struct worker : Actor
{
void handle_calc(const calc_msg& msg, Address from)
{
struct worker : Actor {
void handle_calc(const calc_msg& msg, Address from) {
factorize(msg.value);
}
void handle_master_done(const master_done&, Address from)
{
void handle_master_done(const master_done&, Address from) {
Send(worker_done(), from);
}
worker()
{
worker() {
RegisterHandler(this, &worker::handle_calc);
RegisterHandler(this, &worker::handle_master_done);
}
};
struct chain_link : Actor
{
struct chain_link : Actor {
Address next;
void handle_token(const token_msg& msg, Address)
{
void handle_token(const token_msg& msg, Address) {
Send(msg, next);
}
typedef struct { Address next; } Parameters;
chain_link(const Parameters& p) : next(p.next)
{
chain_link(const Parameters& p) : next(p.next) {
RegisterHandler(this, &chain_link::handle_token);
}
};
struct master : Actor
{
struct master : Actor {
Address mc;
int iteration;
int max_iterations;
......@@ -72,20 +64,17 @@ struct master : Actor
int ring_size;
int initial_token_value;
std::vector<ActorRef> m_children;
void new_ring()
{
void new_ring() {
m_children.clear();
w.Push(calc_msg{s_task_n}, GetAddress());
next = GetAddress();
for (int i = 1; i < ring_size; ++i)
{
for (int i = 1; i < ring_size; ++i) {
m_children.push_back(GetFramework().CreateActor<chain_link>(chain_link::Parameters{next}));
next = m_children.back().GetAddress();
}
Send(token_msg{initial_token_value}, next);
}
void handle_init(const init_msg& msg, Address)
{
void handle_init(const init_msg& msg, Address) {
w = GetFramework().CreateActor<worker>();
iteration = 0;
ring_size = msg.ring_size;
......@@ -93,40 +82,32 @@ struct master : Actor
max_iterations = msg.iterations;
new_ring();
}
void handle_token(const token_msg& msg, Address)
{
if (msg.value == 0)
{
if (++iteration < max_iterations)
{
void handle_token(const token_msg& msg, Address) {
if (msg.value == 0) {
if (++iteration < max_iterations) {
new_ring();
}
else
{
else {
w.Push(master_done(), GetAddress());
}
}
else
{
else {
Send(token_msg{msg.value - 1}, next);
}
}
void handle_worker_done(const worker_done&, Address)
{
void handle_worker_done(const worker_done&, Address) {
Send(master_done(), mc);
w = ActorRef::Null();
}
typedef struct { Address mc; } Parameters;
master(const Parameters& p) : mc(p.mc), iteration(0)
{
master(const Parameters& p) : mc(p.mc), iteration(0) {
RegisterHandler(this, &master::handle_init);
RegisterHandler(this, &master::handle_token);
RegisterHandler(this, &master::handle_worker_done);
}
};
void usage()
{
void usage() {
cout << "usage: mailbox_performance "
"'send' (num rings) (ring size) "
"(initial token value) (repetitions)"
......@@ -135,8 +116,7 @@ void usage()
exit(1);
}
int main(int argc, char** argv)
{
int main(int argc, char** argv) {
if (argc != 6) usage();
if (strcmp("send", argv[1]) != 0) usage();
int num_rings = rd<int>(argv[2]);
......@@ -146,12 +126,10 @@ int main(int argc, char** argv)
Receiver r;
Framework framework(num_cores());
std::vector<ActorRef> masters;
for (int i = 0; i < num_rings; ++i)
{
for (int i = 0; i < num_rings; ++i) {
masters.push_back(framework.CreateActor<master>(master::Parameters{r.GetAddress()}));
}
for (ActorRef& m : masters)
{
for (ActorRef& m : masters) {
m.Push(init_msg{ring_size, inital_token_value, repetitions}, r.GetAddress());
}
for (int i = 0; i < num_rings; ++i) r.Wait();
......
......@@ -32,18 +32,35 @@
#define UTILITY_HPP
#include <vector>
#include <string>
#include <sstream>
#include <stdexcept>
#include <algorithm>
#include "boost/thread.hpp"
inline std::vector<std::string> split(std::string const& str, char delim) {
std::vector<std::string> result;
std::stringstream strs{str};
std::string tmp;
while (std::getline(strs, tmp, delim)) result.push_back(tmp);
return result;
}
inline std::string join(std::vector<std::string> const& vec,
std::string const& delim = "") {
if (vec.empty()) return "";
auto result = vec.front();
for (auto i = vec.begin() + 1; i != vec.end(); ++i) {
result += delim;
result += *i;
}
return result;
}
template<typename T>
T rd(char const* cstr)
{
T rd(char const* cstr) {
char* endptr = nullptr;
T result = static_cast<T>(strtol(cstr, &endptr, 10));
if (endptr == nullptr || *endptr != '\0')
{
if (endptr == nullptr || *endptr != '\0') {
std::string errstr;
errstr += "\"";
errstr += cstr;
......@@ -53,18 +70,10 @@ T rd(char const* cstr)
return result;
}
#ifdef __APPLE__
int num_cores()
{
return static_cast<int>(boost::thread::hardware_concurrency());
}
#else
int num_cores()
{
int num_cores() {
char cbuf[100];
FILE* cmd = popen("/bin/cat /proc/cpuinfo | /bin/grep processor | /usr/bin/wc -l", "r");
if (fgets(cbuf, 100, cmd) == 0)
{
if (fgets(cbuf, 100, cmd) == 0) {
throw std::runtime_error("cannot determine number of cores");
}
pclose(cmd);
......@@ -73,26 +82,20 @@ int num_cores()
*i = '\0';
return rd<int>(cbuf);
}
#endif
std::vector<uint64_t> factorize(uint64_t n)
{
std::vector<uint64_t> factorize(uint64_t n) {
std::vector<uint64_t> result;
if (n <= 3)
{
if (n <= 3) {
result.push_back(n);
return std::move(result);
}
uint64_t d = 2;
while(d < n)
{
if((n % d) == 0)
{
while(d < n) {
if((n % d) == 0) {
result.push_back(d);
n /= d;
}
else
{
else {
d = (d == 2) ? 3 : (d + 2);
}
}
......
......@@ -4,16 +4,13 @@
using std::cout;
using std::endl;
struct pseudo_worker
{
struct pseudo_worker {
int m_value;
pseudo_worker() : m_value(0) { }
void operator()()
{
for (;;)
{
void operator()() {
for (;;) {
++m_value;
cout << "value = " << m_value << endl;
cppa_fibre_yield(0);
......@@ -21,22 +18,18 @@ struct pseudo_worker
}
};
void coroutine()
{
auto pw = reinterpret_cast<pseudo_worker*>(cppa_fibre_init_switch_arg());
(*pw)();
void coroutine() {
auto pw = reinterpret_cast<pseudo_worker*>(cppa_fibre_init_switch_arg()); (*pw)();
}
int main()
{
int main() {
pseudo_worker pw;
cppa_fibre fself;
cppa_fibre fcoroutine;
cppa_fibre_ctor(&fself);
cppa_fibre_ctor2(&fcoroutine, coroutine, &pw);
cppa_fibre_initialize(&fcoroutine);
for (int i = 1; i < 11; ++i)
{
for (int i = 1; i < 11; ++i) {
cout << "i = " << i << endl;
cppa_fibre_switch(&fself, &fcoroutine);
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -47,11 +47,9 @@ namespace cppa {
/**
* @brief Base class for all event-based actor implementations.
*/
class abstract_event_based_actor : public detail::abstract_scheduled_actor
{
class abstract_event_based_actor : public detail::abstract_scheduled_actor {
typedef detail::abstract_scheduled_actor super;
typedef super::queue_node queue_node;
public:
......@@ -59,7 +57,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
void dequeue(partial_function&); //override
void resume(util::fiber*, resume_callback* callback); //override
void resume(util::fiber*, scheduler::callback* cb); //override
/**
* @brief Initializes the actor by defining an initial behavior.
......@@ -71,16 +69,18 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
*/
virtual void on_exit();
inline abstract_event_based_actor* attach_to_scheduler(scheduler* sched)
{
CPPA_REQUIRE(sched != nullptr);
m_scheduler = sched;
init();
return this;
}
protected:
std::vector<std::unique_ptr<detail::recursive_queue_node> > m_cache;
enum handle_message_result {
drop_msg,
msg_handled,
cache_msg
};
auto handle_message(mailbox_element& node) -> handle_message_result;
abstract_event_based_actor();
// ownership flag + pointer
......@@ -89,9 +89,6 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
std::vector<stack_element> m_loop_stack;
// current position in mailbox
mailbox_cache_type::iterator m_mailbox_pos;
// provoke compiler errors for usage of receive() and related functions
/**
......@@ -99,8 +96,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
* does not accidently uses receive() instead of become().
*/
template<typename... Args>
void receive(Args&&...)
{
void receive(Args&&...) {
static_assert((sizeof...(Args) + 1) < 1,
"You shall not use receive in an event-based actor. "
"Use become() instead.");
......@@ -110,8 +106,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
* @brief Provokes a compiler error.
*/
template<typename... Args>
void receive_loop(Args&&... args)
{
void receive_loop(Args&&... args) {
receive(std::forward<Args>(args)...);
}
......@@ -119,8 +114,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
* @brief Provokes a compiler error.
*/
template<typename... Args>
void receive_while(Args&&... args)
{
void receive_while(Args&&... args) {
receive(std::forward<Args>(args)...);
}
......@@ -128,16 +122,10 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
* @brief Provokes a compiler error.
*/
template<typename... Args>
void do_receive(Args&&... args)
{
void do_receive(Args&&... args) {
receive(std::forward<Args>(args)...);
}
private:
bool handle_message(queue_node& iter);
bool invoke_from_cache();
};
} // namespace cppa
......
......@@ -52,13 +52,19 @@ typedef std::uint32_t actor_id;
/**
* @brief Base class for all actor implementations.
*/
class actor : public channel
{
class actor : public channel {
public:
~actor();
/**
* @brief Enqueues @p msg to the actor's mailbox and returns true if
* this actor is an scheduled actor that successfully changed
* its state to @p pending.
*/
virtual bool pending_enqueue(actor* sender, any_tuple msg);
/**
* @brief Attaches @p ptr to this actor.
*
......@@ -150,7 +156,7 @@ class actor : public channel
void link_to(intrusive_ptr<actor>&& other);
/**
* @copydoc unlink_from(intrusive_ptr<actor>&)
* @copydoc :unlink_from(intrusive_ptr<actor>&)
*/
void unlink_from(intrusive_ptr<actor>&& other);
......@@ -217,23 +223,19 @@ typedef intrusive_ptr<actor> actor_ptr;
* inline and template member function implementations *
******************************************************************************/
inline const process_information& actor::parent_process() const
{
inline const process_information& actor::parent_process() const {
return *m_parent_process;
}
inline process_information_ptr actor::parent_process_ptr() const
{
inline process_information_ptr actor::parent_process_ptr() const {
return m_parent_process;
}
inline std::uint32_t actor::id() const
{
inline std::uint32_t actor::id() const {
return m_id;
}
inline bool actor::is_proxy() const
{
inline bool actor::is_proxy() const {
return m_is_proxy;
}
......@@ -241,39 +243,33 @@ template<typename T>
bool actor::attach(std::unique_ptr<T>&& ptr,
typename std::enable_if<
std::is_base_of<attachable,T>::value
>::type*)
{
>::type*) {
return attach(static_cast<attachable*>(ptr.release()));
}
template<class F>
class functor_attachable : public attachable
{
class functor_attachable : public attachable {
F m_functor;
public:
template<class FArg>
functor_attachable(FArg&& arg) : m_functor(std::forward<FArg>(arg))
{
functor_attachable(FArg&& arg) : m_functor(std::forward<FArg>(arg)) {
}
void actor_exited(std::uint32_t reason)
{
void actor_exited(std::uint32_t reason) {
m_functor(reason);
}
bool matches(const attachable::token&)
{
bool matches(const attachable::token&) {
return false;
}
};
template<typename F>
bool actor::attach_functor(F&& ftor)
{
bool actor::attach_functor(F&& ftor) {
typedef typename util::rm_ref<F>::type f_type;
return attach(new functor_attachable<f_type>(std::forward<F>(ftor)));
}
......
......@@ -45,8 +45,7 @@ class actor_proxy : public actor { };
#else // CPPA_DOCUMENTATION
class actor_proxy : public abstract_actor<actor>
{
class actor_proxy : public abstract_actor<actor> {
typedef abstract_actor<actor> super;
......@@ -54,19 +53,17 @@ class actor_proxy : public abstract_actor<actor>
actor_proxy(std::uint32_t mid, const process_information_ptr& parent);
void enqueue(actor* sender, any_tuple&& msg);
void enqueue(actor* sender, const any_tuple& msg);
void enqueue(actor* sender, any_tuple msg);
void link_to(intrusive_ptr<actor>& other);
// do not cause to send this actor an ":Unlink" message
// do not cause to send this actor an "UNLINK" message
// to the "original" remote actor
void local_link_to(intrusive_ptr<actor>& other);
void unlink_from(intrusive_ptr<actor>& other);
// do not cause to send this actor an ":Unlink" message
// do not cause to send this actor an "UNLINK" message
// to the "original" remote actor
void local_unlink_from(intrusive_ptr<actor>& other);
......@@ -76,8 +73,7 @@ class actor_proxy : public abstract_actor<actor>
public:
void forward_message(const process_information_ptr&,
actor*, const any_tuple&);
void forward_message(const process_information_ptr&, actor*, any_tuple&&);
};
......
......@@ -110,16 +110,14 @@ bool announce(const std::type_info& tinfo, uniform_type_info* utype);
*/
template<class C, class Parent, typename... Args>
std::pair<C Parent::*, util::abstract_uniform_type_info<C>*>
compound_member(C Parent::*c_ptr, const Args&... args)
{
compound_member(C Parent::*c_ptr, const Args&... args) {
return { c_ptr, new detail::default_uniform_type_info_impl<C>(args...) };
}
// deals with getter returning a mutable reference
template<class C, class Parent, typename... Args>
std::pair<C& (Parent::*)(), util::abstract_uniform_type_info<C>*>
compound_member(C& (Parent::*c_ptr)(), const Args&... args)
{
compound_member(C& (Parent::*c_ptr)(), const Args&... args) {
return { c_ptr, new detail::default_uniform_type_info_impl<C>(args...) };
}
......@@ -129,8 +127,7 @@ template<class Parent, typename GRes,
std::pair<std::pair<GRes (Parent::*)() const, SRes (Parent::*)(SArg)>,
util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>
compound_member(const std::pair<GRes (Parent::*)() const, SRes (Parent::*)(SArg)>& gspair,
const Args&... args)
{
const Args&... args) {
return { gspair, new detail::default_uniform_type_info_impl<typename util::rm_ref<GRes>::type>(args...) };
}
......@@ -142,8 +139,7 @@ compound_member(const std::pair<GRes (Parent::*)() const, SRes (Parent::*)(SArg)
* otherwise @c false.
*/
template<typename T, typename... Args>
inline bool announce(const Args&... args)
{
inline bool announce(const Args&... args) {
return announce(typeid(T),
new detail::default_uniform_type_info_impl<T>(args...));
}
......
......@@ -33,9 +33,9 @@
#include <type_traits>
#include "cppa/cow_tuple.hpp"
#include "cppa/config.hpp"
#include "cppa/cow_ptr.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/is_iterable.hpp"
......@@ -51,8 +51,7 @@ namespace cppa {
* @brief Describes a fixed-length copy-on-write tuple
* with elements of any type.
*/
class any_tuple
{
class any_tuple {
public:
......@@ -129,15 +128,13 @@ class any_tuple
inline bool empty() const { return size() == 0; }
template<typename T>
inline const T& get_as(size_t p) const
{
inline const T& get_as(size_t p) const {
CPPA_REQUIRE(*(type_at(p)) == typeid(T));
return *reinterpret_cast<T const*>(at(p));
}
template<typename T>
inline T& get_as_mutable(size_t p)
{
inline T& get_as_mutable(size_t p) {
CPPA_REQUIRE(*(type_at(p)) == typeid(T));
return *reinterpret_cast<T*>(mutable_at(p));
}
......@@ -150,13 +147,11 @@ class any_tuple
inline const cow_ptr<detail::abstract_tuple>& vals() const { return m_vals; }
inline const cow_ptr<detail::abstract_tuple>& cvals() const { return m_vals; }
inline std::type_info const* type_token() const
{
inline std::type_info const* type_token() const {
return m_vals->type_token();
}
inline detail::tuple_impl_info impl_type() const
{
inline detail::tuple_impl_info impl_type() const {
return m_vals->impl_type();
}
......@@ -166,8 +161,7 @@ class any_tuple
util::is_iterable<
typename util::rm_ref<T>::type
>::value
>::type* = 0)
{
>::type* = 0) {
static constexpr bool can_optimize = std::is_reference<T>::value
&& !std::is_const<T>::value;
std::integral_constant<bool, can_optimize> token;
......@@ -180,8 +174,7 @@ class any_tuple
util::is_iterable<
typename util::rm_ref<T>::type
>::value == false
>::type* = 0)
{
>::type* = 0) {
typedef typename util::rm_ref<T>::type vtype;
typedef typename detail::implicit_conversions<vtype>::type converted;
static_assert(util::is_legal_tuple_type<converted>::value,
......@@ -194,8 +187,7 @@ class any_tuple
return any_tuple{simple_view(std::forward<T>(value), token)};
}
void force_detach()
{
void force_detach() {
m_vals.detach();
}
......@@ -211,22 +203,19 @@ class any_tuple
template<typename T>
static inline tup_ptr simple_view(T& value,
std::integral_constant<bool, true>)
{
std::integral_constant<bool, true>) {
return new detail::tuple_view<T>(&value);
}
template<typename First, typename Second>
static inline tup_ptr simple_view(std::pair<First, Second>& p,
std::integral_constant<bool, true>)
{
std::integral_constant<bool, true>) {
return new detail::tuple_view<First, Second>(&p.first, &p.second);
}
template<typename T>
static inline tup_ptr simple_view(T&& value,
std::integral_constant<bool, false>)
{
std::integral_constant<bool, false>) {
typedef typename util::rm_ref<T>::type vtype;
typedef typename detail::implicit_conversions<vtype>::type converted;
return new detail::tuple_vals<converted>(std::forward<T>(value));
......@@ -234,23 +223,20 @@ class any_tuple
template<typename First, typename Second>
static inline any_tuple view(std::pair<First, Second> p,
std::integral_constant<bool, false>)
{
std::integral_constant<bool, false>) {
return new detail::tuple_vals<First, Second>(std::move(p.first),
std::move(p.second));
}
template<typename T>
static inline detail::abstract_tuple* container_view(T& value,
std::integral_constant<bool, true>)
{
std::integral_constant<bool, true>) {
return new detail::container_tuple_view<T>(&value);
}
template<typename T>
static inline detail::abstract_tuple* container_view(T&& value,
std::integral_constant<bool, false>)
{
std::integral_constant<bool, false>) {
typedef typename util::rm_ref<T>::type ctype;
return new detail::container_tuple_view<T>(new ctype(std::forward<T>(value)), true);
}
......@@ -260,19 +246,22 @@ class any_tuple
/**
* @relates any_tuple
*/
inline bool operator==(const any_tuple& lhs, const any_tuple& rhs)
{
inline bool operator==(const any_tuple& lhs, const any_tuple& rhs) {
return lhs.equals(rhs);
}
/**
* @relates any_tuple
*/
inline bool operator!=(const any_tuple& lhs, const any_tuple& rhs)
{
inline bool operator!=(const any_tuple& lhs, const any_tuple& rhs) {
return !(lhs == rhs);
}
template<typename... Args>
inline any_tuple make_any_tuple(Args&&... args) {
return make_cow_tuple(std::forward<Args>(args)...);
}
} // namespace cppa
#endif // ANY_TUPLE_HPP
......@@ -40,19 +40,16 @@ namespace cppa {
*/
struct anything { };
inline bool operator==(const anything&, const anything&)
{
inline bool operator==(const anything&, const anything&) {
return true;
}
inline bool operator!=(const anything&, const anything&)
{
inline bool operator!=(const anything&, const anything&) {
return false;
}
template<typename T>
struct is_anything
{
struct is_anything {
static constexpr bool value = std::is_same<T, anything>::value;
};
......
......@@ -45,8 +45,7 @@ std::string to_string(const atom_value& a);
* @brief Creates an atom from given string literal.
*/
template<size_t Size>
constexpr atom_value atom(char const (&str) [Size])
{
constexpr atom_value atom(char const (&str) [Size]) {
// last character is the NULL terminator
static_assert(Size <= 11, "only 10 characters are allowed");
return static_cast<atom_value>(detail::atom_val(str, 0xF));
......
......@@ -39,8 +39,7 @@ namespace cppa {
/**
* @brief Callback utility class.
*/
class attachable
{
class attachable {
attachable(const attachable&) = delete;
attachable& operator=(const attachable&) = delete;
......@@ -54,8 +53,7 @@ class attachable
/**
* @brief Represents a pointer to a value with its RTTI.
*/
struct token
{
struct token {
/**
* @brief Denotes the type of @c ptr.
*/
......@@ -65,8 +63,7 @@ class attachable
*/
void const* ptr;
inline token(const std::type_info& msubtype, void const* mptr)
: subtype(msubtype), ptr(mptr)
{
: subtype(msubtype), ptr(mptr) {
}
};
......
......@@ -49,8 +49,7 @@ namespace cppa {
/**
* @brief Describes the behavior of an actor.
*/
class behavior
{
class behavior {
friend behavior operator,(partial_function&& lhs, behavior&& rhs);
......@@ -62,41 +61,42 @@ class behavior
behavior() = default;
behavior(behavior&&) = default;
inline behavior(partial_function&& fun) : m_fun(std::move(fun))
{
inline behavior(partial_function&& fun) : m_fun(std::move(fun)) {
}
template<typename... Cases>
behavior(const match_expr<Cases...>& me) : m_fun(me) { }
inline behavior(util::duration tout, std::function<void()>&& handler)
: m_timeout(tout), m_timeout_handler(std::move(handler))
{
: m_timeout(tout), m_timeout_handler(std::move(handler)) {
}
behavior& operator=(behavior&&) = default;
//behavior& operator=(partial_function&& pfun)
//{
// m_fun = std::move(pfun);
// return *this;
//}
inline void handle_timeout() const
{
inline void handle_timeout() const {
m_timeout_handler();
}
inline const util::duration& timeout() const
{
inline const util::duration& timeout() const {
return m_timeout;
}
inline partial_function& get_partial_function()
{
inline partial_function& get_partial_function() {
return m_fun;
}
inline bool operator()(any_tuple& value) {
return m_fun(value);
}
inline bool operator()(any_tuple const& value) {
return m_fun(value);
}
inline bool operator()(any_tuple&& value) {
return m_fun(std::move(value));
}
private:
// terminates recursion
......@@ -110,21 +110,18 @@ class behavior
template<typename... Lhs>
behavior operator,(const match_expr<Lhs...>& lhs,
behavior&& rhs)
{
behavior&& rhs) {
rhs.get_partial_function() = lhs;
return std::move(rhs);
}
template<typename Arg0>
behavior bhvr_collapse(Arg0&& arg)
{
behavior bhvr_collapse(Arg0&& arg) {
return {std::forward<Arg0>(arg)};
}
template<typename Arg0, typename Arg1, typename... Args>
behavior bhvr_collapse(Arg0&& arg0, Arg1&& arg1, Args&&... args)
{
behavior bhvr_collapse(Arg0&& arg0, Arg1&& arg1, Args&&... args) {
return bhvr_collapse((std::forward<Arg0>(arg0), std::forward<Arg1>(arg1)),
std::forward<Args>(args)...);
}
......@@ -134,8 +131,7 @@ typename std::enable_if<
util::disjunction<std::is_same<behavior, Args>...>::value,
behavior
>::type
match_expr_concat(Args&&... args)
{
match_expr_concat(Args&&... args) {
return bhvr_collapse(std::forward<Args>(args)...);
}
......@@ -149,26 +145,22 @@ typename std::enable_if<
>::value == false,
partial_function
>::type
match_expr_concat(Args&&... args)
{
match_expr_concat(Args&&... args) {
return mexpr_concat_convert(std::forward<Args>(args)...);
}
inline partial_function match_expr_concat(partial_function&& pfun)
{
inline partial_function match_expr_concat(partial_function&& pfun) {
return std::move(pfun);
}
inline behavior match_expr_concat(behavior&& bhvr)
{
inline behavior match_expr_concat(behavior&& bhvr) {
return std::move(bhvr);
}
namespace detail {
template<typename... Ts>
struct select_bhvr
{
struct select_bhvr {
static constexpr bool timed =
util::disjunction<std::is_same<behavior, Ts>...>::value;
typedef typename util::if_else_c<timed,
......
......@@ -39,8 +39,7 @@ namespace cppa {
* @brief Implements the deserializer interface with
* a binary serialization protocol.
*/
class binary_deserializer : public deserializer
{
class binary_deserializer : public deserializer {
char const* pos;
char const* end;
......
......@@ -42,8 +42,7 @@ namespace detail { class binary_writer; }
* @brief Implements the serializer interface with
* a binary serialization protocol.
*/
class binary_serializer : public serializer
{
class binary_serializer : public serializer {
friend class detail::binary_writer;
......@@ -72,12 +71,6 @@ class binary_serializer : public serializer
void write_tuple(size_t size, primitive_variant const* values);
/**
* @brief Takes the internal buffer and returns it.
*
*/
std::pair<size_t, char*> take_buffer();
/**
* @brief Returns the number of written bytes.
*/
......@@ -88,6 +81,10 @@ class binary_serializer : public serializer
*/
char const* data() const;
size_t sendable_size() const;
char const* sendable_data();
/**
* @brief Resets the internal buffer.
*/
......
......@@ -47,8 +47,7 @@ class any_tuple;
* This interface describes an entity that can receive messages
* and is implemented by {@link actor} and {@link group}.
*/
class channel : public ref_counted
{
class channel : public ref_counted {
friend class actor;
friend class group;
......@@ -60,9 +59,7 @@ class channel : public ref_counted
/**
* @brief Enqueues @p msg to the list of received messages.
*/
virtual void enqueue(actor* sender, const any_tuple& msg) = 0;
virtual void enqueue(actor* sender, any_tuple&& msg) = 0;
virtual void enqueue(actor* sender, any_tuple msg) = 0;
private:
......
......@@ -63,12 +63,13 @@
#elif defined(CPPA_GCC)
# define CPPA_MEMORY_BARRIER() __sync_synchronize()
#else
# error Plattform and/or compiler not supportet
# error Plattform and/or compiler not supported
#endif
#ifdef CPPA_DEBUG
#include <cstdio>
#include <cstdlib>
#ifdef CPPA_DEBUG
#include <execinfo.h>
#define CPPA_REQUIRE__(stmt, file, line) \
......@@ -87,4 +88,11 @@
#define CPPA_REQUIRE(unused) ((void) 0)
#endif // CPPA_DEBUG
#define CPPA_CRITICAL__(error, file, line) { \
printf("%s:%u: critical error: '%s'\n", file, line, error); \
exit(7); \
} ((void) 0)
#define CPPA_CRITICAL(error) CPPA_CRITICAL__(error, __FILE__, __LINE__)
#endif // CPPA_CONFIG_HPP
......@@ -46,8 +46,7 @@ namespace cppa {
* {@link ref_counted}.
*/
template<typename T>
class cow_ptr
{
class cow_ptr {
public:
......@@ -63,35 +62,29 @@ class cow_ptr
template<typename Y>
cow_ptr(const cow_ptr<Y>& other) : m_ptr(const_cast<Y*>(other.get())) { }
inline void swap(cow_ptr& other)
{
inline void swap(cow_ptr& other) {
m_ptr.swap(other.m_ptr);
}
cow_ptr& operator=(cow_ptr&& other)
{
cow_ptr& operator=(cow_ptr&& other) {
swap(other);
return *this;
}
cow_ptr& operator=(const cow_ptr& other)
{
cow_ptr& operator=(const cow_ptr& other) {
cow_ptr tmp{other};
swap(tmp);
return *this;
}
template<typename Y>
cow_ptr& operator=(const cow_ptr<Y>& other)
{
cow_ptr& operator=(const cow_ptr<Y>& other) {
cow_ptr tmp{other};
swap(tmp);
return *this;
}
void detach()
{
(void) detached_ptr();
void detach() { (void) detached_ptr();
}
inline void reset(T* value = nullptr) { m_ptr.reset(value); }
......@@ -114,11 +107,9 @@ class cow_ptr
intrusive_ptr<T> m_ptr;
T* detached_ptr()
{
T* detached_ptr() {
T* ptr = m_ptr.get();
if (!ptr->unique())
{
if (!ptr->unique()) {
//T* new_ptr = detail::copy_of(ptr, copy_of_token());
T* new_ptr = ptr->copy();
cow_ptr tmp(new_ptr);
......
......@@ -63,8 +63,7 @@ class local_actor;
* @brief A fixed-length copy-on-write cow_tuple.
*/
template<typename... ElementTypes>
class cow_tuple
{
class cow_tuple {
static_assert(sizeof...(ElementTypes) > 0, "tuple is empty");
......@@ -94,24 +93,21 @@ class cow_tuple
/**
* @brief Initializes each element with its default constructor.
*/
cow_tuple() : m_vals(new data_type)
{
cow_tuple() : m_vals(new data_type) {
}
/**
* @brief Initializes the cow_tuple with @p args.
* @param args Initialization values.
*/
cow_tuple(const ElementTypes&... args) : m_vals(new data_type(args...))
{
cow_tuple(const ElementTypes&... args) : m_vals(new data_type(args...)) {
}
/**
* @brief Initializes the cow_tuple with @p args.
* @param args Initialization values.
*/
cow_tuple(ElementTypes&&... args) : m_vals(new data_type(std::move(args)...))
{
cow_tuple(ElementTypes&&... args) : m_vals(new data_type(std::move(args)...)) {
}
cow_tuple(cow_tuple&&) = default;
......@@ -119,19 +115,16 @@ class cow_tuple
cow_tuple& operator=(cow_tuple&&) = default;
cow_tuple& operator=(const cow_tuple&) = default;
inline static cow_tuple from(cow_ptr_type ptr)
{
inline static cow_tuple from(cow_ptr_type ptr) {
return {priv_ctor{}, std::move(ptr)};
}
inline static cow_tuple from(cow_ptr_type ptr,
const util::fixed_vector<size_t, num_elements>& mv)
{
const util::fixed_vector<size_t, num_elements>& mv) {
return {priv_ctor{}, decorated_type::create(std::move(ptr), mv)};
}
inline static cow_tuple offset_subtuple(cow_ptr_type ptr, size_t offset)
{
inline static cow_tuple offset_subtuple(cow_ptr_type ptr, size_t offset) {
CPPA_REQUIRE(offset > 0);
return {priv_ctor{}, decorated_type::create(std::move(ptr), offset)};
}
......@@ -139,24 +132,21 @@ class cow_tuple
/**
* @brief Gets the size of this cow_tuple.
*/
inline size_t size() const
{
inline size_t size() const {
return sizeof...(ElementTypes);
}
/**
* @brief Gets a const pointer to the element at position @p p.
*/
inline void const* at(size_t p) const
{
inline void const* at(size_t p) const {
return m_vals->at(p);
}
/**
* @brief Gets a mutable pointer to the element at position @p p.
*/
inline void* mutable_at(size_t p)
{
inline void* mutable_at(size_t p) {
return m_vals->mutable_at(p);
}
......@@ -164,13 +154,11 @@ class cow_tuple
* @brief Gets {@link uniform_type_info uniform type information}
* of the element at position @p p.
*/
inline uniform_type_info const* type_at(size_t p) const
{
inline uniform_type_info const* type_at(size_t p) const {
return m_vals->type_at(p);
}
inline const cow_ptr<detail::abstract_tuple>& vals() const
{
inline const cow_ptr<detail::abstract_tuple>& vals() const {
return m_vals;
}
......@@ -180,8 +168,7 @@ template<typename TypeList>
struct cow_tuple_from_type_list;
template<typename... Types>
struct cow_tuple_from_type_list< util::type_list<Types...> >
{
struct cow_tuple_from_type_list< util::type_list<Types...> > {
typedef cow_tuple<Types...> type;
};
......@@ -223,23 +210,20 @@ cow_tuple<Args...> make_cow_tuple(Args&&... args);
#else
template<size_t N, typename... Types>
const typename util::at<N, Types...>::type& get(const cow_tuple<Types...>& tup)
{
const typename util::at<N, Types...>::type& get(const cow_tuple<Types...>& tup) {
typedef typename util::at<N, Types...>::type result_type;
return *reinterpret_cast<result_type const*>(tup.at(N));
}
template<size_t N, typename... Types>
typename util::at<N, Types...>::type& get_ref(cow_tuple<Types...>& tup)
{
typename util::at<N, Types...>::type& get_ref(cow_tuple<Types...>& tup) {
typedef typename util::at<N, Types...>::type result_type;
return *reinterpret_cast<result_type*>(tup.mutable_at(N));
}
template<typename... Args>
cow_tuple<typename detail::strip_and_convert<Args>::type...>
make_cow_tuple(Args&&... args)
{
make_cow_tuple(Args&&... args) {
return {std::forward<Args>(args)...};
}
......@@ -254,8 +238,7 @@ make_cow_tuple(Args&&... args)
*/
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator==(const cow_tuple<LhsTypes...>& lhs,
const cow_tuple<RhsTypes...>& rhs)
{
const cow_tuple<RhsTypes...>& rhs) {
return util::compare_tuples(lhs, rhs);
}
......@@ -268,8 +251,7 @@ inline bool operator==(const cow_tuple<LhsTypes...>& lhs,
*/
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator!=(const cow_tuple<LhsTypes...>& lhs,
const cow_tuple<RhsTypes...>& rhs)
{
const cow_tuple<RhsTypes...>& rhs) {
return !(lhs == rhs);
}
......
......@@ -33,6 +33,7 @@
#include <tuple>
#include <cstdint>
#include <functional>
#include <type_traits>
#include "cppa/on.hpp"
......@@ -454,7 +455,7 @@ void unlink(actor_ptr& lhs, actor_ptr& rhs);
* @ingroup ActorManagement
* @brief Adds a unidirectional @p monitor to @p whom.
* @note Each calls to @p monitor creates a new, independent monitor.
* @pre The calling actor receives a ":Down" message from @p whom when
* @pre The calling actor receives a "DOWN" message from @p whom when
* it terminates.
*/
void monitor(actor_ptr& whom);
......@@ -472,9 +473,8 @@ void demonitor(actor_ptr& whom);
* @brief Spans a new context-switching actor.
* @returns A pointer to the spawned {@link actor Actor}.
*/
inline actor_ptr spawn(scheduled_actor* what)
{
return get_scheduler()->spawn(what, scheduled);
inline actor_ptr spawn(scheduled_actor* what) {
return get_scheduler()->spawn(what);
}
/**
......@@ -484,9 +484,8 @@ inline actor_ptr spawn(scheduled_actor* what)
* @returns A pointer to the spawned {@link actor Actor}.
*/
template<scheduling_hint Hint>
inline actor_ptr spawn(scheduled_actor* what)
{
return get_scheduler()->spawn(what, Hint);
inline actor_ptr spawn(std::function<void()> what) {
return get_scheduler()->spawn(std::move(what), Hint);
}
/**
......@@ -494,19 +493,45 @@ inline actor_ptr spawn(scheduled_actor* what)
* @brief Spans a new event-based actor.
* @returns A pointer to the spawned {@link actor Actor}.
*/
inline actor_ptr spawn(abstract_event_based_actor* what)
{
return get_scheduler()->spawn(what);
inline actor_ptr spawn(std::function<void()> what) {
return get_scheduler()->spawn(std::move(what), scheduled);
}
/**
template<typename T>
struct spawn_fwd_ {
static inline T&& _(T&& arg) { return std::move(arg); }
static inline T& _(T& arg) { return arg; }
static inline T const& _(T const& arg) { return arg; }
};
template<>
struct spawn_fwd_<self_type> {
static inline actor_ptr _(self_type const&) { return self; }
};
template<typename F, typename Arg0, typename... Args>
inline actor_ptr spawn(F&& what, Arg0&& arg0, Args&&... args) {
return spawn(std::bind(std::move(what),
spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...));
}
template<scheduling_hint Hint, typename F, typename Arg0, typename... Args>
inline actor_ptr spawn(F&& what, Arg0&& arg0, Args&&... args) {
return spawn<Hint>(std::bind(std::move(what),
spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...));
}
/*
/ **
* @ingroup ActorManagement
* @brief Spawns a new actor that executes @p what with given arguments.
* @tparam Hint Hint to the scheduler for the best scheduling strategy.
* @param what Function or functor that the spawned Actor should execute.
* @param args Arguments needed to invoke @p what.
* @returns A pointer to the spawned {@link actor actor}.
*/
* /
template<scheduling_hint Hint, typename F, typename... Args>
auto //actor_ptr
spawn(F&& what, const Args&... args)
......@@ -514,18 +539,17 @@ spawn(F&& what, const Args&... args)
!std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value
&& !std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value,
actor_ptr
>::type
{
>::type {
typedef typename util::rm_ref<F>::type ftype;
std::integral_constant<bool, std::is_function<ftype>::value> is_fun;
auto ptr = detail::get_behavior(is_fun, std::forward<F>(what), args...);
return get_scheduler()->spawn(ptr, Hint);
}
/**
/ **
* @ingroup ActorManagement
* @brief Alias for <tt>spawn<scheduled>(what, args...)</tt>.
*/
* /
template<typename F, typename... Args>
auto // actor_ptr
spawn(F&& what, const Args&... args)
......@@ -533,10 +557,10 @@ spawn(F&& what, const Args&... args)
!std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value
&& !std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value,
actor_ptr
>::type
{
>::type {
return spawn<scheduled>(std::forward<F>(what), args...);
}
*/
#ifdef CPPA_DOCUMENTATION
......@@ -562,32 +586,29 @@ channel_ptr& operator<<(channel_ptr& whom, const any_tuple& what);
#else
template<class C, typename Arg0, typename... Args>
void send(intrusive_ptr<C>& whom, const Arg0& arg0, const Args&... args)
{
void send(intrusive_ptr<C>& whom, const Arg0& arg0, const Args&... args) {
static_assert(std::is_base_of<channel, C>::value, "C is not a channel");
if (whom) whom->enqueue(self, make_cow_tuple(arg0, args...));
if (whom) self->send_message(whom.get(), make_cow_tuple(arg0, args...));
}
template<class C, typename Arg0, typename... Args>
void send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args)
{
void send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args) {
static_assert(std::is_base_of<channel, C>::value, "C is not a channel");
intrusive_ptr<C> tmp(std::move(whom));
if (tmp) tmp->enqueue(self, make_cow_tuple(arg0, args...));
send(tmp, arg0, args...);
}
// matches "send(this, ...)" in event-based actors
template<typename Arg0, typename... Args>
void send(local_actor* whom, const Arg0& arg0, const Args&... args)
{
inline void send(local_actor* whom, const Arg0& arg0, const Args&... args) {
CPPA_REQUIRE(whom != nullptr);
whom->enqueue(whom, make_cow_tuple(arg0, args...));
}
// matches send(self, ...);
template<typename Arg0, typename... Args>
inline void send(const self_type&, const Arg0& arg0, const Args&... args)
{
inline void send(const self_type&, const Arg0& arg0, const Args&... args) {
send(static_cast<local_actor*>(self), arg0, args...);
}
......@@ -596,9 +617,8 @@ typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>&
>::type
operator<<(intrusive_ptr<C>& whom, const any_tuple& what)
{
if (whom) whom->enqueue(self, what);
operator<<(intrusive_ptr<C>& whom, const any_tuple& what) {
if (whom) self->send_message(whom.get(), what);
return whom;
}
......@@ -607,10 +627,9 @@ typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>
>::type
operator<<(intrusive_ptr<C>&& whom, const any_tuple& what)
{
operator<<(intrusive_ptr<C>&& whom, const any_tuple& what) {
intrusive_ptr<C> tmp(std::move(whom));
if (tmp) tmp->enqueue(self, what);
tmp << what;
return std::move(tmp);
}
......@@ -619,9 +638,8 @@ typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>&
>::type
operator<<(intrusive_ptr<C>& whom, any_tuple&& what)
{
if (whom) whom->enqueue(self, std::move(what));
operator<<(intrusive_ptr<C>& whom, any_tuple&& what) {
if (whom) self->send_message(whom.get(), std::move(what));
return whom;
}
......@@ -630,10 +648,9 @@ typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>
>::type
operator<<(intrusive_ptr<C>&& whom, any_tuple&& what)
{
operator<<(intrusive_ptr<C>&& whom, any_tuple&& what) {
intrusive_ptr<C> tmp(std::move(whom));
if (tmp) tmp->enqueue(self, std::move(what));
tmp << std::move(what);
return std::move(tmp);
}
......@@ -648,8 +665,7 @@ const self_type& operator<<(const self_type& s, any_tuple&& what);
* @brief Sends a message to the sender of the last received message.
*/
template<typename Arg0, typename... Args>
void reply(const Arg0& arg0, const Args&... args)
{
void reply(const Arg0& arg0, const Args&... args) {
send(self->last_sender(), arg0, args...);
}
......@@ -661,8 +677,7 @@ void reply(const Arg0& arg0, const Args&... args)
* @param data Any number of values for the message content.
*/
template<typename Duration, typename... Data>
void future_send(actor_ptr whom, const Duration& rel_time, const Data&... data)
{
void future_send(actor_ptr whom, const Duration& rel_time, const Data&... data) {
get_scheduler()->future_send(whom, rel_time, data...);
}
......@@ -672,8 +687,7 @@ void future_send(actor_ptr whom, const Duration& rel_time, const Data&... data)
* @see future_send()
*/
template<typename Duration, typename... Data>
void delayed_reply(const Duration& rel_time, Data const... data)
{
void delayed_reply(const Duration& rel_time, Data const... data) {
future_send(self->last_sender(), rel_time, data...);
}
......@@ -683,8 +697,7 @@ void delayed_reply(const Duration& rel_time, Data const... data)
* @warning This function will cause a deadlock if
* called from multiple actors.
*/
inline void await_all_others_done()
{
inline void await_all_others_done() {
detail::actor_count_wait_until((self.unchecked() == nullptr) ? 0 : 1);
}
......
......@@ -45,8 +45,7 @@ class object;
* @ingroup TypeSystem
* @brief Technology-independent deserialization interface.
*/
class deserializer
{
class deserializer {
deserializer(const deserializer&) = delete;
deserializer& operator=(const deserializer&) = delete;
......
......@@ -31,77 +31,74 @@
#ifndef SCHEDULED_ACTOR_HPP
#define SCHEDULED_ACTOR_HPP
#include <iostream>
#include <atomic>
#include "cppa/any_tuple.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/util/fiber.hpp"
#include "cppa/intrusive/singly_linked_list.hpp"
#include "cppa/detail/filter_result.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace cppa { class scheduler; }
namespace cppa { namespace detail {
// A spawned, scheduled Actor.
class abstract_scheduled_actor : public abstract_actor<local_actor>
{
friend class intrusive::single_reader_queue<abstract_scheduled_actor>;
class abstract_scheduled_actor : public abstract_actor<scheduled_actor> {
abstract_scheduled_actor* next; // intrusive next pointer
void enqueue_node(queue_node* node);
typedef abstract_actor<scheduled_actor> super;
protected:
std::atomic<int> m_state;
scheduler* m_scheduler;
typedef abstract_actor super;
typedef super::queue_node_guard queue_node_guard;
typedef super::queue_node queue_node;
typedef super::queue_node_ptr queue_node_ptr;
enum dq_result
{
dq_done,
dq_indeterminate,
dq_timeout_occured
};
enum filter_result
{
normal_exit_signal,
expired_timeout_message,
timeout_message,
ordinary_message
};
filter_result filter_msg(const any_tuple& msg);
auto dq(queue_node& node, partial_function& rules) -> dq_result;
bool has_pending_timeout()
{
filter_result filter_msg(any_tuple const& msg) {
auto& arr = detail::static_types_array<atom_value, std::uint32_t>::arr;
if ( msg.size() == 2
&& msg.type_at(0) == arr[0]
&& msg.type_at(1) == arr[1]) {
auto v0 = *reinterpret_cast<const atom_value*>(msg.at(0));
auto v1 = *reinterpret_cast<const std::uint32_t*>(msg.at(1));
if (v0 == atom("EXIT")) {
if (this->m_trap_exit == false) {
if (v1 != exit_reason::normal) {
quit(v1);
}
return normal_exit_signal;
}
}
else if (v0 == atom(":Timeout")) {
return (v1 == m_active_timeout_id) ? timeout_message
: expired_timeout_message;
}
}
return ordinary_message;
}
bool has_pending_timeout() {
return m_has_pending_timeout_request;
}
void request_timeout(const util::duration& d);
void request_timeout(const util::duration& d) {
if (d.valid()) {
get_scheduler()->future_send(this, d, atom(":Timeout"), ++m_active_timeout_id);
m_has_pending_timeout_request = true;
}
}
void reset_timeout()
{
if (m_has_pending_timeout_request)
{
void reset_timeout() {
if (m_has_pending_timeout_request) {
++m_active_timeout_id;
m_has_pending_timeout_request = false;
}
}
private:
bool m_has_pending_timeout_request;
std::uint32_t m_active_timeout_id;
......@@ -110,44 +107,71 @@ class abstract_scheduled_actor : public abstract_actor<local_actor>
static constexpr int ready = 0x00;
static constexpr int done = 0x01;
static constexpr int blocked = 0x02;
static constexpr int pending = 0x03;
static constexpr int about_to_block = 0x04;
abstract_scheduled_actor(int state = done);
abstract_scheduled_actor(scheduler* sched);
void quit(std::uint32_t reason);
abstract_scheduled_actor(int state = done)
: super(true), m_state(state)
, m_has_pending_timeout_request(false)
, m_active_timeout_id(0) {
}
void enqueue(actor* sender, any_tuple&& msg);
bool pending_enqueue(actor* sender, any_tuple msg) {
return enqueue_node(super::fetch_node(sender, std::move(msg)), pending);
}
void enqueue(actor* sender, const any_tuple& msg);
void quit(std::uint32_t reason) {
this->cleanup(reason);
throw actor_exited(reason);
}
int compare_exchange_state(int expected, int new_value);
void enqueue(actor* sender, any_tuple msg) {
enqueue_node(super::fetch_node(sender, std::move(msg)));
}
struct resume_callback
{
virtual ~resume_callback();
// called if an actor finished execution
virtual void exec_done() = 0;
};
int compare_exchange_state(int expected, int new_value) {
int e = expected;
do {
if (m_state.compare_exchange_weak(e, new_value)) {
return new_value;
}
}
while (e == expected);
return e;
}
// from = calling worker
virtual void resume(util::fiber* from, resume_callback* callback) = 0;
private:
};
bool enqueue_node(typename super::mailbox_element* node,
int target_state = ready) {
CPPA_REQUIRE(node->marked == false);
if (this->m_mailbox._push_back(node)) {
for (;;) {
int state = m_state.load();
switch (state) {
case blocked: {
if (m_state.compare_exchange_weak(state, target_state)) {
CPPA_REQUIRE(this->m_scheduler != nullptr);
if (target_state == ready) {
this->m_scheduler->enqueue(this);
}
return true;
}
break;
}
case about_to_block: {
if (m_state.compare_exchange_weak(state, ready)) {
return false;
}
break;
}
default: return false;
}
}
}
return false;
}
struct scheduled_actor_dummy : abstract_scheduled_actor
{
void resume(util::fiber*, resume_callback*);
void quit(std::uint32_t);
void dequeue(behavior&);
void dequeue(partial_function&);
void link_to(intrusive_ptr<actor>&);
void unlink_from(intrusive_ptr<actor>&);
bool establish_backlink(intrusive_ptr<actor>&);
bool remove_backlink(intrusive_ptr<actor>&);
void detach(const attachable::token&);
bool attach(attachable*);
};
} } // namespace cppa::detail
......
......@@ -44,14 +44,12 @@
namespace cppa { namespace detail {
enum tuple_impl_info
{
enum tuple_impl_info {
statically_typed,
dynamically_typed
};
class abstract_tuple : public ref_counted
{
class abstract_tuple : public ref_counted {
tuple_impl_info m_impl_type;
......@@ -97,31 +95,26 @@ class abstract_tuple : public ref_counted
};
struct full_eq_type
{
struct full_eq_type {
constexpr full_eq_type() { }
template<class Tuple>
inline bool operator()(const tuple_iterator<Tuple>& lhs,
const tuple_iterator<Tuple>& rhs) const
{
const tuple_iterator<Tuple>& rhs) const {
return lhs.type() == rhs.type()
&& lhs.type()->equals(lhs.value(), rhs.value());
}
};
struct types_only_eq_type
{
struct types_only_eq_type {
constexpr types_only_eq_type() { }
template<class Tuple>
inline bool operator()(const tuple_iterator<Tuple>& lhs,
uniform_type_info const* rhs ) const
{
uniform_type_info const* rhs ) const {
return lhs.type() == rhs;
}
template<class Tuple>
inline bool operator()(uniform_type_info const* lhs,
const tuple_iterator<Tuple>& rhs) const
{
const tuple_iterator<Tuple>& rhs) const {
return lhs == rhs.type();
}
};
......
......@@ -32,59 +32,64 @@
#define ACTOR_PROXY_CACHE_HPP
#include <string>
#include <limits>
#include <vector>
#include <functional>
#include "cppa/actor_proxy.hpp"
#include "cppa/process_information.hpp"
namespace cppa { namespace detail {
class actor_proxy_cache
{
public:
typedef std::tuple<std::uint32_t, // actor id
std::uint32_t, // process id
process_information::node_id_type> // node id
key_tuple;
typedef std::function<void (actor_proxy_ptr&)> new_proxy_callback;
private:
#include "cppa/util/shared_spinlock.hpp"
std::map<key_tuple, process_information_ptr> m_pinfos;
std::map<key_tuple, actor_proxy_ptr> m_proxies;
#include "cppa/detail/thread.hpp"
new_proxy_callback m_new_cb;
namespace cppa { namespace detail {
process_information_ptr get_pinfo(const key_tuple& key);
class actor_proxy_cache {
public:
// this callback is called if a new proxy instance is created
template<typename F>
void set_new_proxy_callback(F&& cb)
{
m_new_cb = std::forward<F>(cb);
actor_proxy_ptr get(actor_id aid, std::uint32_t process_id,
process_information::node_id_type const& node_id);
// @returns true if pptr was successfully removed, false otherwise
bool erase(const actor_proxy_ptr& pptr);
template<typename Fun>
void erase_all(process_information::node_id_type const& nid,
std::uint32_t process_id,
Fun fun) {
key_tuple lb{nid, process_id, std::numeric_limits<actor_id>::min()};
key_tuple ub{nid, process_id, std::numeric_limits<actor_id>::max()}; {
lock_guard<util::shared_spinlock> guard{m_lock};
auto e = m_entries.end();
auto first = m_entries.lower_bound(lb);
if (first != e) {
auto last = m_entries.upper_bound(ub);
for (auto i = first; i != last; ++i) {
fun(i->second);
}
m_entries.erase(first, last);
}
}
}
actor_proxy_ptr get(const key_tuple& key);
private:
void add(actor_proxy_ptr& pptr);
typedef std::tuple<process_information::node_id_type, // node id
std::uint32_t, // process id
actor_id> // (remote) actor id
key_tuple;
size_t size() const;
struct key_tuple_less {
bool operator()(key_tuple const& lhs, key_tuple const& rhs) const;
};
void erase(const actor_proxy_ptr& pptr);
util::shared_spinlock m_lock;
std::map<key_tuple, actor_proxy_ptr, key_tuple_less> m_entries;
actor_proxy_ptr get_impl(const key_tuple& key);
template<typename F>
void for_each(F&& fun)
{
for (auto i = m_proxies.begin(); i != m_proxies.end(); ++i)
{
fun(i->second);
}
}
};
......
......@@ -42,8 +42,7 @@
namespace cppa { namespace detail {
class actor_registry
{
class actor_registry {
public:
......
......@@ -38,22 +38,13 @@
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/detail/channel.hpp"
namespace cppa { namespace detail {
class addressed_message
{
class addressed_message {
public:
addressed_message(const actor_ptr& from,
const channel_ptr& to,
const any_tuple& ut);
addressed_message(const actor_ptr& from,
const channel_ptr& to,
any_tuple&& ut);
addressed_message(actor_ptr from, channel_ptr to, any_tuple ut);
addressed_message() = default;
addressed_message(addressed_message&&) = default;
......@@ -61,38 +52,31 @@ class addressed_message
addressed_message& operator=(addressed_message&&) = default;
addressed_message& operator=(const addressed_message&) = default;
inline actor_ptr& sender()
{
inline actor_ptr& sender() {
return m_sender;
}
inline const actor_ptr& sender() const
{
inline const actor_ptr& sender() const {
return m_sender;
}
inline channel_ptr& receiver()
{
inline channel_ptr& receiver() {
return m_receiver;
}
inline const channel_ptr& receiver() const
{
inline const channel_ptr& receiver() const {
return m_receiver;
}
inline any_tuple& content()
{
inline any_tuple& content() {
return m_content;
}
inline const any_tuple& content() const
{
inline const any_tuple& content() const {
return m_content;
}
inline bool empty() const
{
inline bool empty() const {
return m_content.empty();
}
......@@ -106,8 +90,7 @@ class addressed_message
bool operator==(const addressed_message& lhs, const addressed_message& rhs);
inline bool operator!=(const addressed_message& lhs, const addressed_message& rhs)
{
inline bool operator!=(const addressed_message& lhs, const addressed_message& rhs) {
return !(lhs == rhs);
}
......
......@@ -34,8 +34,7 @@
namespace cppa { namespace detail { namespace {
// encodes ASCII characters to 6bit encoding
constexpr char encoding_table[] =
{
constexpr char encoding_table[] = {
/* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */
/* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
......@@ -52,13 +51,11 @@ constexpr char decoding_table[] = " 0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"abcdefghijklmnopqrstuvwxyz";
constexpr std::uint64_t next_interim(std::uint64_t current, size_t char_code)
{
constexpr std::uint64_t next_interim(std::uint64_t current, size_t char_code) {
return (current << 6) | encoding_table[(char_code <= 0x7F) ? char_code : 0];
}
constexpr std::uint64_t atom_val(char const* cstr, std::uint64_t interim = 0)
{
constexpr std::uint64_t atom_val(char const* cstr, std::uint64_t interim = 0) {
return (*cstr == '\0') ? interim
: atom_val(cstr + 1,
next_interim(interim,
......
......@@ -37,50 +37,42 @@
namespace cppa { namespace detail {
template<typename T>
struct boxed
{
struct boxed {
typedef util::wrapped<T> type;
};
template<typename T>
struct boxed< util::wrapped<T> >
{
struct boxed< util::wrapped<T> > {
typedef util::wrapped<T> type;
};
template<>
struct boxed<anything>
{
struct boxed<anything> {
typedef anything type;
};
template<typename T>
struct is_boxed
{
struct is_boxed {
static constexpr bool value = false;
};
template<typename T>
struct is_boxed< util::wrapped<T> >
{
struct is_boxed< util::wrapped<T> > {
static constexpr bool value = true;
};
template<typename T>
struct is_boxed<util::wrapped<T>()>
{
struct is_boxed<util::wrapped<T>()> {
static constexpr bool value = true;
};
template<typename T>
struct is_boxed<util::wrapped<T>(&)()>
{
struct is_boxed<util::wrapped<T>(&)()> {
static constexpr bool value = true;
};
template<typename T>
struct is_boxed<util::wrapped<T>(*)()>
{
struct is_boxed<util::wrapped<T>(*)()> {
static constexpr bool value = true;
};
......
This diff is collapsed.
......@@ -38,8 +38,7 @@ namespace cppa { class message; }
namespace cppa { namespace detail {
// public part of the actor interface
struct channel : ref_counted
{
struct channel : ref_counted {
virtual void enqueue_msg(const message& msg) = 0;
};
......
......@@ -41,8 +41,7 @@
namespace cppa { namespace detail {
template<class Container>
class container_tuple_view : public abstract_tuple
{
class container_tuple_view : public abstract_tuple {
typedef abstract_tuple super;
......@@ -51,40 +50,34 @@ class container_tuple_view : public abstract_tuple
typedef typename Container::value_type value_type;
container_tuple_view(Container* c, bool take_ownership = false)
: super(tuple_impl_info::dynamically_typed), m_ptr(c)
{
: super(tuple_impl_info::dynamically_typed), m_ptr(c) {
CPPA_REQUIRE(c != nullptr);
if (!take_ownership) m_ptr.get_deleter().disable();
}
size_t size() const
{
size_t size() const {
return m_ptr->size();
}
abstract_tuple* copy() const
{
abstract_tuple* copy() const {
return new container_tuple_view{new Container(*m_ptr), true};
}
void const* at(size_t pos) const
{
void const* at(size_t pos) const {
CPPA_REQUIRE(pos < size());
auto i = m_ptr->begin();
std::advance(i, pos);
return &(*i);
}
void* mutable_at(size_t pos)
{
void* mutable_at(size_t pos) {
CPPA_REQUIRE(pos < size());
auto i = m_ptr->begin();
std::advance(i, pos);
return &(*i);
}
uniform_type_info const* type_at(size_t) const
{
uniform_type_info const* type_at(size_t) const {
return static_types_array<value_type>::arr[0];
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -34,8 +34,7 @@
namespace cppa { namespace detail {
template<typename T>
class disablable_delete
{
class disablable_delete {
bool m_enabled;
......@@ -45,8 +44,7 @@ class disablable_delete
inline void disable() { m_enabled = false; }
inline void operator()(T* ptr)
{
inline void operator()(T* ptr) {
if (m_enabled) delete ptr;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment