Correct handling of failed lazy_ptr constructors.

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

Change-Id: I75353e5e511769a96e4332f7f60887f6559c1cd5
This commit is contained in:
Sean Keely
2020-05-06 23:02:44 -05:00
bovenliggende bccb25fc33
commit 2fbacccaed
2 gewijzigde bestanden met toevoegingen van 17 en 7 verwijderingen
@@ -137,7 +137,7 @@ GpuAgent::GpuAgent(HSAuint32 node, const HsaNodeProperties& node_props)
GpuAgent::~GpuAgent() { GpuAgent::~GpuAgent() {
for (auto& blit : blits_) { for (auto& blit : blits_) {
if (blit.created()) { if (!blit.empty()) {
hsa_status_t status = blit->Destroy(*this); hsa_status_t status = blit->Destroy(*this);
assert(status == HSA_STATUS_SUCCESS); assert(status == HSA_STATUS_SUCCESS);
} }
@@ -680,7 +680,7 @@ hsa_status_t GpuAgent::DmaFill(void* ptr, uint32_t value, size_t count) {
hsa_status_t GpuAgent::EnableDmaProfiling(bool enable) { hsa_status_t GpuAgent::EnableDmaProfiling(bool enable) {
for (auto& blit : blits_) { for (auto& blit : blits_) {
if (blit.created()) { if (!blit.empty()) {
const hsa_status_t stat = blit->EnableProfiling(enable); const hsa_status_t stat = blit->EnableProfiling(enable);
if (stat != HSA_STATUS_SUCCESS) { if (stat != HSA_STATUS_SUCCESS) {
return stat; return stat;
@@ -87,6 +87,7 @@ template <typename T> class lazy_ptr {
const std::unique_ptr<T>& operator->() const { const std::unique_ptr<T>& operator->() const {
make(true); make(true);
assert(obj != nullptr && "Null dereference through lazy_ptr.");
return obj; return obj;
} }
@@ -107,7 +108,17 @@ template <typename T> class lazy_ptr {
void touch() const { make(false); } void touch() const { make(false); }
// Tells if the lazy object has been constructed or not. // 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: private:
mutable std::unique_ptr<T> obj; mutable std::unique_ptr<T> obj;
@@ -122,16 +133,15 @@ template <typename T> class lazy_ptr {
return; return;
} }
MAKE_SCOPE_GUARD([&]() { lock.Release(); }); MAKE_SCOPE_GUARD([&]() { lock.Release(); });
if (obj != nullptr) return; if (func == nullptr) return;
T* ptr = func(); T* ptr = func();
std::atomic_thread_fence(std::memory_order_release);
obj.reset(ptr); obj.reset(ptr);
std::atomic_thread_fence(std::memory_order_release);
func = nullptr; func = nullptr;
} }
__forceinline void make(bool block) const { __forceinline void make(bool block) const {
std::atomic_thread_fence(std::memory_order_acquire); if (!created()) {
if (obj == nullptr) {
make_body(block); make_body(block);
} }
} }