From e771882c83ab08aa430200a79e492b5595269c31 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 31 May 2026 11:11:50 +0200 Subject: [PATCH] added a lock to avoid parallel calls from different threads --- AGENTS.md | 5 +++++ src/serum-decode.cpp | 16 +++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 1691cd6..da7f1bc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,6 +30,11 @@ Main global runtime state (in `serum-decode.cpp`): - Current output: `mySerum` (`Serum_Frame_Struc`). - Scene playback state: `sceneFrameCount`, `sceneCurrentFrame`, duration/flags/repeat, etc. - Identification state: `lastfound`, `lastfound_normal`, `lastfound_scene`, CRC tracking. +- Public C API entrypoints are serialized through a recursive runtime mutex + because this state is process-global and scene rendering may re-enter + colorization internally. `Serum_Rotate()` must not run concurrently with + `Serum_Colorize()` while shared output buffers, flags, widths, rotation + tables, or scene state are being updated. - Scene lookup acceleration: - `g_serumData.frameIsScene`: frame ID -> scene/non-scene marker. - `g_serumData.sceneFramesBySignature`: `(mask,shape,hash)` -> matching scene frame IDs. diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index e9f30cb..92f6888 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -195,14 +195,18 @@ static void EnsureWindowsCrashHandlerInstalled() { } #endif +static std::recursive_mutex g_serumApiMutex; + #if defined(_WIN32) || defined(_WIN64) -#define SERUM_API_GUARD_START(apiName) \ - ClearLastErrorMessage(); \ - EnsureWindowsCrashHandlerInstalled(); \ +#define SERUM_API_GUARD_START(apiName) \ + ClearLastErrorMessage(); \ + EnsureWindowsCrashHandlerInstalled(); \ + std::lock_guard serumApiLock(g_serumApiMutex); \ try { #else -#define SERUM_API_GUARD_START(apiName) \ - ClearLastErrorMessage(); \ +#define SERUM_API_GUARD_START(apiName) \ + ClearLastErrorMessage(); \ + std::lock_guard serumApiLock(g_serumApiMutex); \ try { #endif @@ -5269,12 +5273,14 @@ static uint32_t Serum_ColorizeWithMetadatav2Internal(uint8_t* frame, SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame, bool sceneFrameRequested = false) { + SERUM_API_GUARD_START("Serum_ColorizeWithMetadatav2") BeginProfileFrameOperation(); const uint32_t result = Serum_ColorizeWithMetadatav2Internal( frame, sceneFrameRequested, IDENTIFY_NO_FRAME); EndProfileFrameOperation(); MaybeLogDynamicHotPathProfileWindow(sceneFrameRequested); return result; + SERUM_API_GUARD_END("Serum_ColorizeWithMetadatav2", IDENTIFY_NO_FRAME) } SERUM_API uint32_t Serum_Colorize(uint8_t* frame) {