Skip to content

Commit

Permalink
Avoid deadlock from nested NotifyWhenAutowried calls by postponing sa…
Browse files Browse the repository at this point in the history
…tisfied call until after exit of FindByTypeRecursiveUnsafe.
  • Loading branch information
Gabriel Hare committed Aug 23, 2014
1 parent e965fd3 commit 4706051
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 3 deletions.
9 changes: 7 additions & 2 deletions autowiring/CoreContext.h
Expand Up @@ -917,13 +917,14 @@ class CoreContext:
/// </remarks>
template<class T, class Fn>
const AutowirableSlotFn<T, Fn>* NotifyWhenAutowired(Fn&& listener) {
bool found = false;
AutowirableSlotFn<T, Fn>* retVal = nullptr;
{
std::lock_guard<std::mutex> lk(m_stateBlock->m_lock);
FindByTypeRecursiveUnsafe(AnySharedPointerT<T>(),
[this, &listener, &retVal](AnySharedPointer& reference) {
[this, &listener, &retVal, &found](AnySharedPointer& reference) {
if (reference) {
listener();
found = true;
} else {
retVal = MakeAutowirableSlotFn<T>(
shared_from_this(),
Expand All @@ -933,6 +934,10 @@ class CoreContext:
}
});
}
if (found)
// Make call outside of lock
// NOTE: existential guarantees of context enable this.
listener();
return retVal;
}

Expand Down
2 changes: 1 addition & 1 deletion src/autowiring/CoreContext.cpp
Expand Up @@ -295,7 +295,7 @@ void CoreContext::FindByTypeRecursiveUnsafe(AnySharedPointer&& reference, const
if (m_pParent) {
std::lock_guard<std::mutex> guard(m_pParent->m_stateBlock->m_lock);
// Recurse while holding lock on this context
// NOTE: Deadlock is only possible if there is a simultaneous descending locked chain,
// NOTE: Racing Deadlock is only possible if there is a simultaneous descending locked chain,
// but by definition of contexts this is forbidden.
m_pParent->FindByTypeRecursiveUnsafe(std::move(reference), terminal);
} else {
Expand Down

0 comments on commit 4706051

Please sign in to comment.