Correct handling of failed lazy_ptr constructors.

Contructor function must not be attempted twice even if the construction
attempt returns nullptr.

Change-Id: I75353e5e511769a96e4332f7f60887f6559c1cd5


[ROCm/ROCR-Runtime commit: 2fbacccaed]
This commit is contained in:
Sean Keely
2020-05-06 23:02:44 -05:00
parent fbb4e4c2c3
commit 9aa86bb1e4
2 changed files with 17 additions and 7 deletions
@@ -87,6 +87,7 @@ template <typename T> class lazy_ptr {
const std::unique_ptr<T>& operator->() const {
make(true);
assert(obj != nullptr && "Null dereference through lazy_ptr.");
return obj;
}
@@ -107,7 +108,17 @@ template <typename T> class lazy_ptr {
void touch() const { make(false); }
// Tells if the lazy object has been constructed or not.
bool created() const { return obj != nullptr; }
// Construction may fail silently (return nullptr).
bool created() const {
std::atomic_thread_fence(std::memory_order_acquire);
return func == nullptr;
}
// Tells if the lazy object exists or not.
bool empty() const {
std::atomic_thread_fence(std::memory_order_acquire);
return obj == nullptr;
}
private:
mutable std::unique_ptr<T> obj;
@@ -122,16 +133,15 @@ template <typename T> class lazy_ptr {
return;
}
MAKE_SCOPE_GUARD([&]() { lock.Release(); });
if (obj != nullptr) return;
if (func == nullptr) return;
T* ptr = func();
std::atomic_thread_fence(std::memory_order_release);
obj.reset(ptr);
std::atomic_thread_fence(std::memory_order_release);
func = nullptr;
}
__forceinline void make(bool block) const {
std::atomic_thread_fence(std::memory_order_acquire);
if (obj == nullptr) {
if (!created()) {
make_body(block);
}
}