From c349757c006f6e72ae2508be903a571330a37c46 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Mon, 19 Oct 2020 12:24:22 -0400 Subject: [PATCH] refactor: Cleaned up SafeTimer, added duration validation to clarify bad values --- ICD.Common.Utils/Timers/SafeTimer.cs | 58 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/ICD.Common.Utils/Timers/SafeTimer.cs b/ICD.Common.Utils/Timers/SafeTimer.cs index 554a49f..254b42d 100644 --- a/ICD.Common.Utils/Timers/SafeTimer.cs +++ b/ICD.Common.Utils/Timers/SafeTimer.cs @@ -2,25 +2,26 @@ using ICD.Common.Utils.Services; using ICD.Common.Utils.Services.Logging; #if SIMPLSHARP -using Crestron.SimplSharp; +using Timer = Crestron.SimplSharp.CTimer; +using Timeout = Crestron.SimplSharp.Timeout; #else -using System.Threading; +using Timer = System.Threading.Timer; +using Timeout = System.Threading.Timeout; #endif namespace ICD.Common.Utils.Timers { /// - /// SafeTimer wraps CTimer to hide some of the jank. + /// SafeTimer is a platform agnostic timer that better handles disposal than the underlying timer. /// public sealed class SafeTimer : IStateDisposable { -#if SIMPLSHARP - private readonly CTimer m_Timer; -#else - private readonly Timer m_Timer; + private readonly Timer m_Timer; + private Action m_Callback; + +#if !SIMPLSHARP private int m_RepeatPeriod; #endif - private Action m_Callback; /// /// Returns true if this instance has been disposed. @@ -30,12 +31,12 @@ namespace ICD.Common.Utils.Timers #region Constructors /// - /// Creates a timer that is called every repeatPeriod in milliseconds. + /// Creates a timer that is called immediately and then every repeatPeriod in milliseconds. /// /// /// public SafeTimer(Action callback, long repeatPeriod) - : this(callback, 0, repeatPeriod) + : this(callback, -1, repeatPeriod) { } @@ -52,12 +53,9 @@ namespace ICD.Common.Utils.Timers throw new ArgumentNullException("callback"); m_Callback = callback; -#if SIMPLSHARP - m_Timer = new CTimer(SafeCallback, null, dueTime, repeatPeriod); -#else - m_RepeatPeriod = (int)repeatPeriod; - m_Timer = new Timer(SafeCallback, null, (int)dueTime, m_RepeatPeriod); -#endif + m_Timer = new Timer(SafeCallback, null, Timeout.Infinite, Timeout.Infinite); + + Reset(dueTime, repeatPeriod); } /// @@ -67,10 +65,7 @@ namespace ICD.Common.Utils.Timers /// public static SafeTimer Stopped(Action callback) { - //No due time or repeat period on a stopped timer - SafeTimer output = new SafeTimer(callback, -1, -1); - output.Stop(); - return output; + return new SafeTimer(callback, Timeout.Infinite, Timeout.Infinite); } #endregion @@ -124,11 +119,7 @@ namespace ICD.Common.Utils.Timers /// public void Reset(long dueTime) { -#if SIMPLSHARP - m_Timer.Reset(dueTime); -#else - m_Timer.Change((int)dueTime, Timeout.Infinite); -#endif + Reset(dueTime, Timeout.Infinite); } /// @@ -138,6 +129,18 @@ namespace ICD.Common.Utils.Timers /// public void Reset(long dueTime, long repeatPeriod) { + if (dueTime < 0 && dueTime != Timeout.Infinite) + throw new ArgumentOutOfRangeException("dueTime", "DueTime must be greater than or equal to 0ms"); + + if (dueTime >= int.MaxValue) + throw new ArgumentOutOfRangeException("dueTime", string.Format("DueTime must be less than {0:n0}ms", int.MaxValue)); + + if (repeatPeriod < 0 && repeatPeriod != Timeout.Infinite) + throw new ArgumentOutOfRangeException("repeatPeriod", "Repeat period must be greater than or equal to 0ms"); + + if (dueTime >= int.MaxValue) + throw new ArgumentOutOfRangeException("repeatPeriod", string.Format("Repeat period must be less than {0:n0}ms", int.MaxValue)); + #if SIMPLSHARP m_Timer.Reset(dueTime, repeatPeriod); #else @@ -158,10 +161,9 @@ namespace ICD.Common.Utils.Timers private void SafeCallback(object unused) { // Essentially the meat of this class. There's some weirdness with the garbage collector where - // the reference to the timer will be cleared, and eventually the CTimer will call the callback + // the reference to the timer will be cleared, and eventually the Timer will call the callback // despite being stopped/disposed. - if (IsDisposed || - m_Timer == null + if (IsDisposed || m_Timer == null #if SIMPLSHARP || m_Timer.Disposed #endif