Commit a4f60453 authored by Dominik Charousset's avatar Dominik Charousset

fixed timeout handling in become() API, fixes #116

parent ec8cc487
...@@ -122,14 +122,30 @@ class behavior_stack_based_impl : public single_timeout<Base, Subtype> { ...@@ -122,14 +122,30 @@ class behavior_stack_based_impl : public single_timeout<Base, Subtype> {
return m_bhvr_stack; return m_bhvr_stack;
} }
/**************************************************************************
* extended timeout handling (handle_timeout mem fun) *
**************************************************************************/
void handle_timeout(behavior& bhvr, std::uint32_t timeout_id) {
if (this->is_active_timeout(timeout_id)) {
this->reset_timeout();
bhvr.handle_timeout();
// request next timeout if behavior stack is not empty
// and timeout handler did not set a new timeout, e.g.,
// by calling become()
if (!this->has_active_timeout() && has_behavior()) {
this->request_timeout(get_behavior().timeout());
}
}
}
private: private:
void do_become(behavior_type bhvr, bool discard_old) { void do_become(behavior_type bhvr, bool discard_old) {
if (discard_old) this->m_bhvr_stack.pop_async_back(); if (discard_old) this->m_bhvr_stack.pop_async_back();
this->reset_timeout(); // since we know we extend single_timeout, we can be sure
if (bhvr.timeout().valid()) { // request_timeout simply resets the timeout when it's invalid
this->request_timeout(bhvr.timeout()); this->request_timeout(bhvr.timeout());
}
this->m_bhvr_stack.push_back(std::move(unbox(bhvr))); this->m_bhvr_stack.push_back(std::move(unbox(bhvr)));
} }
......
...@@ -79,15 +79,12 @@ class single_timeout : public Base { ...@@ -79,15 +79,12 @@ class single_timeout : public Base {
return waits_for_timeout(tid); return waits_for_timeout(tid);
} }
inline void reset_timeout() { inline bool has_active_timeout() const {
m_has_timeout = false; return m_has_timeout;
} }
inline void handle_timeout(behavior& bhvr, std::uint32_t timeout_id) { inline void reset_timeout() {
if (timeout_id == m_timeout_id) {
m_has_timeout = false; m_has_timeout = false;
bhvr.handle_timeout();
}
} }
protected: protected:
......
...@@ -62,7 +62,8 @@ actor spawn_event_testee2(actor parent) { ...@@ -62,7 +62,8 @@ actor spawn_event_testee2(actor parent) {
behavior wait4timeout(int remaining) { behavior wait4timeout(int remaining) {
CPPA_LOG_TRACE(CPPA_ARG(remaining)); CPPA_LOG_TRACE(CPPA_ARG(remaining));
return { return {
after(chrono::milliseconds(50)) >> [=] { after(chrono::milliseconds(1)) >> [=] {
CPPA_PRINT(CPPA_ARG(remaining));
if (remaining == 1) { if (remaining == 1) {
send(parent, atom("t2done")); send(parent, atom("t2done"));
quit(); quit();
...@@ -887,13 +888,32 @@ void test_spawn() { ...@@ -887,13 +888,32 @@ void test_spawn() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
spawn<high_priority_testee_class, priority_aware>(); spawn<high_priority_testee_class, priority_aware>();
self->await_all_other_actors_done(); self->await_all_other_actors_done();
// don't try this at home, kids // test sending message to self via scoped_actor
self->send(self, atom("check")); self->send(self, atom("check"));
self->receive ( self->receive (
on(atom("check")) >> [] { on(atom("check")) >> [] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
} }
); );
CPPA_CHECKPOINT();
CPPA_PRINT("check whether timeouts trigger more than once");
auto counter = make_shared<int>(0);
auto sleeper = self->spawn<monitored>([=](event_based_actor* s) {
return after(std::chrono::milliseconds(1)) >> [=] {
CPPA_PRINT("received timeout #" << (*counter + 1));
if (++*counter > 3) {
CPPA_CHECKPOINT();
s->quit();
}
};
});
self->receive(
[&](const down_msg& msg) {
CPPA_CHECK_EQUAL(msg.source, sleeper);
CPPA_CHECK_EQUAL(msg.reason, exit_reason::normal);
}
);
CPPA_CHECKPOINT();
} }
int main() { int main() {
......
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