Recycle MpscQueue nodes and keep host time out of emulated state

A drained MpscQueue node goes onto a free stack shared by every queue of the same type, and a
producer takes that stack whole when its own thread's list runs dry, so once warmed up a push
no longer allocates. That takes the heap allocation back off memory block notifications, the
CPU queue, Vulkan deletes and the GL render queue. A unit test runs several producers against
one consumer over two rounds.

The NpSignin dialog's delays run on emulated time and are saved with the state, so the dialog
behaves the same at any speed and under run-ahead. The time since the last save and savestate
goes; only the standalone frontends' exit prompts read it.
This commit is contained in:
libretroadmin committed 2026-10-09 08:28:29 +02:00
1 parent b570567b88
commit 3f225d06c1
8 files changed
+112 -70

No files matched your search

-16
View File
@@ -33,7 +33,6 @@
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/StringUtils.h"
#include "Common/TimeUtil.h"
#include "Core/SaveState.h"
#include "Core/Config.h"
@@ -80,7 +79,6 @@ static const char * const LOAD_UNDO_NAME = "load_undo.ppst";
namespace SaveState {
// Used for "confirm exit if you haven't saved in a while"
double g_lastSaveTime = -1.0;
// Set by Enqueue on any thread, taken by Process on the emulation thread.
static retro_atomic_int_t needsProcess{ 0 };
@@ -97,7 +95,6 @@ static StateRingbuffer rewindStates;
// Updated by Rescan. This is to avoid calling Exists a lot of times, which could be slow
// on some Android devices when we allow many save states.
static double g_lastRescan = 0.0;
static std::map<std::string, uint64_t, std::less<>> g_files; // the value is the mod-time.
struct SaveStart {
@@ -588,7 +585,6 @@ static retro_atomic_int_t g_screenshotFailures{ 0 };
g_files[f.name] = f.mtime;
}
g_lastRescan = time_now_d();
}
static bool SaveStateFileExists(std::string_view gamePrefix, int slot, const char *extension) {
@@ -920,7 +916,6 @@ static retro_atomic_int_t g_screenshotFailures{ 0 };
}
}
#endif
g_lastSaveTime = time_now_d();
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
HandleLoadFailure(false, &callbackMetadata);
callbackMessage = std::string(i18nLoadFailure) + ": " + errorString;
@@ -956,7 +951,6 @@ static retro_atomic_int_t g_screenshotFailures{ 0 };
}
}
#endif
g_lastSaveTime = time_now_d();
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
// TODO: What else might we want to do here? This should be very unusual.
callbackMessage = i18nSaveFailure;
@@ -1049,20 +1043,10 @@ static retro_atomic_int_t g_screenshotFailures{ 0 };
saveDataGeneration = 0;
lastSaveDataGeneration = 0;
saveStateInitialGitVersion.clear();
g_lastSaveTime = time_now_d();
}
void Shutdown() {
rewindStates.Clear();
}
double SecondsSinceLastSavestate() {
if (g_lastSaveTime < 0) {
return -1.0;
} else {
return time_now_d() - g_lastSaveTime;
}
}
} // namespace SaveState