Fix deadlock

This commit is contained in:
2026-04-24 12:54:16 +10:00
parent e2bf17289d
commit fd2394a85a
3 changed files with 138 additions and 16 deletions

View File

@@ -96,9 +96,12 @@ namespace fs = std::filesystem;
// creation on the same extracted folder so concurrent CreateANSODHandle calls
// cannot truncate/rewrite a model file while another thread is loading it.
// Keyed by folder path (not zip path) so both extractor and consumer agree.
// Returns std::timed_mutex so callers can bound their wait and avoid a hang
// if a peer thread deadlocks inside extraction or ORT session creation.
ANSLICENSE_API std::shared_ptr<std::timed_mutex> GetModelFolderLock(const std::string& folderPath);
// Returns std::recursive_timed_mutex so callers can bound their wait and
// recursion — layered load paths (e.g. ANSALPR_OD::LoadEngine ->
// ANSONNXYOLO::LoadModelFromFolder) legitimately re-enter on the same
// thread; a non-recursive timed_mutex self-deadlocks that nesting. Cross-
// thread serialization is unchanged.
ANSLICENSE_API std::shared_ptr<std::recursive_timed_mutex> GetModelFolderLock(const std::string& folderPath);
// ============================================================================
// ModelFolderLockGuard
@@ -111,8 +114,10 @@ namespace fs = std::filesystem;
// error number 13" (EACCES) on the reader.
//
// Backed by GetModelFolderLock() above which returns a process-wide
// std::timed_mutex keyed on the folder path. The extractor takes the same
// lock, so extract ↔ open is mutually exclusive.
// std::recursive_timed_mutex keyed on the folder path. The extractor takes
// the same lock, so extract ↔ open is mutually exclusive across threads,
// while same-thread re-entry (layered loaders) is permitted without
// deadlocking.
//
// Acquisition is bounded by `timeout` (default 120 s) so a deadlocked peer
// cannot hang the caller thread forever. On timeout, .acquired() is false and
@@ -165,7 +170,7 @@ namespace ANSCENTER {
return;
}
auto lock = GetModelFolderLock(folderPath);
_guard = std::unique_lock<std::timed_mutex>(*lock, std::defer_lock);
_guard = std::unique_lock<std::recursive_timed_mutex>(*lock, std::defer_lock);
ANS_DBG("EngineLoad",
"%s: waiting on folder lock (%llds): %s",
_caller, (long long)timeout.count(), folderPath.c_str());
@@ -196,7 +201,7 @@ namespace ANSCENTER {
private:
const char* _caller;
std::string _folder;
std::unique_lock<std::timed_mutex> _guard;
std::unique_lock<std::recursive_timed_mutex> _guard;
bool _ok = false;
};
} // namespace ANSCENTER