Skip to content

Commit 72fad65

Browse files
samwarringpixar-oss
authored andcommitted
Fix potential hang that occurs while retreiving the Exec_DefinitionRegistry
singleton. This is a follow-up to a recent change where clients now wait for the definition registry to be fully initialized before attempting to look up computation definitions. There was a chance that a thread could enter the wait state immediately after the condition variable had been notified, thus missing the notification and will wait forever. The registry now holds a mutex while updating the flag, so that all other threads are either awaiting notification, or have yet to read the new flag value. (Internal change: 2365783)
1 parent 8d4d538 commit 72fad65

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

pxr/exec/exec/definitionRegistry.cpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ Exec_DefinitionRegistry::Exec_DefinitionRegistry()
5454

5555
// Callers of Exec_DefinitionRegistry::GetInstance() can now safely return
5656
// a fully-constructed registry.
57-
_isFullyConstructed.store(true);
58-
_isFullyConstructedConditionVariable.notify_all();
57+
_SetInstanceFullyConstructed();
5958
}
6059

6160
// This must be defined in the cpp file, or we get undefined symbols when
@@ -71,15 +70,7 @@ Exec_DefinitionRegistry::GetInstance()
7170
return instance;
7271
}
7372

74-
// Measure time spent waiting for the _isFullyConstructed flag.
75-
TRACE_FUNCTION_SCOPE("Waiting for construction");
76-
77-
// Wait for the registry to be fully constructed.
78-
std::unique_lock<std::mutex> lock(instance._isFullyConstructedMutex);
79-
instance._isFullyConstructedConditionVariable.wait(lock, [&instance] {
80-
return instance._isFullyConstructed.load();
81-
});
82-
73+
instance._WaitForFullConstruction();
8374
return instance;
8475
}
8576

@@ -328,4 +319,26 @@ Exec_DefinitionRegistry::_RegisterBuiltinComputations()
328319
ExecBuiltinComputations->GetComputationTokens().size());
329320
}
330321

322+
void
323+
Exec_DefinitionRegistry::_SetInstanceFullyConstructed()
324+
{
325+
// Even though _isFullyConstructed is an atomic, we still need to protect
326+
// its update with a lock on the mutex, or else other threads might enter
327+
// a wait state after we've notified the condition variable.
328+
std::lock_guard<std::mutex> lock(_isFullyConstructedMutex);
329+
_isFullyConstructed.store(true);
330+
_isFullyConstructedConditionVariable.notify_all();
331+
}
332+
333+
void
334+
Exec_DefinitionRegistry::_WaitForFullConstruction()
335+
{
336+
TRACE_FUNCTION();
337+
338+
std::unique_lock<std::mutex> lock(_isFullyConstructedMutex);
339+
_isFullyConstructedConditionVariable.wait(lock, [this] {
340+
return _isFullyConstructed.load();
341+
});
342+
}
343+
331344
PXR_NAMESPACE_CLOSE_SCOPE

pxr/exec/exec/definitionRegistry.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ class Exec_DefinitionRegistry : public TfWeakBase
123123

124124
void _RegisterBuiltinComputations();
125125

126+
void _SetInstanceFullyConstructed();
127+
128+
void _WaitForFullConstruction();
129+
126130
private:
127131

128132
// These members ensure singleton access returns a fully-constructed

0 commit comments

Comments
 (0)