From 6e3e50d4c3ca10af75f7b545a0055c2f300de17a Mon Sep 17 00:00:00 2001 From: Jonas Fabisiak Date: Sat, 11 Feb 2023 09:15:37 +0100 Subject: [PATCH] fix: check against race condition while converting data Add a check, if the converting is still ongoing, to simply skip it in the current thread to avoid race conditions --- changelog.md | 4 ++ scs-client/C#/SCSSdkClient/SCSSdkConvert.cs | 22 ++++---- scs-client/C#/SCSSdkClient/SCSSdkTelemetry.cs | 50 ++++++++++++------- scs-client/C#/SCSSdkClient/SharedMemory.cs | 4 +- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/changelog.md b/changelog.md index 4c85cad..3982681 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## Rev 12, Update 1 + +- fix: add check to avoid a race condition when converting the data + ## Rev 12, former Rev 11 Update 1 Change version to 12, because of offset changes. This leads to a rev change and not just an update like it was before. diff --git a/scs-client/C#/SCSSdkClient/SCSSdkConvert.cs b/scs-client/C#/SCSSdkClient/SCSSdkConvert.cs index b78483d..d3615b8 100644 --- a/scs-client/C#/SCSSdkClient/SCSSdkConvert.cs +++ b/scs-client/C#/SCSSdkClient/SCSSdkConvert.cs @@ -1,9 +1,4 @@ -// -// Ets2SdkClient -// Ets2SdkDataAlt.cs -// 22:51 - -using System; +using System; using System.Text; using SCSSdkClient.Object; @@ -14,8 +9,8 @@ namespace SCSSdkClient { /// public class SCSSdkConvert { private const int StringSize = 64; - private const int Substances = 25; private const int WheelSize = 16; + private const int Substances = 25; private readonly int[] _offsetAreas = {0, 40, 500, 700, 1500, 1640, 2000, 2200, 2300, 4000, 4200, 4300, 4400, 6000}; @@ -25,6 +20,8 @@ public class SCSSdkConvert { private int _offsetArea; + private bool currentlyActive = false; + /// /// Convert the Shared Memory Byte data structure in a C# object /// @@ -35,6 +32,12 @@ public class SCSSdkConvert { /// C# object with game data of the shared memory /// public SCSTelemetry Convert(byte[] structureDataBytes) { + if (currentlyActive) { + return null; + } + + currentlyActive = true; + _offsetArea = 0; SetOffset(); @@ -388,6 +391,8 @@ public SCSTelemetry Convert(byte[] structureDataBytes) { #endregion 14TH ZONE + currentlyActive = false; + return retData; } @@ -399,6 +404,7 @@ private bool GetBool() { private bool[] GetBoolArray(int length) { var res = new bool[length]; + for (var i = 0; i < length; i++) { res[i] = GetBool(); } @@ -594,7 +600,6 @@ private SCSTelemetry.Trailer GetTrailer() { private SCSTelemetry.Trailer[] GetTrailers() { var trailer = new SCSTelemetry.Trailer[10]; - //TODO : only 1 for old game versions for (var i = 0; i < 10; i++) { trailer[i] = GetTrailer(); @@ -640,7 +645,6 @@ private void NextOffsetArea() { } private void SetOffset() { - // Debug Fix? if (_offsetArea >= _offsetAreas.Length) { return; } diff --git a/scs-client/C#/SCSSdkClient/SCSSdkTelemetry.cs b/scs-client/C#/SCSSdkClient/SCSSdkTelemetry.cs index 8934b5e..776f4c8 100644 --- a/scs-client/C#/SCSSdkClient/SCSSdkTelemetry.cs +++ b/scs-client/C#/SCSSdkClient/SCSSdkTelemetry.cs @@ -3,14 +3,15 @@ using SCSSdkClient.Object; namespace SCSSdkClient { + /// /// Data Event - /// + /// /// The parameter **newTimeStamp** is deprecated and will be removed in a future release. - /// + /// /// - /// - /// + /// + /// /// All data of the telemetry /// Flag if the data changed public delegate void TelemetryData(SCSTelemetry data, bool newTimestamp); @@ -19,27 +20,27 @@ namespace SCSSdkClient { /// Handle the SCSSdkTelemetry. /// Currently IDisposable. Was implemented because of an error /// - public class SCSSdkTelemetry : IDisposable { + public class SCSSdkTelemetry: IDisposable { private const string DefaultSharedMemoryMap = "Local\\SCSTelemetry"; private const int DefaultUpdateInterval = 100; private const int DefaultPausedUpdateInterval = 1000; private int updateInterval; - // todo: enhancement: some way to set this value + // todo: enhancement: some way to set this value private readonly int pausedUpdateInterval = DefaultPausedUpdateInterval; private Timer _updateTimer; private ulong lastTime = 0xFFFFFFFFFFFFFFFF; - #if LOGGING public void Dispose() { _updateTimer?.Dispose(); Log.SaveShutdown(); } #else + public void Dispose() => _updateTimer?.Dispose(); #endif @@ -69,20 +70,28 @@ public void Dispose() { public string Map { get; private set; } public int UpdateInterval => paused ? pausedUpdateInterval : updateInterval; - public Exception Error { get; private set; } public event TelemetryData Data; public event EventHandler JobStarted; + public event EventHandler JobCancelled; + public event EventHandler JobDelivered; + public event EventHandler Fined; + public event EventHandler Tollgate; + public event EventHandler Ferry; + public event EventHandler Train; + public event EventHandler RefuelStart; + public event EventHandler RefuelEnd; + public event EventHandler RefuelPayed; public void pause() => _updateTimer.Change(Timeout.Infinite, Timeout.Infinite); @@ -127,9 +136,13 @@ private void Setup(string map, int interval) { private void _updateTimer_Elapsed(object sender) { var scsTelemetry = SharedMemory.Update(); + if (scsTelemetry == null) { + return; + } + // check if sdk is NOT running if (!scsTelemetry.SdkActive && !paused) { - // if so don't check so often the data + // if so don't check so often the data var tsInterval = new TimeSpan(0, 0, 0, 0, DefaultPausedUpdateInterval); _updateTimer.Change(tsInterval.Add(tsInterval), tsInterval); paused = true; @@ -182,43 +195,41 @@ private void _updateTimer_Elapsed(object sender) { if (delivered != scsTelemetry.SpecialEventsValues.JobDelivered) { delivered = scsTelemetry.SpecialEventsValues.JobDelivered; - + if (!updated) { Data?.Invoke(scsTelemetry, true); updated = true; } - JobDelivered?.Invoke(this, new EventArgs()); + JobDelivered?.Invoke(this, new EventArgs()); } if (fined != scsTelemetry.SpecialEventsValues.Fined) { fined = scsTelemetry.SpecialEventsValues.Fined; - - Fined?.Invoke(this, new EventArgs()); + + Fined?.Invoke(this, new EventArgs()); } if (tollgate != scsTelemetry.SpecialEventsValues.Tollgate) { tollgate = scsTelemetry.SpecialEventsValues.Tollgate; - Tollgate?.Invoke(this, new EventArgs()); - } if (ferry != scsTelemetry.SpecialEventsValues.Ferry) { ferry = scsTelemetry.SpecialEventsValues.Ferry; - + if (!updated) { Data?.Invoke(scsTelemetry, true); updated = true; } - Ferry?.Invoke(this, new EventArgs()); + Ferry?.Invoke(this, new EventArgs()); } if (train != scsTelemetry.SpecialEventsValues.Train) { train = scsTelemetry.SpecialEventsValues.Train; - + if (!updated) { Data?.Invoke(scsTelemetry, true); updated = true; @@ -252,6 +263,7 @@ private void _updateTimer_Elapsed(object sender) { Data?.Invoke(scsTelemetry, false); } } + #if LOGGING private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { try { @@ -269,4 +281,4 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc } #endif } -} \ No newline at end of file +} diff --git a/scs-client/C#/SCSSdkClient/SharedMemory.cs b/scs-client/C#/SCSSdkClient/SharedMemory.cs index b2330f0..5bdeb27 100644 --- a/scs-client/C#/SCSSdkClient/SharedMemory.cs +++ b/scs-client/C#/SCSSdkClient/SharedMemory.cs @@ -3,10 +3,12 @@ using SCSSdkClient.Object; namespace SCSSdkClient { + /// /// Manage the shared memory /// public class SharedMemory { + /// /// size of the shared memory in bytes /// @@ -119,4 +121,4 @@ public void Update() { /// Managed object from given bytes protected SCSTelemetry ToObject(byte[] structureDataBytes) => _sdkconvert.Convert(structureDataBytes); } -} \ No newline at end of file +}