refactor: Cleaned up SafeTimer, added duration validation to clarify bad values

This commit is contained in:
Chris Cameron
2020-10-19 12:24:22 -04:00
parent 8c70c8d534
commit c349757c00

View File

@@ -2,25 +2,26 @@
using ICD.Common.Utils.Services; using ICD.Common.Utils.Services;
using ICD.Common.Utils.Services.Logging; using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP #if SIMPLSHARP
using Crestron.SimplSharp; using Timer = Crestron.SimplSharp.CTimer;
using Timeout = Crestron.SimplSharp.Timeout;
#else #else
using System.Threading; using Timer = System.Threading.Timer;
using Timeout = System.Threading.Timeout;
#endif #endif
namespace ICD.Common.Utils.Timers namespace ICD.Common.Utils.Timers
{ {
/// <summary> /// <summary>
/// SafeTimer wraps CTimer to hide some of the jank. /// SafeTimer is a platform agnostic timer that better handles disposal than the underlying timer.
/// </summary> /// </summary>
public sealed class SafeTimer : IStateDisposable 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; private int m_RepeatPeriod;
#endif #endif
private Action m_Callback;
/// <summary> /// <summary>
/// Returns true if this instance has been disposed. /// Returns true if this instance has been disposed.
@@ -30,12 +31,12 @@ namespace ICD.Common.Utils.Timers
#region Constructors #region Constructors
/// <summary> /// <summary>
/// Creates a timer that is called every repeatPeriod in milliseconds. /// Creates a timer that is called immediately and then every repeatPeriod in milliseconds.
/// </summary> /// </summary>
/// <param name="callback"></param> /// <param name="callback"></param>
/// <param name="repeatPeriod"></param> /// <param name="repeatPeriod"></param>
public SafeTimer(Action callback, long repeatPeriod) 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"); throw new ArgumentNullException("callback");
m_Callback = callback; m_Callback = callback;
#if SIMPLSHARP m_Timer = new Timer(SafeCallback, null, Timeout.Infinite, Timeout.Infinite);
m_Timer = new CTimer(SafeCallback, null, dueTime, repeatPeriod);
#else Reset(dueTime, repeatPeriod);
m_RepeatPeriod = (int)repeatPeriod;
m_Timer = new Timer(SafeCallback, null, (int)dueTime, m_RepeatPeriod);
#endif
} }
/// <summary> /// <summary>
@@ -67,10 +65,7 @@ namespace ICD.Common.Utils.Timers
/// <returns></returns> /// <returns></returns>
public static SafeTimer Stopped(Action callback) public static SafeTimer Stopped(Action callback)
{ {
//No due time or repeat period on a stopped timer return new SafeTimer(callback, Timeout.Infinite, Timeout.Infinite);
SafeTimer output = new SafeTimer(callback, -1, -1);
output.Stop();
return output;
} }
#endregion #endregion
@@ -124,11 +119,7 @@ namespace ICD.Common.Utils.Timers
/// <param name="dueTime"></param> /// <param name="dueTime"></param>
public void Reset(long dueTime) public void Reset(long dueTime)
{ {
#if SIMPLSHARP Reset(dueTime, Timeout.Infinite);
m_Timer.Reset(dueTime);
#else
m_Timer.Change((int)dueTime, Timeout.Infinite);
#endif
} }
/// <summary> /// <summary>
@@ -138,6 +129,18 @@ namespace ICD.Common.Utils.Timers
/// <param name="repeatPeriod"></param> /// <param name="repeatPeriod"></param>
public void Reset(long dueTime, long repeatPeriod) 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 #if SIMPLSHARP
m_Timer.Reset(dueTime, repeatPeriod); m_Timer.Reset(dueTime, repeatPeriod);
#else #else
@@ -158,10 +161,9 @@ namespace ICD.Common.Utils.Timers
private void SafeCallback(object unused) private void SafeCallback(object unused)
{ {
// Essentially the meat of this class. There's some weirdness with the garbage collector where // 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. // despite being stopped/disposed.
if (IsDisposed || if (IsDisposed || m_Timer == null
m_Timer == null
#if SIMPLSHARP #if SIMPLSHARP
|| m_Timer.Disposed || m_Timer.Disposed
#endif #endif