mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 17:19:28 +01:00
Display: Don't call a flip listener after it's been removed
DisplayFireFlip() copied the listener list and called the copy without the lock, so a debugger connection closing on its own thread could free its GPU stats subscriber while the CPU thread was about to call it. Headless crashed (or hung) in WebSocketGPUStatsState::FlipListener() with scripts that open a connection per command. Hold the lock across the calls, as LogManager does for its callbacks, so __DisplayForgetFlip() returns only once the listener can't be running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9c9eefa358
commit
16544a3bd3
1 file changed
+9
-7
+9
-7
@@ -250,15 +250,14 @@ void DisplayFireVblankEnd() {
|
||||
}
|
||||
|
||||
void DisplayFireFlip() {
|
||||
std::vector<FlipListener> toCall = [] {
|
||||
std::lock_guard<std::mutex> guard(listenersLock);
|
||||
return flipListeners;
|
||||
}();
|
||||
|
||||
// This is also the right time to calculate FPS.
|
||||
CalculateFPS();
|
||||
|
||||
for (FlipListener cb : toCall) {
|
||||
// Held across the calls, so that once __DisplayForgetFlip() returns (on a debugger connection's
|
||||
// thread, say) its listener isn't running and won't be called again. A listener must not add or
|
||||
// remove listeners.
|
||||
std::lock_guard<std::mutex> guard(listenersLock);
|
||||
for (const FlipListener &cb : flipListeners) {
|
||||
cb.first(cb.second);
|
||||
}
|
||||
}
|
||||
@@ -281,7 +280,10 @@ void __DisplayForgetFlip(FlipCallback callback, void *userdata) {
|
||||
|
||||
// This is called on game bootup.
|
||||
void DisplayHWInit() {
|
||||
flipListeners.clear();
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(listenersLock);
|
||||
flipListeners.clear();
|
||||
}
|
||||
frameStartTicks = 0;
|
||||
numVBlanks = 0;
|
||||
isVblank = 0;
|
||||
|
||||
Reference in new issue
Block a user