[#94122] SystemCPeripheral: Fix Dispose race condition There was a race between the background thread receiving the TCP FIN message (closing the socket cleanly) and the socket.Close() call in Dispose. If the background thread did not get scheduled and got a chance to exit cleanly before .Close() was called, the socket was aborted by the kernel, causing an exception to be thrown.
diff --git a/src/Plugins/SystemCPlugin/Peripheral/SystemCPeripheral.cs b/src/Plugins/SystemCPlugin/Peripheral/SystemCPeripheral.cs index cf2825c..2cfd98e 100644 --- a/src/Plugins/SystemCPlugin/Peripheral/SystemCPeripheral.cs +++ b/src/Plugins/SystemCPlugin/Peripheral/SystemCPeripheral.cs
@@ -271,6 +271,27 @@ } } + try + { + forwardSocket?.Shutdown(SocketShutdown.Both); + } + catch(SocketException ex) + { + this.DebugLog("Exception when shutting down forward socket: {0}", ex.Message); + } + try + { + backwardSocket?.Shutdown(SocketShutdown.Both); + } + catch(SocketException ex) + { + this.DebugLog("Exception when shutting down backward socket: {0}", ex.Message); + } + if(backwardThreadStarted) + { + // Give the backward connection thread some time to gracefully shut down the TCP connection. + backwardThread.Join(TimeSpan.FromMilliseconds(500)); + } forwardSocket?.Close(); backwardSocket?.Close(); } @@ -477,6 +498,7 @@ SendRequest(new RenodeMessage(RenodeAction.Init, 0, 0, 0, (ulong)timeSyncPeriodUS), out var response); backwardThread.Start(); + backwardThreadStarted = true; } private void SetupTimesync() @@ -733,6 +755,7 @@ private ulong outGPIOState; private Process systemcProcess; private string systemcExecutablePath; + private bool backwardThreadStarted = false; private readonly Dictionary<int, IDirectAccessPeripheral> directAccessPeripherals;