Fix unregister issue

This commit is contained in:
2026-04-19 14:47:29 +10:00
parent 2de11c4b0c
commit 51fe507dfd
8 changed files with 191 additions and 122 deletions

View File

@@ -9,8 +9,12 @@
// Handle registry with refcount — prevents use-after-free when
// ReleaseANSLLMHandle is called while an operation is still running.
static std::unordered_map<ANSCENTER::ANSLLM*, int>& LLMHandleRegistry() {
static std::unordered_map<ANSCENTER::ANSLLM*, int> s;
// destructionStarted: set by the first Unregister caller; blocks new Acquires
// 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;
}
static std::mutex& LLMHandleRegistryMutex() {
@@ -24,14 +28,15 @@ static std::condition_variable& LLMHandleRegistryCV() {
static void RegisterLLMHandle(ANSCENTER::ANSLLM* h) {
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
LLMHandleRegistry()[h] = 1;
LLMHandleRegistry()[h] = { 1, false };
}
static ANSCENTER::ANSLLM* AcquireLLMHandle(ANSCENTER::ANSLLM* h) {
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
auto it = LLMHandleRegistry().find(h);
if (it == LLMHandleRegistry().end()) return nullptr;
it->second++;
if (it->second.destructionStarted) return nullptr;
it->second.refcount++;
return h;
}
@@ -39,23 +44,25 @@ static bool ReleaseLLMHandleRef(ANSCENTER::ANSLLM* h) {
std::lock_guard<std::mutex> lk(LLMHandleRegistryMutex());
auto it = LLMHandleRegistry().find(h);
if (it == LLMHandleRegistry().end()) return false;
it->second--;
if (it->second <= 0) {
LLMHandleRegistry().erase(it);
it->second.refcount--;
if (it->second.refcount <= 0) {
LLMHandleRegistryCV().notify_all();
return true;
}
return false;
return false; // Only Unregister deletes.
}
static bool UnregisterLLMHandle(ANSCENTER::ANSLLM* h) {
std::unique_lock<std::mutex> lk(LLMHandleRegistryMutex());
auto it = LLMHandleRegistry().find(h);
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), [&]() {
auto it2 = LLMHandleRegistry().find(h);
return it2 == LLMHandleRegistry().end() || it2->second <= 0;
return it2 == LLMHandleRegistry().end() || it2->second.refcount <= 0;
});
if (!ok) {
OutputDebugStringA("WARNING: UnregisterLLMHandle timed out waiting for in-flight operations\n");