Skip to content

Commit 833870c

Browse files
committed
fix: PinMAME threading issue.
1 parent 9efbcfa commit 833870c

2 files changed

Lines changed: 85 additions & 101 deletions

File tree

VisualPinball.Engine.PinMAME.Unity/Editor/PinMamePlayModeLifecycle.cs

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,13 @@ namespace VisualPinball.Engine.PinMAME.Editor
3232
public static class PinMamePlayModeLifecycle
3333
{
3434
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
35-
private const string LogPrefix = "[PinMAME-debug]";
3635
private static bool _stopping;
3736
private static Stopwatch _stopwatch;
3837
private const int StopTimeoutMs = 2000;
3938
private static bool _warnedTimeout;
4039
private static System.Threading.Tasks.Task _stopTask;
4140

42-
private static bool IsDomainReloadDisabled()
43-
{
44-
// When Enter Play Mode Options are enabled, Unity can skip domain/scene reload.
45-
// If domain reload is enabled (default), we must not run PinMAME stop on a background task
46-
// that can outlive the managed domain during playmode transitions.
47-
try {
48-
if (!EditorSettings.enterPlayModeOptionsEnabled) {
49-
return false;
50-
}
51-
return (EditorSettings.enterPlayModeOptions & EnterPlayModeOptions.DisableDomainReload) != 0;
52-
} catch {
53-
return false;
54-
}
55-
}
56-
// Native stop is potentially blocking; we do it on a background thread.
41+
// (removed) Domain reload branching; stop is synchronous for determinism.
5742

5843
static PinMamePlayModeLifecycle()
5944
{
@@ -75,8 +60,10 @@ private static void OnPlayModeStateChanged(PlayModeStateChange state)
7560

7661
private static void RequestStop(string reason)
7762
{
63+
int runState;
7864
try {
79-
if (!PinMame.PinMame.IsRunning) {
65+
runState = PinMame.PinMame.RunState;
66+
if (runState == 0) {
8067
return;
8168
}
8269
} catch {
@@ -90,7 +77,7 @@ private static void RequestStop(string reason)
9077
_stopping = true;
9178
_warnedTimeout = false;
9279
_stopwatch = Stopwatch.StartNew();
93-
Logger.Warn($"{LogPrefix} [PinMAME] Stop requested ({reason})");
80+
Logger.Info($"[PinMAME] Stop requested ({reason}), RunState={runState}");
9481

9582
// Stop sim thread(s) first. This reduces the chance of other high-frequency code paths
9683
// continuing to call into PinMAME while we are stopping it.
@@ -113,49 +100,41 @@ private static void RequestStop(string reason)
113100
EditorApplication.update += Update;
114101

115102
// Stop PinMAME now.
116-
// - With Domain Reload enabled: stop synchronously while the domain is still stable.
117-
// - With Domain Reload disabled: stop on a background task to keep the editor responsive.
118-
if (IsDomainReloadDisabled()) {
119-
_stopTask = System.Threading.Tasks.Task.Run(() => {
120-
try {
121-
PinMame.PinMame.StopRunningGame();
122-
} catch (Exception e) {
123-
Logger.Warn(e, $"{LogPrefix} [PinMAME] StopGame failed while exiting play mode.");
124-
}
125-
});
126-
} else {
127-
try {
128-
PinMame.PinMame.StopRunningGame();
129-
_stopTask = System.Threading.Tasks.Task.CompletedTask;
130-
} catch (Exception e) {
131-
Logger.Warn(e, $"{LogPrefix} [PinMAME] StopGame failed while exiting play mode.");
132-
_stopTask = System.Threading.Tasks.Task.CompletedTask;
133-
}
103+
// With Domain Reload disabled, background stop can overlap the next play session.
104+
// Now that other hot loops are tamed, prefer a synchronous stop for determinism.
105+
try {
106+
var sw = Stopwatch.StartNew();
107+
PinMame.PinMame.StopRunningGame();
108+
Logger.Info($"[PinMAME] Stop call returned after {sw.ElapsedMilliseconds}ms");
109+
} catch (Exception e) {
110+
Logger.Warn(e, "[PinMAME] StopGame failed while exiting play mode.");
134111
}
112+
_stopTask = System.Threading.Tasks.Task.CompletedTask;
135113
}
136114

137115
private static void Update()
138116
{
139-
bool running;
117+
int runState;
140118
try {
141-
running = PinMame.PinMame.IsRunning;
119+
runState = PinMame.PinMame.RunState;
142120
} catch {
143-
running = false;
121+
runState = 0;
144122
}
123+
var running = runState != 0;
145124

146125
var stopDone = _stopTask == null || _stopTask.IsCompleted;
147126
if (!running && stopDone) {
148127
EditorApplication.update -= Update;
149128
_stopping = false;
150129
_warnedTimeout = false;
151130
_stopTask = null;
152-
Logger.Warn($"{LogPrefix} [PinMAME] Stopped (editor)");
131+
Logger.Info("[PinMAME] Stopped (editor)");
153132
return;
154133
}
155134

156135
if (!_warnedTimeout && _stopwatch != null && _stopwatch.ElapsedMilliseconds > StopTimeoutMs) {
157136
_warnedTimeout = true;
158-
Logger.Warn($"{LogPrefix} [PinMAME] Still running after stop timeout (editor)");
137+
Logger.Warn($"[PinMAME] Still running after stop timeout (editor), RunState={runState}");
159138
}
160139
}
161140
}

0 commit comments

Comments
 (0)