-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix rules engine unsubscribe race condition #731
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,21 +44,19 @@ rule_thread_pool_t::~rule_thread_pool_t() | |
shutdown(); | ||
} | ||
|
||
void rule_thread_pool_t::shutdown() | ||
void rule_thread_pool_t::wait_for_rules_to_finish() | ||
{ | ||
if (m_threads.size() == 0) | ||
{ | ||
return; | ||
} | ||
|
||
// Wait for any scheduled rules to finish executing. Once the rule | ||
// has finished, its worker thread will go into a wait state (not busy). | ||
// Once all workers are not busy, then we can exit if there are no pending | ||
// rule invocations. If there are invocations left, then wait for them to | ||
// be executed and check again. | ||
auto start_shutdown_time = gaia::common::timer_t::get_time_point(); | ||
|
||
unique_lock lock(m_lock, defer_lock); | ||
wait_for_rules_to_finish(lock); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks to me like you don't really need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really don't want anyone messing with |
||
lock.unlock(); | ||
} | ||
|
||
// NOTE: Callers must unlock the passed in mutex. | ||
// | ||
// TODO[GAIAPLAT-1020]: Add a configuration setting to limit the time | ||
// we will wait for all rules to execute. | ||
void rule_thread_pool_t::wait_for_rules_to_finish(std::unique_lock<std::mutex>& lock) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, assuming you no longer passed in the lock via There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, this code used to live in the shutdown method and I wanted to preserve its locking behavior exactly. |
||
while (true) | ||
{ | ||
lock.lock(); | ||
|
@@ -70,6 +68,23 @@ void rule_thread_pool_t::shutdown() | |
lock.unlock(); | ||
std::this_thread::yield(); | ||
} | ||
} | ||
|
||
void rule_thread_pool_t::shutdown() | ||
{ | ||
if (m_threads.size() == 0) | ||
{ | ||
return; | ||
} | ||
|
||
auto start_shutdown_time = gaia::common::timer_t::get_time_point(); | ||
|
||
unique_lock lock(m_lock, defer_lock); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that this method doesn't seem to use the lock itself, why can't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. I want it to set |
||
|
||
// Wait for the currently executing rules "graph" to finish executing. This will | ||
// drain the work queues of any rules executing AND any rules that these rules | ||
// may trigger. | ||
wait_for_rules_to_finish(lock); | ||
|
||
m_exit = true; | ||
lock.unlock(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super-dumb question (because I don't know the rules engine code at all): since it seems to be safe to clear the commit trigger before calling
wait_for_rules_to_finish()
(since you do it immediately after clearing the commit trigger), why do we need to callwait_for_rules_to_finish()
before callingset_commit_trigger()
? Is this just a best-effort attempt to execute all existing rule invocations? Is that necessary at this point?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first call to
wait_for_rules_to_finish
is to drain any invocations and any further rules that run because of those invocations. If I were to clear the commit trigger before doing this, I woudn't execute the entire intended graph of rules that were supposed to be run. After the engine is done with that, then it's a best effort to preclude firing any more rules by setting the commit trigger to nullptr. The secondwait_for_rules_to_finish
is to account for the case when some other procedural code made a change that caused a rule to fire before I had the chance to null out the commit trigger.