Files
ANSCORE/modules/ANSMOT/dllmain.cpp

289 lines
8.8 KiB
C++
Raw Normal View History

2026-03-28 16:54:11 +11:00
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "ANSMOT.h"
#include "ANSByteTrackNCNN.h"
#include "ANSByteTrack.h"
#include "ANSByteTrackEigen.h"
#include "ANSOCSortTrack.h"
#include "ANSUCMC.h"
#include <unordered_map>
#include <condition_variable>
#include <mutex>
#include <cstdint>
// Handle registry with refcount — prevents use-after-free when
// ReleaseANSMOTHandle is called while an operation is still running.
2026-04-19 14:47:29 +10:00
// 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 MOTEntry { int refcount; bool destructionStarted; };
static std::unordered_map<ANSCENTER::ANSMOT*, MOTEntry>& MOTHandleRegistry() {
static std::unordered_map<ANSCENTER::ANSMOT*, MOTEntry> s;
2026-03-28 16:54:11 +11:00
return s;
}
static std::mutex& MOTHandleRegistryMutex() {
static std::mutex m;
return m;
}
static std::condition_variable& MOTHandleRegistryCV() {
static std::condition_variable cv;
return cv;
}
static void RegisterMOTHandle(ANSCENTER::ANSMOT* h) {
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
2026-04-19 14:47:29 +10:00
MOTHandleRegistry()[h] = { 1, false };
2026-03-28 16:54:11 +11:00
}
static ANSCENTER::ANSMOT* AcquireMOTHandle(ANSCENTER::ANSMOT* h) {
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
auto it = MOTHandleRegistry().find(h);
if (it == MOTHandleRegistry().end()) return nullptr;
2026-04-19 14:47:29 +10:00
if (it->second.destructionStarted) return nullptr;
it->second.refcount++;
2026-03-28 16:54:11 +11:00
return h;
}
static bool ReleaseMOTHandleRef(ANSCENTER::ANSMOT* h) {
std::lock_guard<std::mutex> lk(MOTHandleRegistryMutex());
auto it = MOTHandleRegistry().find(h);
if (it == MOTHandleRegistry().end()) return false;
2026-04-19 14:47:29 +10:00
it->second.refcount--;
if (it->second.refcount <= 0) {
2026-03-28 16:54:11 +11:00
MOTHandleRegistryCV().notify_all();
}
2026-04-19 14:47:29 +10:00
return false; // Only Unregister deletes.
2026-03-28 16:54:11 +11:00
}
static bool UnregisterMOTHandle(ANSCENTER::ANSMOT* h) {
std::unique_lock<std::mutex> lk(MOTHandleRegistryMutex());
auto it = MOTHandleRegistry().find(h);
if (it == MOTHandleRegistry().end()) return false;
2026-04-19 14:47:29 +10:00
if (it->second.destructionStarted) {
return false; // Another thread already owns the delete.
}
it->second.destructionStarted = true;
it->second.refcount--;
2026-03-28 16:54:11 +11:00
bool ok = MOTHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
auto it2 = MOTHandleRegistry().find(h);
2026-04-19 14:47:29 +10:00
return it2 == MOTHandleRegistry().end() || it2->second.refcount <= 0;
2026-03-28 16:54:11 +11:00
});
if (!ok) {
OutputDebugStringA("WARNING: UnregisterMOTHandle timed out waiting for in-flight operations\n");
}
MOTHandleRegistry().erase(h);
return true;
}
// RAII guard — ensures ReleaseMOTHandleRef is always called
class MOTHandleGuard {
ANSCENTER::ANSMOT* engine;
public:
explicit MOTHandleGuard(ANSCENTER::ANSMOT* e) : engine(e) {}
~MOTHandleGuard() { if (engine) ReleaseMOTHandleRef(engine); }
ANSCENTER::ANSMOT* get() const { return engine; }
explicit operator bool() const { return engine != nullptr; }
MOTHandleGuard(const MOTHandleGuard&) = delete;
MOTHandleGuard& operator=(const MOTHandleGuard&) = delete;
};
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/*
enum MOTEType {
BYTETRACKNCNN = 0,
BYTETRACK = 1,
BYTETRACKEIGEN=2,
OCSORT=3
};
*/
extern "C" __declspec(dllexport) int __cdecl CreateANSMOTHandle(ANSCENTER::ANSMOT **Handle, int motType) {
if (Handle == nullptr) return 0;
try {
2026-04-19 14:47:29 +10:00
// Pure constructor: ignore *Handle(in). LabVIEW's CLF Node marshalling
// reuses the same temp buffer per call site, so *Handle(in) often holds
// leftover bytes from the previous Create's output even when the actual
// LabVIEW wire is a different, freshly-allocated instance. Inspecting
// *Handle(in) and destroying what we "see" tears down legitimate
// parallel instances. (Same reasoning as CreateANSAWSHandle.)
// Trade-off: a true double-Create on the same wire leaks the prior
// handle -- caller's bug; the alternative is far worse.
*Handle = nullptr;
2026-03-28 16:54:11 +11:00
switch (motType) {
case 0: //BYTETRACKNCNN =0
(*Handle) = new ANSCENTER::ANSByteTrack();// ANSByteTrackNCNN();
break;
case 1: //BYTETRACK = 1
(*Handle) = new ANSCENTER::ANSByteTrack();
break;
case 2://BYTETRACKEIGEN = 2
(*Handle) = new ANSCENTER::ANSByteTrack();// ANSByteTrackEigen();
break;
case 3://UCMC = 3
(*Handle) = new ANSCENTER::ANSUCMCTrack();
break;
case 4://OCSORT = 4
(*Handle) = new ANSCENTER::ANSOCSortTrack();
break;
default:
(*Handle) = new ANSCENTER::ANSByteTrack();// ANSByteTrackNCNN();
break;
}
if (*Handle == nullptr) {
return 0;
}
else {
RegisterMOTHandle(*Handle);
return 1;
}
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
static int ReleaseANSMOTHandle_Impl(ANSCENTER::ANSMOT** Handle) {
try {
if (!Handle || !*Handle) return 1;
if (!UnregisterMOTHandle(*Handle)) {
*Handle = nullptr;
return 1;
}
(*Handle)->Destroy();
delete *Handle;
*Handle = nullptr;
return 1;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int __cdecl ReleaseANSMOTHandle(ANSCENTER::ANSMOT **Handle) {
__try {
return ReleaseANSMOTHandle_Impl(Handle);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int __cdecl UpdateANSMOTParameters(ANSCENTER::ANSMOT * *Handle, const char* trackerParameter) {
if (Handle == nullptr || *Handle == nullptr) return -1;
MOTHandleGuard guard(AcquireMOTHandle(*Handle));
if (!guard) return -1;
try {
bool result = guard.get()->UpdateParameters(trackerParameter);
if (result) return 1;
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int __cdecl UpdateANSMOT(ANSCENTER::ANSMOT * *Handle, int modelId, const char* detectionData, std::string & result) {
if (Handle == nullptr || *Handle == nullptr) return -1;
MOTHandleGuard guard(AcquireMOTHandle(*Handle));
if (!guard) return -1;
try {
result = guard.get()->Update(modelId, detectionData);
if (result.empty())return 0;
else return 1;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int __cdecl UpdateANSMOT_LV(ANSCENTER::ANSMOT * *Handle, int modelId, const char* detectionData, LStrHandle trackerResult) {
if (Handle == nullptr || *Handle == nullptr) return -1;
MOTHandleGuard guard(AcquireMOTHandle(*Handle));
if (!guard) return -1;
try {
std::string st = guard.get()->Update(modelId, detectionData);
int size = static_cast<int>(st.length());
MgErr error;
error = DSSetHandleSize(trackerResult, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*trackerResult)->cnt = size;
memcpy((*trackerResult)->str, st.c_str(), size);
return 1;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int __cdecl UpdateANSMOTTracker(ANSCENTER::ANSMOT** Handle, int modelId, const std::vector<ANSCENTER::TrackerObject>& detectionObjects, std::vector<ANSCENTER::TrackerObject>& trackedObjects)
{
if (Handle == nullptr || *Handle == nullptr) return -1;
MOTHandleGuard guard(AcquireMOTHandle(*Handle));
if (!guard) return -1;
try {
trackedObjects = guard.get()->UpdateTracker(modelId, detectionObjects);
if (trackedObjects.empty()) return 0;
else return 1;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
// ============================================================================
// V2 LabVIEW API — Accept handle as uint64_t by value.
// Eliminates Handle** pointer-to-pointer instability when LabVIEW calls
// concurrently from multiple tasks.
// LabVIEW CLFN: set Handle parameter to Numeric / Unsigned Pointer-sized Integer / Pass: Value
// ============================================================================
extern "C" __declspec(dllexport) int __cdecl UpdateANSMOT_LV_V2(uint64_t handleVal, int modelId, const char* detectionData, LStrHandle trackerResult) {
ANSCENTER::ANSMOT* directHandle = reinterpret_cast<ANSCENTER::ANSMOT*>(handleVal);
if (directHandle == nullptr) return -1;
MOTHandleGuard guard(AcquireMOTHandle(directHandle));
if (!guard) return -1;
try {
std::string st = guard.get()->Update(modelId, detectionData);
int size = static_cast<int>(st.length());
MgErr error = DSSetHandleSize(trackerResult, sizeof(int32) + size * sizeof(uChar));
if (error == noErr) {
(*trackerResult)->cnt = size;
memcpy((*trackerResult)->str, st.c_str(), size);
return 1;
}
else return 0;
}
catch (...) { return 0; }
}