Fix unregister issue
This commit is contained in:
@@ -20,8 +20,12 @@ static void AWSDbg(const char* fmt, ...) {
|
||||
}
|
||||
|
||||
// ── ANSUtilities handle registry ──
|
||||
static std::unordered_map<ANSCENTER::ANSUtilities*, int>& UtilHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSUtilities*, int> s;
|
||||
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||
// and causes subsequent Unregister calls to return false without deleting.
|
||||
// Prevents double-free when two threads race Release on the same handle.
|
||||
struct UtilEntry { int refcount; bool destructionStarted; };
|
||||
static std::unordered_map<ANSCENTER::ANSUtilities*, UtilEntry>& UtilHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSUtilities*, UtilEntry> s;
|
||||
return s;
|
||||
}
|
||||
static std::mutex& UtilHandleRegistryMutex() {
|
||||
@@ -35,14 +39,15 @@ static std::condition_variable& UtilHandleRegistryCV() {
|
||||
|
||||
static void RegisterUtilHandle(ANSCENTER::ANSUtilities* h) {
|
||||
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
||||
UtilHandleRegistry()[h] = 1;
|
||||
UtilHandleRegistry()[h] = { 1, false };
|
||||
}
|
||||
|
||||
static ANSCENTER::ANSUtilities* AcquireUtilHandle(ANSCENTER::ANSUtilities* h) {
|
||||
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
||||
auto it = UtilHandleRegistry().find(h);
|
||||
if (it == UtilHandleRegistry().end()) return nullptr;
|
||||
it->second++;
|
||||
if (it->second.destructionStarted) return nullptr;
|
||||
it->second.refcount++;
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -50,23 +55,26 @@ static bool ReleaseUtilHandleRef(ANSCENTER::ANSUtilities* h) {
|
||||
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
||||
auto it = UtilHandleRegistry().find(h);
|
||||
if (it == UtilHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
if (it->second <= 0) {
|
||||
UtilHandleRegistry().erase(it);
|
||||
it->second.refcount--;
|
||||
if (it->second.refcount <= 0) {
|
||||
UtilHandleRegistryCV().notify_all();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return false; // Only Unregister deletes. Ref drop just signals the CV.
|
||||
}
|
||||
|
||||
static bool UnregisterUtilHandle(ANSCENTER::ANSUtilities* h) {
|
||||
std::unique_lock<std::mutex> lk(UtilHandleRegistryMutex());
|
||||
auto it = UtilHandleRegistry().find(h);
|
||||
if (it == UtilHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
if (it->second.destructionStarted) {
|
||||
// Another thread is already tearing this handle down; let it own the delete.
|
||||
return false;
|
||||
}
|
||||
it->second.destructionStarted = true;
|
||||
it->second.refcount--;
|
||||
bool ok = UtilHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||
auto it2 = UtilHandleRegistry().find(h);
|
||||
return it2 == UtilHandleRegistry().end() || it2->second <= 0;
|
||||
return it2 == UtilHandleRegistry().end() || it2->second.refcount <= 0;
|
||||
});
|
||||
if (!ok) {
|
||||
OutputDebugStringA("WARNING: UnregisterUtilHandle timed out waiting for in-flight operations\n");
|
||||
@@ -87,8 +95,13 @@ public:
|
||||
};
|
||||
|
||||
// ── ANSAWSS3 handle registry ──
|
||||
static std::unordered_map<ANSCENTER::ANSAWSS3*, int>& AWSHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSAWSS3*, int> s;
|
||||
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||
// and causes subsequent Unregister calls to return false without deleting.
|
||||
// Prevents double-free when two threads race Release on the same handle
|
||||
// (e.g. LabVIEW double-Release on the same wire, or Release during heap reuse).
|
||||
struct AWSEntry { int refcount; bool destructionStarted; };
|
||||
static std::unordered_map<ANSCENTER::ANSAWSS3*, AWSEntry>& AWSHandleRegistry() {
|
||||
static std::unordered_map<ANSCENTER::ANSAWSS3*, AWSEntry> s;
|
||||
return s;
|
||||
}
|
||||
static std::mutex& AWSHandleRegistryMutex() {
|
||||
@@ -102,14 +115,15 @@ static std::condition_variable& AWSHandleRegistryCV() {
|
||||
|
||||
static void RegisterAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
||||
AWSHandleRegistry()[h] = 1;
|
||||
AWSHandleRegistry()[h] = { 1, false };
|
||||
AWSDbg("[ANSAWS] Register: handle=%p (uint=%llu) registrySize=%zu\n",
|
||||
(void*)h, (unsigned long long)(uintptr_t)h, AWSHandleRegistry().size());
|
||||
}
|
||||
|
||||
static bool IsAWSHandleLive(ANSCENTER::ANSAWSS3* h) {
|
||||
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
||||
return AWSHandleRegistry().find(h) != AWSHandleRegistry().end();
|
||||
auto it = AWSHandleRegistry().find(h);
|
||||
return it != AWSHandleRegistry().end() && !it->second.destructionStarted;
|
||||
}
|
||||
|
||||
static ANSCENTER::ANSAWSS3* AcquireAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||
@@ -118,16 +132,20 @@ static ANSCENTER::ANSAWSS3* AcquireAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||
if (it == AWSHandleRegistry().end()) {
|
||||
AWSDbg("[ANSAWS] Acquire FAIL: handle=%p (uint=%llu) NOT in registry. registrySize=%zu\n",
|
||||
(void*)h, (unsigned long long)(uintptr_t)h, AWSHandleRegistry().size());
|
||||
// dump current registry contents so you can compare what IS there
|
||||
size_t i = 0;
|
||||
for (auto& kv : AWSHandleRegistry()) {
|
||||
AWSDbg("[ANSAWS] registry[%zu] = %p (uint=%llu) refcount=%d\n",
|
||||
i++, (void*)kv.first, (unsigned long long)(uintptr_t)kv.first, kv.second);
|
||||
AWSDbg("[ANSAWS] registry[%zu] = %p (uint=%llu) refcount=%d destructionStarted=%d\n",
|
||||
i++, (void*)kv.first, (unsigned long long)(uintptr_t)kv.first,
|
||||
kv.second.refcount, kv.second.destructionStarted ? 1 : 0);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
it->second++;
|
||||
AWSDbg("[ANSAWS] Acquire OK: handle=%p refcount=%d\n", (void*)h, it->second);
|
||||
if (it->second.destructionStarted) {
|
||||
AWSDbg("[ANSAWS] Acquire FAIL: handle=%p is being destroyed (destructionStarted=true)\n", (void*)h);
|
||||
return nullptr;
|
||||
}
|
||||
it->second.refcount++;
|
||||
AWSDbg("[ANSAWS] Acquire OK: handle=%p refcount=%d\n", (void*)h, it->second.refcount);
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -135,13 +153,11 @@ static bool ReleaseAWSHandleRef(ANSCENTER::ANSAWSS3* h) {
|
||||
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
||||
auto it = AWSHandleRegistry().find(h);
|
||||
if (it == AWSHandleRegistry().end()) return false;
|
||||
it->second--;
|
||||
if (it->second <= 0) {
|
||||
AWSHandleRegistry().erase(it);
|
||||
it->second.refcount--;
|
||||
if (it->second.refcount <= 0) {
|
||||
AWSHandleRegistryCV().notify_all();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return false; // Only Unregister deletes. Ref drop just signals the CV.
|
||||
}
|
||||
|
||||
static bool UnregisterAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||
@@ -151,11 +167,16 @@ static bool UnregisterAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||
AWSDbg("[ANSAWS] Unregister: handle=%p NOT in registry (already gone)\n", (void*)h);
|
||||
return false;
|
||||
}
|
||||
AWSDbg("[ANSAWS] Unregister: handle=%p starting (refcount before=%d)\n", (void*)h, it->second);
|
||||
it->second--;
|
||||
if (it->second.destructionStarted) {
|
||||
AWSDbg("[ANSAWS] Unregister: handle=%p already being destroyed by another thread, returning false\n", (void*)h);
|
||||
return false;
|
||||
}
|
||||
AWSDbg("[ANSAWS] Unregister: handle=%p starting (refcount before=%d)\n", (void*)h, it->second.refcount);
|
||||
it->second.destructionStarted = true;
|
||||
it->second.refcount--;
|
||||
bool ok = AWSHandleRegistryCV().wait_for(lk, std::chrono::seconds(120), [&]() {
|
||||
auto it2 = AWSHandleRegistry().find(h);
|
||||
return it2 == AWSHandleRegistry().end() || it2->second <= 0;
|
||||
return it2 == AWSHandleRegistry().end() || it2->second.refcount <= 0;
|
||||
});
|
||||
if (!ok) {
|
||||
OutputDebugStringA("WARNING: UnregisterAWSHandle timed out waiting for in-flight operations\n");
|
||||
|
||||
Reference in New Issue
Block a user