Fix unregister issue
This commit is contained in:
@@ -28,8 +28,12 @@ std::atomic<bool> g_forceNoPool{false};
|
|||||||
|
|
||||||
// Handle registry with refcount — prevents use-after-free when
|
// Handle registry with refcount — prevents use-after-free when
|
||||||
// ReleaseANSRFHandle is called while inference is still running.
|
// ReleaseANSRFHandle is called while inference is still running.
|
||||||
static std::unordered_map<ANSCENTER::ANSFacialRecognition*, int>& FRHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSFacialRecognition*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct FREntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSFacialRecognition*, FREntry>& FRHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSFacialRecognition*, FREntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& FRHandleRegistryMutex() {
|
static std::mutex& FRHandleRegistryMutex() {
|
||||||
@@ -43,14 +47,15 @@ static std::condition_variable& FRHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterFRHandle(ANSCENTER::ANSFacialRecognition* h) {
|
static void RegisterFRHandle(ANSCENTER::ANSFacialRecognition* h) {
|
||||||
std::lock_guard<std::mutex> lk(FRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(FRHandleRegistryMutex());
|
||||||
FRHandleRegistry()[h] = 1;
|
FRHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
static ANSCENTER::ANSFacialRecognition* AcquireFRHandle(ANSCENTER::ANSFacialRecognition* h) {
|
static ANSCENTER::ANSFacialRecognition* AcquireFRHandle(ANSCENTER::ANSFacialRecognition* h) {
|
||||||
std::lock_guard<std::mutex> lk(FRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(FRHandleRegistryMutex());
|
||||||
auto it = FRHandleRegistry().find(h);
|
auto it = FRHandleRegistry().find(h);
|
||||||
if (it == FRHandleRegistry().end()) return nullptr;
|
if (it == FRHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,23 +63,25 @@ static bool ReleaseFRHandleRef(ANSCENTER::ANSFacialRecognition* h) {
|
|||||||
std::lock_guard<std::mutex> lk(FRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(FRHandleRegistryMutex());
|
||||||
auto it = FRHandleRegistry().find(h);
|
auto it = FRHandleRegistry().find(h);
|
||||||
if (it == FRHandleRegistry().end()) return false;
|
if (it == FRHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
FRHandleRegistry().erase(it);
|
|
||||||
FRHandleRegistryCV().notify_all();
|
FRHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterFRHandle(ANSCENTER::ANSFacialRecognition* h) {
|
static bool UnregisterFRHandle(ANSCENTER::ANSFacialRecognition* h) {
|
||||||
std::unique_lock<std::mutex> lk(FRHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(FRHandleRegistryMutex());
|
||||||
auto it = FRHandleRegistry().find(h);
|
auto it = FRHandleRegistry().find(h);
|
||||||
if (it == FRHandleRegistry().end()) return false;
|
if (it == FRHandleRegistry().end()) return false;
|
||||||
it->second--;
|
if (it->second.destructionStarted) {
|
||||||
|
return false; // Another thread already owns the delete.
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--;
|
||||||
bool ok = FRHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
bool ok = FRHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = FRHandleRegistry().find(h);
|
auto it2 = FRHandleRegistry().find(h);
|
||||||
return it2 == FRHandleRegistry().end() || it2->second <= 0;
|
return it2 == FRHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterFRHandle timed out waiting for in-flight inference\n");
|
OutputDebugStringA("WARNING: UnregisterFRHandle timed out waiting for in-flight inference\n");
|
||||||
|
|||||||
@@ -9,8 +9,12 @@
|
|||||||
|
|
||||||
// Handle registry with refcount — prevents use-after-free when
|
// Handle registry with refcount — prevents use-after-free when
|
||||||
// ReleaseANSLLMHandle is called while an operation is still running.
|
// ReleaseANSLLMHandle is called while an operation is still running.
|
||||||
static std::unordered_map<ANSCENTER::ANSLLM*, int>& LLMHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSLLM*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct LLMEntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSLLM*, LLMEntry>& LLMHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSLLM*, LLMEntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& LLMHandleRegistryMutex() {
|
static std::mutex& LLMHandleRegistryMutex() {
|
||||||
@@ -24,14 +28,15 @@ static std::condition_variable& LLMHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterLLMHandle(ANSCENTER::ANSLLM* h) {
|
static void RegisterLLMHandle(ANSCENTER::ANSLLM* h) {
|
||||||
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
|
||||||
LLMHandleRegistry()[h] = 1;
|
LLMHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
static ANSCENTER::ANSLLM* AcquireLLMHandle(ANSCENTER::ANSLLM* h) {
|
static ANSCENTER::ANSLLM* AcquireLLMHandle(ANSCENTER::ANSLLM* h) {
|
||||||
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
|
||||||
auto it = LLMHandleRegistry().find(h);
|
auto it = LLMHandleRegistry().find(h);
|
||||||
if (it == LLMHandleRegistry().end()) return nullptr;
|
if (it == LLMHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,23 +44,25 @@ static bool ReleaseLLMHandleRef(ANSCENTER::ANSLLM* h) {
|
|||||||
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
|
||||||
auto it = LLMHandleRegistry().find(h);
|
auto it = LLMHandleRegistry().find(h);
|
||||||
if (it == LLMHandleRegistry().end()) return false;
|
if (it == LLMHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
LLMHandleRegistry().erase(it);
|
|
||||||
LLMHandleRegistryCV().notify_all();
|
LLMHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterLLMHandle(ANSCENTER::ANSLLM* h) {
|
static bool UnregisterLLMHandle(ANSCENTER::ANSLLM* h) {
|
||||||
std::unique_lock<std::mutex> lk(LLMHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(LLMHandleRegistryMutex());
|
||||||
auto it = LLMHandleRegistry().find(h);
|
auto it = LLMHandleRegistry().find(h);
|
||||||
if (it == LLMHandleRegistry().end()) return false;
|
if (it == LLMHandleRegistry().end()) return false;
|
||||||
it->second--;
|
if (it->second.destructionStarted) {
|
||||||
|
return false; // Another thread already owns the delete.
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--;
|
||||||
bool ok = LLMHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
bool ok = LLMHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = LLMHandleRegistry().find(h);
|
auto it2 = LLMHandleRegistry().find(h);
|
||||||
return it2 == LLMHandleRegistry().end() || it2->second <= 0;
|
return it2 == LLMHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterLLMHandle timed out waiting for in-flight operations\n");
|
OutputDebugStringA("WARNING: UnregisterLLMHandle timed out waiting for in-flight operations\n");
|
||||||
|
|||||||
@@ -28,8 +28,12 @@ static void WriteWindowsEventLog(const char* message, WORD eventType = EVENTLOG_
|
|||||||
// ReleaseANSALPRHandle is called while inference is still running.
|
// ReleaseANSALPRHandle is called while inference is still running.
|
||||||
// refcount: starts at 1 on Register. AcquireALPRHandle increments,
|
// refcount: starts at 1 on Register. AcquireALPRHandle increments,
|
||||||
// ReleaseALPRHandleRef decrements. Object is destroyed when refcount hits 0.
|
// ReleaseALPRHandleRef decrements. Object is destroyed when refcount hits 0.
|
||||||
static std::unordered_map<ANSCENTER::ANSALPR*, int>& ALPRHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSALPR*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct ALPREntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSALPR*, ALPREntry>& ALPRHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSALPR*, ALPREntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& ALPRHandleRegistryMutex() {
|
static std::mutex& ALPRHandleRegistryMutex() {
|
||||||
@@ -43,46 +47,48 @@ static std::condition_variable& ALPRHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterALPRHandle(ANSCENTER::ANSALPR* h) {
|
static void RegisterALPRHandle(ANSCENTER::ANSALPR* h) {
|
||||||
std::lock_guard<std::mutex> lk(ALPRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(ALPRHandleRegistryMutex());
|
||||||
ALPRHandleRegistry()[h] = 1; // refcount = 1
|
ALPRHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a handle for use (increment refcount). Returns the handle
|
// Acquire a handle for use (increment refcount). Returns the handle
|
||||||
// if valid, nullptr if already released.
|
// if valid, nullptr if already released or being destroyed.
|
||||||
static ANSCENTER::ANSALPR* AcquireALPRHandle(ANSCENTER::ANSALPR* h) {
|
static ANSCENTER::ANSALPR* AcquireALPRHandle(ANSCENTER::ANSALPR* h) {
|
||||||
std::lock_guard<std::mutex> lk(ALPRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(ALPRHandleRegistryMutex());
|
||||||
auto it = ALPRHandleRegistry().find(h);
|
auto it = ALPRHandleRegistry().find(h);
|
||||||
if (it == ALPRHandleRegistry().end()) return nullptr;
|
if (it == ALPRHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release a use of the handle (decrement refcount).
|
// Release a use of the handle (decrement refcount). Only signals the CV;
|
||||||
// Returns true if this was the last reference (caller should destroy).
|
// the object is always deleted by Unregister, never by a stray ref-drop.
|
||||||
static bool ReleaseALPRHandleRef(ANSCENTER::ANSALPR* h) {
|
static bool ReleaseALPRHandleRef(ANSCENTER::ANSALPR* h) {
|
||||||
std::lock_guard<std::mutex> lk(ALPRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(ALPRHandleRegistryMutex());
|
||||||
auto it = ALPRHandleRegistry().find(h);
|
auto it = ALPRHandleRegistry().find(h);
|
||||||
if (it == ALPRHandleRegistry().end()) return false;
|
if (it == ALPRHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
ALPRHandleRegistry().erase(it);
|
|
||||||
ALPRHandleRegistryCV().notify_all();
|
ALPRHandleRegistryCV().notify_all();
|
||||||
return true; // Caller should destroy
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unregister and wait for all in-flight uses to finish.
|
// Unregister and wait for all in-flight uses to finish.
|
||||||
// Decrements the creation refcount and blocks until refcount hits 0.
|
// First caller takes ownership of destruction; subsequent calls return false.
|
||||||
// Returns true if caller should destroy the object.
|
|
||||||
static bool UnregisterALPRHandle(ANSCENTER::ANSALPR* h) {
|
static bool UnregisterALPRHandle(ANSCENTER::ANSALPR* h) {
|
||||||
std::unique_lock<std::mutex> lk(ALPRHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(ALPRHandleRegistryMutex());
|
||||||
auto it = ALPRHandleRegistry().find(h);
|
auto it = ALPRHandleRegistry().find(h);
|
||||||
if (it == ALPRHandleRegistry().end()) return false;
|
if (it == ALPRHandleRegistry().end()) return false;
|
||||||
it->second--; // Remove creation ref
|
if (it->second.destructionStarted) {
|
||||||
// Wait for in-flight inferences to finish (30s timeout as safety net)
|
// Another thread already owns the delete — back off.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--; // Remove creation ref
|
||||||
bool ok = ALPRHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
bool ok = ALPRHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = ALPRHandleRegistry().find(h);
|
auto it2 = ALPRHandleRegistry().find(h);
|
||||||
return it2 == ALPRHandleRegistry().end() || it2->second <= 0;
|
return it2 == ALPRHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterALPRHandle timed out waiting for in-flight inference\n");
|
OutputDebugStringA("WARNING: UnregisterALPRHandle timed out waiting for in-flight inference\n");
|
||||||
|
|||||||
@@ -13,8 +13,12 @@
|
|||||||
|
|
||||||
// Handle registry with refcount — prevents use-after-free when
|
// Handle registry with refcount — prevents use-after-free when
|
||||||
// ReleaseANSMOTHandle is called while an operation is still running.
|
// ReleaseANSMOTHandle is called while an operation is still running.
|
||||||
static std::unordered_map<ANSCENTER::ANSMOT*, int>& MOTHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSMOT*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct MOTEntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSMOT*, MOTEntry>& MOTHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSMOT*, MOTEntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& MOTHandleRegistryMutex() {
|
static std::mutex& MOTHandleRegistryMutex() {
|
||||||
@@ -28,14 +32,15 @@ static std::condition_variable& MOTHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterMOTHandle(ANSCENTER::ANSMOT* h) {
|
static void RegisterMOTHandle(ANSCENTER::ANSMOT* h) {
|
||||||
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
||||||
MOTHandleRegistry()[h] = 1;
|
MOTHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
static ANSCENTER::ANSMOT* AcquireMOTHandle(ANSCENTER::ANSMOT* h) {
|
static ANSCENTER::ANSMOT* AcquireMOTHandle(ANSCENTER::ANSMOT* h) {
|
||||||
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
||||||
auto it = MOTHandleRegistry().find(h);
|
auto it = MOTHandleRegistry().find(h);
|
||||||
if (it == MOTHandleRegistry().end()) return nullptr;
|
if (it == MOTHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,23 +48,25 @@ static bool ReleaseMOTHandleRef(ANSCENTER::ANSMOT* h) {
|
|||||||
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
|
||||||
auto it = MOTHandleRegistry().find(h);
|
auto it = MOTHandleRegistry().find(h);
|
||||||
if (it == MOTHandleRegistry().end()) return false;
|
if (it == MOTHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
MOTHandleRegistry().erase(it);
|
|
||||||
MOTHandleRegistryCV().notify_all();
|
MOTHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterMOTHandle(ANSCENTER::ANSMOT* h) {
|
static bool UnregisterMOTHandle(ANSCENTER::ANSMOT* h) {
|
||||||
std::unique_lock<std::mutex> lk(MOTHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(MOTHandleRegistryMutex());
|
||||||
auto it = MOTHandleRegistry().find(h);
|
auto it = MOTHandleRegistry().find(h);
|
||||||
if (it == MOTHandleRegistry().end()) return false;
|
if (it == MOTHandleRegistry().end()) return false;
|
||||||
it->second--;
|
if (it->second.destructionStarted) {
|
||||||
|
return false; // Another thread already owns the delete.
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--;
|
||||||
bool ok = MOTHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
bool ok = MOTHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = MOTHandleRegistry().find(h);
|
auto it2 = MOTHandleRegistry().find(h);
|
||||||
return it2 == MOTHandleRegistry().end() || it2->second <= 0;
|
return it2 == MOTHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterMOTHandle timed out waiting for in-flight operations\n");
|
OutputDebugStringA("WARNING: UnregisterMOTHandle timed out waiting for in-flight operations\n");
|
||||||
@@ -106,14 +113,15 @@ BOOL APIENTRY DllMain( HMODULE hModule,
|
|||||||
extern "C" __declspec(dllexport) int __cdecl CreateANSMOTHandle(ANSCENTER::ANSMOT **Handle, int motType) {
|
extern "C" __declspec(dllexport) int __cdecl CreateANSMOTHandle(ANSCENTER::ANSMOT **Handle, int motType) {
|
||||||
if (Handle == nullptr) return 0;
|
if (Handle == nullptr) return 0;
|
||||||
try {
|
try {
|
||||||
// Release existing handle if called twice (prevents leak from LabVIEW)
|
// Pure constructor: ignore *Handle(in). LabVIEW's CLF Node marshalling
|
||||||
if (*Handle) {
|
// reuses the same temp buffer per call site, so *Handle(in) often holds
|
||||||
if (UnregisterMOTHandle(*Handle)) {
|
// leftover bytes from the previous Create's output even when the actual
|
||||||
(*Handle)->Destroy();
|
// LabVIEW wire is a different, freshly-allocated instance. Inspecting
|
||||||
delete *Handle;
|
// *Handle(in) and destroying what we "see" tears down legitimate
|
||||||
}
|
// parallel instances. (Same reasoning as CreateANSAWSHandle.)
|
||||||
*Handle = nullptr;
|
// Trade-off: a true double-Create on the same wire leaks the prior
|
||||||
}
|
// handle -- caller's bug; the alternative is far worse.
|
||||||
|
*Handle = nullptr;
|
||||||
|
|
||||||
switch (motType) {
|
switch (motType) {
|
||||||
case 0: //BYTETRACKNCNN =0
|
case 0: //BYTETRACKNCNN =0
|
||||||
|
|||||||
@@ -17,8 +17,12 @@
|
|||||||
|
|
||||||
// Handle registry with refcount — prevents use-after-free when
|
// Handle registry with refcount — prevents use-after-free when
|
||||||
// ReleaseANSOCRHandle is called while inference is still running.
|
// ReleaseANSOCRHandle is called while inference is still running.
|
||||||
static std::unordered_map<ANSCENTER::ANSOCRBase*, int>& OCRHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSOCRBase*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct OCREntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSOCRBase*, OCREntry>& OCRHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSOCRBase*, OCREntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& OCRHandleRegistryMutex() {
|
static std::mutex& OCRHandleRegistryMutex() {
|
||||||
@@ -32,14 +36,15 @@ static std::condition_variable& OCRHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterOCRHandle(ANSCENTER::ANSOCRBase* h) {
|
static void RegisterOCRHandle(ANSCENTER::ANSOCRBase* h) {
|
||||||
std::lock_guard<std::mutex> lk(OCRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(OCRHandleRegistryMutex());
|
||||||
OCRHandleRegistry()[h] = 1; // refcount = 1
|
OCRHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
static ANSCENTER::ANSOCRBase* AcquireOCRHandle(ANSCENTER::ANSOCRBase* h) {
|
static ANSCENTER::ANSOCRBase* AcquireOCRHandle(ANSCENTER::ANSOCRBase* h) {
|
||||||
std::lock_guard<std::mutex> lk(OCRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(OCRHandleRegistryMutex());
|
||||||
auto it = OCRHandleRegistry().find(h);
|
auto it = OCRHandleRegistry().find(h);
|
||||||
if (it == OCRHandleRegistry().end()) return nullptr;
|
if (it == OCRHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,23 +52,25 @@ static bool ReleaseOCRHandleRef(ANSCENTER::ANSOCRBase* h) {
|
|||||||
std::lock_guard<std::mutex> lk(OCRHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(OCRHandleRegistryMutex());
|
||||||
auto it = OCRHandleRegistry().find(h);
|
auto it = OCRHandleRegistry().find(h);
|
||||||
if (it == OCRHandleRegistry().end()) return false;
|
if (it == OCRHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
OCRHandleRegistry().erase(it);
|
|
||||||
OCRHandleRegistryCV().notify_all();
|
OCRHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterOCRHandle(ANSCENTER::ANSOCRBase* h) {
|
static bool UnregisterOCRHandle(ANSCENTER::ANSOCRBase* h) {
|
||||||
std::unique_lock<std::mutex> lk(OCRHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(OCRHandleRegistryMutex());
|
||||||
auto it = OCRHandleRegistry().find(h);
|
auto it = OCRHandleRegistry().find(h);
|
||||||
if (it == OCRHandleRegistry().end()) return false;
|
if (it == OCRHandleRegistry().end()) return false;
|
||||||
it->second--;
|
if (it->second.destructionStarted) {
|
||||||
|
return false; // Another thread already owns the delete.
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--;
|
||||||
bool ok = OCRHandleRegistryCV().wait_for(lk, std::chrono::seconds(5), [&]() {
|
bool ok = OCRHandleRegistryCV().wait_for(lk, std::chrono::seconds(5), [&]() {
|
||||||
auto it2 = OCRHandleRegistry().find(h);
|
auto it2 = OCRHandleRegistry().find(h);
|
||||||
return it2 == OCRHandleRegistry().end() || it2->second <= 0;
|
return it2 == OCRHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterOCRHandle timed out waiting for in-flight inference\n");
|
OutputDebugStringA("WARNING: UnregisterOCRHandle timed out waiting for in-flight inference\n");
|
||||||
|
|||||||
@@ -193,8 +193,12 @@ static bool CheckGPUVRAM(int gpuIndex, size_t minFreeBytes = 512ULL * 1024 * 102
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unordered_map<ANSCENTER::ANSODBase*, int>& ODHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSODBase*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct ODEntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSODBase*, ODEntry>& ODHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSODBase*, ODEntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& ODHandleRegistryMutex() {
|
static std::mutex& ODHandleRegistryMutex() {
|
||||||
@@ -208,46 +212,48 @@ static std::condition_variable& ODHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterODHandle(ANSCENTER::ANSODBase* h) {
|
static void RegisterODHandle(ANSCENTER::ANSODBase* h) {
|
||||||
std::lock_guard<std::mutex> lk(ODHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(ODHandleRegistryMutex());
|
||||||
ODHandleRegistry()[h] = 1; // refcount = 1
|
ODHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a handle for use (increment refcount). Returns the handle
|
// Acquire a handle for use (increment refcount). Returns the handle
|
||||||
// if valid, nullptr if already released.
|
// if valid, nullptr if already released or being destroyed.
|
||||||
static ANSCENTER::ANSODBase* AcquireODHandle(ANSCENTER::ANSODBase* h) {
|
static ANSCENTER::ANSODBase* AcquireODHandle(ANSCENTER::ANSODBase* h) {
|
||||||
std::lock_guard<std::mutex> lk(ODHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(ODHandleRegistryMutex());
|
||||||
auto it = ODHandleRegistry().find(h);
|
auto it = ODHandleRegistry().find(h);
|
||||||
if (it == ODHandleRegistry().end()) return nullptr;
|
if (it == ODHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release a use of the handle (decrement refcount).
|
// Release a use of the handle (decrement refcount). Only signals the CV;
|
||||||
// Returns true if this was the last reference (caller should destroy).
|
// the object is always deleted by Unregister, never by a stray ref-drop.
|
||||||
static bool ReleaseODHandleRef(ANSCENTER::ANSODBase* h) {
|
static bool ReleaseODHandleRef(ANSCENTER::ANSODBase* h) {
|
||||||
std::lock_guard<std::mutex> lk(ODHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(ODHandleRegistryMutex());
|
||||||
auto it = ODHandleRegistry().find(h);
|
auto it = ODHandleRegistry().find(h);
|
||||||
if (it == ODHandleRegistry().end()) return false;
|
if (it == ODHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
ODHandleRegistry().erase(it);
|
|
||||||
ODHandleRegistryCV().notify_all();
|
ODHandleRegistryCV().notify_all();
|
||||||
return true; // Caller should destroy
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unregister and wait for all in-flight uses to finish.
|
// Unregister and wait for all in-flight uses to finish.
|
||||||
// Decrements the creation refcount and blocks until refcount hits 0.
|
// First caller takes ownership of destruction; subsequent calls return false.
|
||||||
// Returns true if caller should destroy the object.
|
|
||||||
static bool UnregisterODHandle(ANSCENTER::ANSODBase* h) {
|
static bool UnregisterODHandle(ANSCENTER::ANSODBase* h) {
|
||||||
std::unique_lock<std::mutex> lk(ODHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(ODHandleRegistryMutex());
|
||||||
auto it = ODHandleRegistry().find(h);
|
auto it = ODHandleRegistry().find(h);
|
||||||
if (it == ODHandleRegistry().end()) return false;
|
if (it == ODHandleRegistry().end()) return false;
|
||||||
it->second--; // Remove creation ref
|
if (it->second.destructionStarted) {
|
||||||
|
return false; // Another thread already owns the delete.
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--; // Remove creation ref
|
||||||
// Wait for in-flight inferences to finish (30s timeout as safety net)
|
// Wait for in-flight inferences to finish (30s timeout as safety net)
|
||||||
bool ok = ODHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
bool ok = ODHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = ODHandleRegistry().find(h);
|
auto it2 = ODHandleRegistry().find(h);
|
||||||
return it2 == ODHandleRegistry().end() || it2->second <= 0;
|
return it2 == ODHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterODHandle timed out waiting for in-flight inference\n");
|
OutputDebugStringA("WARNING: UnregisterODHandle timed out waiting for in-flight inference\n");
|
||||||
|
|||||||
@@ -20,8 +20,12 @@
|
|||||||
|
|
||||||
// Handle registry with refcount — prevents use-after-free when
|
// Handle registry with refcount — prevents use-after-free when
|
||||||
// ReleaseANSTREHandle is called while an operation is still running.
|
// ReleaseANSTREHandle is called while an operation is still running.
|
||||||
static std::unordered_map<ANSCENTER::ANSTRE*, int>& TREHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSTRE*, int> s;
|
// and makes subsequent Unregister calls return false without deleting.
|
||||||
|
// Prevents double-free when Release is raced on the same handle.
|
||||||
|
struct TREEntry { int refcount; bool destructionStarted; };
|
||||||
|
static std::unordered_map<ANSCENTER::ANSTRE*, TREEntry>& TREHandleRegistry() {
|
||||||
|
static std::unordered_map<ANSCENTER::ANSTRE*, TREEntry> s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& TREHandleRegistryMutex() {
|
static std::mutex& TREHandleRegistryMutex() {
|
||||||
@@ -35,14 +39,15 @@ static std::condition_variable& TREHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterTREHandle(ANSCENTER::ANSTRE* h) {
|
static void RegisterTREHandle(ANSCENTER::ANSTRE* h) {
|
||||||
std::lock_guard<std::mutex> lk(TREHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(TREHandleRegistryMutex());
|
||||||
TREHandleRegistry()[h] = 1;
|
TREHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
static ANSCENTER::ANSTRE* AcquireTREHandle(ANSCENTER::ANSTRE* h) {
|
static ANSCENTER::ANSTRE* AcquireTREHandle(ANSCENTER::ANSTRE* h) {
|
||||||
std::lock_guard<std::mutex> lk(TREHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(TREHandleRegistryMutex());
|
||||||
auto it = TREHandleRegistry().find(h);
|
auto it = TREHandleRegistry().find(h);
|
||||||
if (it == TREHandleRegistry().end()) return nullptr;
|
if (it == TREHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,23 +55,25 @@ static bool ReleaseTREHandleRef(ANSCENTER::ANSTRE* h) {
|
|||||||
std::lock_guard<std::mutex> lk(TREHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(TREHandleRegistryMutex());
|
||||||
auto it = TREHandleRegistry().find(h);
|
auto it = TREHandleRegistry().find(h);
|
||||||
if (it == TREHandleRegistry().end()) return false;
|
if (it == TREHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
TREHandleRegistry().erase(it);
|
|
||||||
TREHandleRegistryCV().notify_all();
|
TREHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterTREHandle(ANSCENTER::ANSTRE* h) {
|
static bool UnregisterTREHandle(ANSCENTER::ANSTRE* h) {
|
||||||
std::unique_lock<std::mutex> lk(TREHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(TREHandleRegistryMutex());
|
||||||
auto it = TREHandleRegistry().find(h);
|
auto it = TREHandleRegistry().find(h);
|
||||||
if (it == TREHandleRegistry().end()) return false;
|
if (it == TREHandleRegistry().end()) return false;
|
||||||
it->second--;
|
if (it->second.destructionStarted) {
|
||||||
|
return false; // Another thread already owns the delete.
|
||||||
|
}
|
||||||
|
it->second.destructionStarted = true;
|
||||||
|
it->second.refcount--;
|
||||||
bool ok = TREHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
bool ok = TREHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = TREHandleRegistry().find(h);
|
auto it2 = TREHandleRegistry().find(h);
|
||||||
return it2 == TREHandleRegistry().end() || it2->second <= 0;
|
return it2 == TREHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterTREHandle timed out waiting for in-flight operations\n");
|
OutputDebugStringA("WARNING: UnregisterTREHandle timed out waiting for in-flight operations\n");
|
||||||
|
|||||||
@@ -20,8 +20,12 @@ static void AWSDbg(const char* fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── ANSUtilities handle registry ──
|
// ── ANSUtilities handle registry ──
|
||||||
static std::unordered_map<ANSCENTER::ANSUtilities*, int>& UtilHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSUtilities*, int> s;
|
// 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;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& UtilHandleRegistryMutex() {
|
static std::mutex& UtilHandleRegistryMutex() {
|
||||||
@@ -35,14 +39,15 @@ static std::condition_variable& UtilHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterUtilHandle(ANSCENTER::ANSUtilities* h) {
|
static void RegisterUtilHandle(ANSCENTER::ANSUtilities* h) {
|
||||||
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
||||||
UtilHandleRegistry()[h] = 1;
|
UtilHandleRegistry()[h] = { 1, false };
|
||||||
}
|
}
|
||||||
|
|
||||||
static ANSCENTER::ANSUtilities* AcquireUtilHandle(ANSCENTER::ANSUtilities* h) {
|
static ANSCENTER::ANSUtilities* AcquireUtilHandle(ANSCENTER::ANSUtilities* h) {
|
||||||
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
||||||
auto it = UtilHandleRegistry().find(h);
|
auto it = UtilHandleRegistry().find(h);
|
||||||
if (it == UtilHandleRegistry().end()) return nullptr;
|
if (it == UtilHandleRegistry().end()) return nullptr;
|
||||||
it->second++;
|
if (it->second.destructionStarted) return nullptr;
|
||||||
|
it->second.refcount++;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,23 +55,26 @@ static bool ReleaseUtilHandleRef(ANSCENTER::ANSUtilities* h) {
|
|||||||
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(UtilHandleRegistryMutex());
|
||||||
auto it = UtilHandleRegistry().find(h);
|
auto it = UtilHandleRegistry().find(h);
|
||||||
if (it == UtilHandleRegistry().end()) return false;
|
if (it == UtilHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
UtilHandleRegistry().erase(it);
|
|
||||||
UtilHandleRegistryCV().notify_all();
|
UtilHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes. Ref drop just signals the CV.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterUtilHandle(ANSCENTER::ANSUtilities* h) {
|
static bool UnregisterUtilHandle(ANSCENTER::ANSUtilities* h) {
|
||||||
std::unique_lock<std::mutex> lk(UtilHandleRegistryMutex());
|
std::unique_lock<std::mutex> lk(UtilHandleRegistryMutex());
|
||||||
auto it = UtilHandleRegistry().find(h);
|
auto it = UtilHandleRegistry().find(h);
|
||||||
if (it == UtilHandleRegistry().end()) return false;
|
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), [&]() {
|
bool ok = UtilHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
|
||||||
auto it2 = UtilHandleRegistry().find(h);
|
auto it2 = UtilHandleRegistry().find(h);
|
||||||
return it2 == UtilHandleRegistry().end() || it2->second <= 0;
|
return it2 == UtilHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterUtilHandle timed out waiting for in-flight operations\n");
|
OutputDebugStringA("WARNING: UnregisterUtilHandle timed out waiting for in-flight operations\n");
|
||||||
@@ -87,8 +95,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ── ANSAWSS3 handle registry ──
|
// ── ANSAWSS3 handle registry ──
|
||||||
static std::unordered_map<ANSCENTER::ANSAWSS3*, int>& AWSHandleRegistry() {
|
// destructionStarted: set by the first Unregister caller; blocks new Acquires
|
||||||
static std::unordered_map<ANSCENTER::ANSAWSS3*, int> s;
|
// 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;
|
return s;
|
||||||
}
|
}
|
||||||
static std::mutex& AWSHandleRegistryMutex() {
|
static std::mutex& AWSHandleRegistryMutex() {
|
||||||
@@ -102,14 +115,15 @@ static std::condition_variable& AWSHandleRegistryCV() {
|
|||||||
|
|
||||||
static void RegisterAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
static void RegisterAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||||
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
||||||
AWSHandleRegistry()[h] = 1;
|
AWSHandleRegistry()[h] = { 1, false };
|
||||||
AWSDbg("[ANSAWS] Register: handle=%p (uint=%llu) registrySize=%zu\n",
|
AWSDbg("[ANSAWS] Register: handle=%p (uint=%llu) registrySize=%zu\n",
|
||||||
(void*)h, (unsigned long long)(uintptr_t)h, AWSHandleRegistry().size());
|
(void*)h, (unsigned long long)(uintptr_t)h, AWSHandleRegistry().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsAWSHandleLive(ANSCENTER::ANSAWSS3* h) {
|
static bool IsAWSHandleLive(ANSCENTER::ANSAWSS3* h) {
|
||||||
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
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) {
|
static ANSCENTER::ANSAWSS3* AcquireAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
||||||
@@ -118,16 +132,20 @@ static ANSCENTER::ANSAWSS3* AcquireAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
|||||||
if (it == AWSHandleRegistry().end()) {
|
if (it == AWSHandleRegistry().end()) {
|
||||||
AWSDbg("[ANSAWS] Acquire FAIL: handle=%p (uint=%llu) NOT in registry. registrySize=%zu\n",
|
AWSDbg("[ANSAWS] Acquire FAIL: handle=%p (uint=%llu) NOT in registry. registrySize=%zu\n",
|
||||||
(void*)h, (unsigned long long)(uintptr_t)h, AWSHandleRegistry().size());
|
(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;
|
size_t i = 0;
|
||||||
for (auto& kv : AWSHandleRegistry()) {
|
for (auto& kv : AWSHandleRegistry()) {
|
||||||
AWSDbg("[ANSAWS] registry[%zu] = %p (uint=%llu) refcount=%d\n",
|
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);
|
i++, (void*)kv.first, (unsigned long long)(uintptr_t)kv.first,
|
||||||
|
kv.second.refcount, kv.second.destructionStarted ? 1 : 0);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
it->second++;
|
if (it->second.destructionStarted) {
|
||||||
AWSDbg("[ANSAWS] Acquire OK: handle=%p refcount=%d\n", (void*)h, it->second);
|
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;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,13 +153,11 @@ static bool ReleaseAWSHandleRef(ANSCENTER::ANSAWSS3* h) {
|
|||||||
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
std::lock_guard<std::mutex> lk(AWSHandleRegistryMutex());
|
||||||
auto it = AWSHandleRegistry().find(h);
|
auto it = AWSHandleRegistry().find(h);
|
||||||
if (it == AWSHandleRegistry().end()) return false;
|
if (it == AWSHandleRegistry().end()) return false;
|
||||||
it->second--;
|
it->second.refcount--;
|
||||||
if (it->second <= 0) {
|
if (it->second.refcount <= 0) {
|
||||||
AWSHandleRegistry().erase(it);
|
|
||||||
AWSHandleRegistryCV().notify_all();
|
AWSHandleRegistryCV().notify_all();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false; // Only Unregister deletes. Ref drop just signals the CV.
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UnregisterAWSHandle(ANSCENTER::ANSAWSS3* h) {
|
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);
|
AWSDbg("[ANSAWS] Unregister: handle=%p NOT in registry (already gone)\n", (void*)h);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AWSDbg("[ANSAWS] Unregister: handle=%p starting (refcount before=%d)\n", (void*)h, it->second);
|
if (it->second.destructionStarted) {
|
||||||
it->second--;
|
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), [&]() {
|
bool ok = AWSHandleRegistryCV().wait_for(lk, std::chrono::seconds(120), [&]() {
|
||||||
auto it2 = AWSHandleRegistry().find(h);
|
auto it2 = AWSHandleRegistry().find(h);
|
||||||
return it2 == AWSHandleRegistry().end() || it2->second <= 0;
|
return it2 == AWSHandleRegistry().end() || it2->second.refcount <= 0;
|
||||||
});
|
});
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
OutputDebugStringA("WARNING: UnregisterAWSHandle timed out waiting for in-flight operations\n");
|
OutputDebugStringA("WARNING: UnregisterAWSHandle timed out waiting for in-flight operations\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user