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
e09e8634
Commit
e09e8634
authored
Dec 11, 2011
by
neverlord
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
event_based_actor improvements and fixes
parent
4ff15bf7
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
230 additions
and
87 deletions
+230
-87
cppa/detail/abstract_event_based_actor.hpp
cppa/detail/abstract_event_based_actor.hpp
+2
-0
cppa/detail/scheduled_actor.hpp
cppa/detail/scheduled_actor.hpp
+9
-0
cppa/event_based_actor.hpp
cppa/event_based_actor.hpp
+26
-10
cppa/util/either.hpp
cppa/util/either.hpp
+33
-0
cppa/util/singly_linked_list.hpp
cppa/util/singly_linked_list.hpp
+16
-10
src/abstract_event_based_actor.cpp
src/abstract_event_based_actor.cpp
+18
-7
src/event_based_actor.cpp
src/event_based_actor.cpp
+6
-0
src/scheduled_actor.cpp
src/scheduled_actor.cpp
+10
-2
unit_testing/test__spawn.cpp
unit_testing/test__spawn.cpp
+110
-58
No files found.
cppa/detail/abstract_event_based_actor.hpp
View file @
e09e8634
...
...
@@ -31,6 +31,8 @@ class abstract_event_based_actor : public scheduled_actor
void
resume
(
util
::
fiber
*
,
resume_callback
*
callback
)
/*override*/
;
virtual
void
on_exit
()
=
0
;
private:
void
handle_message
(
std
::
unique_ptr
<
queue_node
>&
node
,
...
...
cppa/detail/scheduled_actor.hpp
View file @
e09e8634
...
...
@@ -65,6 +65,15 @@ class scheduled_actor : public abstract_actor<local_actor>
void
request_timeout
(
const
util
::
duration
&
d
);
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
;
...
...
cppa/event_based_actor.hpp
View file @
e09e8634
...
...
@@ -13,7 +13,7 @@ class event_based_actor : public detail::abstract_event_based_actor
become
(
std
::
move
(
rules
));
}
inline
void
become_impl
(
timed_invoke_rules
&
rules
)
inline
void
become_impl
(
timed_invoke_rules
&
&
rules
)
{
become
(
std
::
move
(
rules
));
}
...
...
@@ -27,11 +27,11 @@ class event_based_actor : public detail::abstract_event_based_actor
protected:
void
unbecome
()
/*override*/
;
void
unbecome
();
void
become
(
invoke_rules
&&
behavior
)
/*override*/
;
void
become
(
invoke_rules
&&
behavior
);
void
become
(
timed_invoke_rules
&&
behavior
)
/*override*/
;
void
become
(
timed_invoke_rules
&&
behavior
);
template
<
typename
Head
,
typename
...
Tail
>
void
become
(
invoke_rules
&&
rules
,
Head
&&
head
,
Tail
&&
...
tail
)
...
...
@@ -45,6 +45,8 @@ class event_based_actor : public detail::abstract_event_based_actor
virtual
void
init
()
=
0
;
virtual
void
on_exit
();
template
<
typename
Scheduler
>
abstract_event_based_actor
*
attach_to_scheduler
(
void
(
*
enqueue_fun
)(
Scheduler
*
,
scheduled_actor
*
),
...
...
@@ -55,21 +57,35 @@ class event_based_actor : public detail::abstract_event_based_actor
return
this
;
}
pr
ivate
:
pr
otected
:
// provoke compiler errors for usage of receive() and related functions
template
<
typename
...
Args
>
void
receive
(
Args
&&
...
rules
);
void
receive
(
Args
&&
...)
{
static_assert
(
sizeof
...(
Args
)
<
0
,
"You shall not use receive in an event-based actor. "
"Use become()/unbecome() instead."
);
}
template
<
typename
...
Args
>
void
receive_loop
(
Args
&&
...
rules
);
void
receive_loop
(
Args
&&
...
args
)
{
receive
(
std
::
forward
<
Args
>
(
args
)...);
}
template
<
typename
Statement
>
void
receive_while
(
Statement
&&
stmt
);
template
<
typename
...
Args
>
void
receive_while
(
Args
&&
...
args
)
{
receive
(
std
::
forward
<
Args
>
(
args
)...);
}
template
<
typename
...
Args
>
void
do_receive
(
Args
&&
...
args
);
void
do_receive
(
Args
&&
...
args
)
{
receive
(
std
::
forward
<
Args
>
(
args
)...);
}
};
...
...
cppa/util/either.hpp
View file @
e09e8634
...
...
@@ -141,6 +141,35 @@ class either
return
*
this
;
}
either
&
operator
=
(
either
&&
other
)
{
if
(
m_is_left
==
other
.
m_is_left
)
{
if
(
m_is_left
)
{
left
()
=
std
::
move
(
other
.
left
());
}
else
{
right
()
=
std
::
move
(
other
.
right
());
}
}
else
{
destroy
();
m_is_left
=
other
.
m_is_left
;
if
(
other
.
m_is_left
)
{
cr_left
(
std
::
move
(
other
.
left
()));
}
else
{
cr_right
(
std
::
move
(
other
.
right
()));
}
}
return
*
this
;
}
inline
bool
is_left
()
const
{
return
m_is_left
;
...
...
@@ -153,21 +182,25 @@ class either
Left
&
left
()
{
check_flag
(
true
,
"left"
);
return
m_left
;
}
const
Left
&
left
()
const
{
check_flag
(
true
,
"left"
);
return
m_left
;
}
Right
&
right
()
{
check_flag
(
false
,
"right"
);
return
m_right
;
}
const
Right
&
right
()
const
{
check_flag
(
false
,
"right"
);
return
m_right
;
}
...
...
cppa/util/singly_linked_list.hpp
View file @
e09e8634
...
...
@@ -16,23 +16,18 @@ class singly_linked_list
typedef
T
element_type
;
singly_linked_list
()
:
m_head
(
0
),
m_tail
(
0
)
{
}
singly_linked_list
()
:
m_head
(
nullptr
),
m_tail
(
nullptr
)
{
}
~
singly_linked_list
()
{
while
(
m_head
)
{
T
*
next
=
m_head
->
next
;
delete
m_head
;
m_head
=
next
;
}
clear
();
}
inline
bool
empty
()
const
{
return
m_head
==
0
;
}
inline
bool
empty
()
const
{
return
m_head
==
nullptr
;
}
void
push_back
(
element_type
*
what
)
{
what
->
next
=
0
;
what
->
next
=
nullptr
;
if
(
m_tail
)
{
m_tail
->
next
=
what
;
...
...
@@ -48,10 +43,21 @@ class singly_linked_list
{
element_type
*
first
=
m_head
;
element_type
*
last
=
m_tail
;
m_head
=
m_tail
=
0
;
m_head
=
m_tail
=
nullptr
;
return
{
first
,
last
};
}
void
clear
()
{
while
(
m_head
)
{
T
*
next
=
m_head
->
next
;
delete
m_head
;
m_head
=
next
;
}
m_head
=
m_tail
=
nullptr
;
}
};
}
}
// namespace cppa::util
...
...
src/abstract_event_based_actor.cpp
View file @
e09e8634
...
...
@@ -14,25 +14,34 @@ void abstract_event_based_actor::dequeue(timed_invoke_rules&)
}
void
abstract_event_based_actor
::
handle_message
(
std
::
unique_ptr
<
queue_node
>&
node
,
invoke_rules
&
behavior
)
invoke_rules
&
behavior
)
{
// no need to handle result
(
void
)
dq
(
node
,
behavior
,
m_buffer
);
}
void
abstract_event_based_actor
::
handle_message
(
std
::
unique_ptr
<
queue_node
>&
node
,
timed_invoke_rules
&
behavior
)
timed_invoke_rules
&
behavior
)
{
// request timeout only if we're running short on messages
if
(
m_mailbox
.
empty
()
&&
has_pending_timeout
()
==
false
)
{
request_timeout
(
behavior
.
timeout
());
}
switch
(
dq
(
node
,
behavior
,
m_buffer
))
{
case
dq_timeout_occured
:
{
behavior
.
handle_timeout
();
// fall through
}
case
dq_done
:
{
// callback might have called become()/unbecome()
// request next timeout if needed
if
(
!
m_loop_stack
.
empty
())
{
if
(
m_loop_stack
.
top
().
is_right
())
{
request_timeout
(
m_loop_stack
.
top
().
right
().
timeout
());
}
}
break
;
}
default:
break
;
}
...
...
@@ -52,10 +61,12 @@ void abstract_event_based_actor::handle_message(std::unique_ptr<queue_node>& nod
void
abstract_event_based_actor
::
resume
(
util
::
fiber
*
,
resume_callback
*
callback
)
{
set_self
(
this
);
auto
done_cb
=
[
&
]()
{
m_state
.
store
(
scheduled_actor
::
done
);
while
(
!
m_loop_stack
.
empty
())
m_loop_stack
.
pop
();
on_exit
();
callback
->
exec_done
();
};
...
...
src/event_based_actor.cpp
View file @
e09e8634
...
...
@@ -2,6 +2,10 @@
namespace
cppa
{
void
event_based_actor
::
on_exit
()
{
}
void
event_based_actor
::
unbecome
()
{
if
(
!
m_loop_stack
.
empty
())
m_loop_stack
.
pop
();
...
...
@@ -9,11 +13,13 @@ void event_based_actor::unbecome()
void
event_based_actor
::
become
(
invoke_rules
&&
behavior
)
{
reset_timeout
();
m_loop_stack
.
push
(
std
::
move
(
behavior
));
}
void
event_based_actor
::
become
(
timed_invoke_rules
&&
behavior
)
{
request_timeout
(
behavior
.
timeout
());
m_loop_stack
.
push
(
std
::
move
(
behavior
));
}
...
...
src/scheduled_actor.cpp
View file @
e09e8634
...
...
@@ -133,7 +133,11 @@ scheduled_actor::dq_result scheduled_actor::dq(std::unique_ptr<queue_node>& node
// m_active_timeout_id is already invalid
m_has_pending_timeout_request
=
false
;
// restore mailbox before calling client
if
(
!
buffer
.
empty
())
m_mailbox
.
push_front
(
std
::
move
(
buffer
));
if
(
!
buffer
.
empty
())
{
m_mailbox
.
push_front
(
std
::
move
(
buffer
));
buffer
.
clear
();
}
return
dq_timeout_occured
;
}
default:
break
;
...
...
@@ -144,7 +148,11 @@ scheduled_actor::dq_result scheduled_actor::dq(std::unique_ptr<queue_node>& node
m_last_dequeued
=
std
::
move
(
node
->
msg
);
m_last_sender
=
std
::
move
(
node
->
sender
);
// restore mailbox before invoking imd
if
(
!
buffer
.
empty
())
m_mailbox
.
push_front
(
std
::
move
(
buffer
));
if
(
!
buffer
.
empty
())
{
m_mailbox
.
push_front
(
std
::
move
(
buffer
));
buffer
.
clear
();
}
// expire pending request
if
(
m_has_pending_timeout_request
)
{
...
...
unit_testing/test__spawn.cpp
View file @
e09e8634
...
...
@@ -25,55 +25,78 @@ using namespace cppa;
class
event_testee
:
public
event_based_actor
{
invoke_rules
wait4string
()
{
return
on
<
std
::
string
>
()
>>
[
=
](
const
std
::
string
&
value
)
{
cout
<<
"event_testee[string]: "
<<
value
<<
endl
;
// switch back to wait4int
unbecome
();
unbecome
();
};
}
invoke_rules
wait4float
()
{
return
on
<
float
>
()
>>
[
=
](
float
value
)
{
cout
<<
"event_testee[float]: "
<<
value
<<
endl
;
become
(
wait4string
());
};
}
invoke_rules
wait4int
()
{
return
on
<
int
>
()
>>
[
=
](
int
value
)
{
cout
<<
"event_testee[int]: "
<<
value
<<
endl
;
become
(
wait4float
());
};
}
public:
void
on_exit
()
{
cout
<<
"event_testee::on_exit()"
<<
endl
;
}
void
init
()
{
become
(
on
<
int
>
()
>>
[
&
](
int
i
)
{
// do NOT call receive() here!
// this would hijack the worker thread
become
(
on
<
int
>
()
>>
[
&
](
int
i2
)
{
cout
<<
"event testee: ("
<<
i
<<
", "
<<
i2
<<
")"
<<
endl
;
unbecome
();
},
on
<
float
>
()
>>
[
&
](
float
f
)
{
cout
<<
"event testee: ("
<<
i
<<
", "
<<
f
<<
")"
<<
endl
;
become
(
on
<
float
>
()
>>
[
&
]()
{
// switch back to the outer behavior
unbecome
();
unbecome
();
},
others
()
>>
[]()
{
cout
<<
"event testee[line "
<<
__LINE__
<<
"]: "
<<
to_string
(
last_received
())
<<
endl
;
}
);
}
);
},
others
()
>>
[]()
{
cout
<<
"event testee[line "
<<
__LINE__
<<
"]: "
<<
to_string
(
last_received
())
<<
endl
;
}
);
cout
<<
"event_testee::init()"
<<
endl
;
become
(
wait4int
());
}
};
event_based_actor
*
event_testee2
()
{
struct
impl
:
event_based_actor
{
int
num_timeouts
;
impl
()
:
num_timeouts
(
0
)
{
}
void
init
()
{
become
(
others
()
>>
[]()
{
cout
<<
"event testee2: "
<<
to_string
(
last_received
())
<<
endl
;
},
after
(
std
::
chrono
::
milliseconds
(
50
))
>>
[
this
]()
{
cout
<<
"testee2 received timeout nr. "
<<
(
num_timeouts
+
1
)
<<
endl
;
if
(
++
num_timeouts
>=
5
)
unbecome
();
}
);
}
};
return
new
impl
;
}
class
testee_behavior
:
public
actor_behavior
{
...
...
@@ -81,12 +104,27 @@ class testee_behavior : public actor_behavior
void
act
()
{
cout
<<
"testee_behavior::act()"
<<
endl
;
receive_loop
(
after
(
std
::
chrono
::
milliseconds
(
10
))
>>
[](
)
on
<
int
>
()
>>
[
&
](
int
i
)
{
quit
(
exit_reason
::
user_defined
);
cout
<<
"testee_behavior[int]: "
<<
i
<<
endl
;
receive
(
on
<
float
>
()
>>
[
&
](
float
f
)
{
cout
<<
"testee_behavior[float]: "
<<
f
<<
endl
;
receive
(
on
<
std
::
string
>
()
>>
[
&
](
const
std
::
string
&
str
)
{
cout
<<
"testee_behavior[string]: "
<<
str
<<
endl
;
}
);
}
);
}
);
}
...
...
@@ -142,27 +180,41 @@ void testee3(actor_ptr parent)
);
}
template
<
class
Testee
>
void
behavior_test
()
{
std
::
string
testee_name
=
detail
::
to_uniform_name
(
typeid
(
Testee
));
cout
<<
"behavior_test<"
<<
testee_name
<<
">()"
<<
endl
;
auto
et
=
spawn
(
new
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
(
":Exit"
),
exit_reason
::
user_defined
);
await_all_others_done
();
cout
<<
endl
;
}
size_t
test__spawn
()
{
CPPA_TEST
(
test__spawn
);
spawn
(
testee1
);
spawn
(
new
testee_behavior
);
//
spawn(testee1);
//
spawn(new testee_behavior);
await_all_others_done
();
//
await_all_others_done();
auto
et
=
spawn
(
new
event_testee
);
send
(
et
,
42
);
send
(
et
,
24
);
send
(
et
,
42
);
send
(
et
,
.24
f
);
send
(
et
,
"hello event actor"
);
send
(
et
,
42
);
send
(
et
,
24.
f
);
send
(
et
,
"hello event actor"
);
send
(
et
,
atom
(
":Exit"
),
exit_reason
::
user_defined
);
//spawn(event_testee2());
await_all_others_done
();
//auto et = spawn(new event_testee);
behavior_test
<
testee_behavior
>
();
behavior_test
<
event_testee
>
();
return
CPPA_TEST_RESULT
;
...
...
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