-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fd561f3
commit d3ebe52
Showing
22 changed files
with
818 additions
and
378 deletions.
There are no files selected for viewing
149 changes: 149 additions & 0 deletions
149
src/AsyncFiberWorks.Windows/Timer/IntervalWaitableTimerEx.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
using AsyncFiberWorks.Core; | ||
using AsyncFiberWorks.Fibers; | ||
using System; | ||
using System.Threading; | ||
|
||
namespace AsyncFiberWorks.Windows.Timer | ||
{ | ||
/// <summary> | ||
/// Timer using WaitableTimerEx in Windows. | ||
/// This timer starts a dedicated thread. | ||
/// </summary> | ||
public class IntervalWaitableTimerEx : IIntervalTimer, IDisposable | ||
{ | ||
readonly ThreadFiber _thread; | ||
readonly WaitableTimerEx _waitableTimer; | ||
readonly ManualResetEventSlim _resetEvent = new ManualResetEventSlim(); | ||
WaitHandle[] _waitHandles = null; | ||
int _scheduled = 0; | ||
bool _disposed = false; | ||
|
||
object _lockObj { get { return _waitableTimer; } } | ||
|
||
/// <summary> | ||
/// Create a timer. | ||
/// </summary> | ||
public IntervalWaitableTimerEx() | ||
{ | ||
_thread = new ThreadFiber(); | ||
_waitableTimer = new WaitableTimerEx(manualReset: false); | ||
} | ||
|
||
/// <summary> | ||
/// Start a repeating timer. | ||
/// </summary> | ||
/// <param name="action">The process to be called when the timer expires.</param> | ||
/// <param name="firstIntervalMs">Initial wait time. Must be greater than or equal to 0.</param> | ||
/// <param name="intervalMs">The waiting interval time after the second time. Must be greater than 0.</param> | ||
/// <param name="token">A handle to cancel the timer.</param> | ||
public void ScheduleOnInterval(Action action, int firstIntervalMs, int intervalMs, CancellationToken token = default) | ||
{ | ||
if (firstIntervalMs < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(firstIntervalMs), $"{nameof(firstIntervalMs)} must be greater than or equal to 0."); | ||
} | ||
if (intervalMs <= 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(intervalMs), $"{nameof(intervalMs)} must be greater than 0."); | ||
} | ||
|
||
var copiedAction = action; | ||
lock (_lockObj) | ||
{ | ||
if (_disposed) | ||
{ | ||
throw new ObjectDisposedException(this.GetType().FullName); | ||
} | ||
if (_scheduled > 0) | ||
{ | ||
_resetEvent.Set(); | ||
} | ||
_scheduled += 1; | ||
|
||
_thread.Enqueue(() => | ||
{ | ||
lock (_lockObj) | ||
{ | ||
if (_scheduled > 1) | ||
{ | ||
_scheduled -= 1; | ||
return; | ||
} | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
_resetEvent.Reset(); | ||
SetWaitHandles(token); | ||
} | ||
|
||
_waitableTimer.Set(firstIntervalMs * -10000L, intervalMs); | ||
int index = WaitHandle.WaitAny(_waitHandles); | ||
if (index == 0) | ||
{ | ||
copiedAction(); | ||
} | ||
else | ||
{ | ||
_waitableTimer.Cancel(); | ||
} | ||
|
||
lock (_lockObj) | ||
{ | ||
_scheduled -= 1; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
private void SetWaitHandles(CancellationToken externalToken) | ||
{ | ||
if (externalToken.CanBeCanceled) | ||
{ | ||
const int needSize = 3; | ||
if ((_waitHandles?.Length ?? 0) != needSize) | ||
{ | ||
_waitHandles = new WaitHandle[needSize]; | ||
} | ||
_waitHandles[0] = _waitableTimer; | ||
_waitHandles[1] = _resetEvent.WaitHandle; | ||
_waitHandles[2] = externalToken.WaitHandle; | ||
} | ||
else | ||
{ | ||
const int needSize = 2; | ||
if ((_waitHandles?.Length ?? 0) != needSize) | ||
{ | ||
_waitHandles = new WaitHandle[needSize]; | ||
} | ||
_waitHandles[0] = _waitableTimer; | ||
_waitHandles[1] = _resetEvent.WaitHandle; | ||
} | ||
} | ||
|
||
void DisposeResources() | ||
{ | ||
_waitableTimer.Dispose(); | ||
_resetEvent.Dispose(); | ||
_thread.Dispose(); | ||
_waitHandles = null; | ||
} | ||
|
||
/// <summary> | ||
/// Stop the timer. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
lock (_lockObj) | ||
{ | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
_disposed = true; | ||
_resetEvent.Set(); | ||
_thread.Enqueue(DisposeResources); | ||
} | ||
} | ||
} | ||
} |
144 changes: 144 additions & 0 deletions
144
src/AsyncFiberWorks.Windows/Timer/OneshotWaitableTimerEx.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
using AsyncFiberWorks.Core; | ||
using AsyncFiberWorks.Fibers; | ||
using System; | ||
using System.Threading; | ||
|
||
namespace AsyncFiberWorks.Windows.Timer | ||
{ | ||
/// <summary> | ||
/// Timer using WaitableTimerEx in Windows. | ||
/// This timer starts a dedicated thread. | ||
/// </summary> | ||
public class OneshotWaitableTimerEx : IOneshotTimer, IDisposable | ||
{ | ||
readonly ThreadFiber _thread; | ||
readonly WaitableTimerEx _waitableTimer; | ||
readonly ManualResetEventSlim _resetEvent = new ManualResetEventSlim(); | ||
WaitHandle[] _waitHandles = null; | ||
int _scheduled = 0; | ||
bool _disposed = false; | ||
|
||
object _lockObj { get { return _waitableTimer; } } | ||
|
||
/// <summary> | ||
/// Create a timer. | ||
/// </summary> | ||
public OneshotWaitableTimerEx() | ||
{ | ||
_thread = new ThreadFiber(); | ||
_waitableTimer = new WaitableTimerEx(manualReset: false); | ||
} | ||
|
||
/// <summary> | ||
/// Start a timer. | ||
/// </summary> | ||
/// <param name="action">The process to be called when the timer expires.</param> | ||
/// <param name="firstIntervalMs">Timer wait time. Must be greater than or equal to 0.</param> | ||
/// <param name="token">A handle to cancel the timer.</param> | ||
public void Schedule(Action action, int firstIntervalMs, CancellationToken token = default) | ||
{ | ||
if (firstIntervalMs < 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(firstIntervalMs), $"{nameof(firstIntervalMs)} must be greater than or equal to 0."); | ||
} | ||
|
||
var copiedAction = action; | ||
lock (_lockObj) | ||
{ | ||
if (_disposed) | ||
{ | ||
throw new ObjectDisposedException(this.GetType().FullName); | ||
} | ||
if (_scheduled > 0) | ||
{ | ||
_resetEvent.Set(); | ||
} | ||
_scheduled += 1; | ||
|
||
_thread.Enqueue(() => | ||
{ | ||
lock (_lockObj) | ||
{ | ||
if (_scheduled > 1) | ||
{ | ||
_scheduled -= 1; | ||
return; | ||
} | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
_resetEvent.Reset(); | ||
SetWaitHandles(token); | ||
} | ||
|
||
_waitableTimer.Set(firstIntervalMs * -10000L); | ||
int index = WaitHandle.WaitAny(_waitHandles); | ||
if (index == 0) | ||
{ | ||
copiedAction(); | ||
} | ||
else | ||
{ | ||
_waitableTimer.Cancel(); | ||
} | ||
|
||
lock (_lockObj) | ||
{ | ||
_scheduled -= 1; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
private void SetWaitHandles(CancellationToken externalToken) | ||
{ | ||
if (externalToken.CanBeCanceled) | ||
{ | ||
const int needSize = 3; | ||
if ((_waitHandles?.Length ?? 0) != needSize) | ||
{ | ||
_waitHandles = new WaitHandle[needSize]; | ||
} | ||
_waitHandles[0] = _waitableTimer; | ||
_waitHandles[1] = _resetEvent.WaitHandle; | ||
_waitHandles[2] = externalToken.WaitHandle; | ||
} | ||
else | ||
{ | ||
const int needSize = 2; | ||
if ((_waitHandles?.Length ?? 0) != needSize) | ||
{ | ||
_waitHandles = new WaitHandle[needSize]; | ||
} | ||
_waitHandles[0] = _waitableTimer; | ||
_waitHandles[1] = _resetEvent.WaitHandle; | ||
} | ||
} | ||
|
||
void DisposeResources() | ||
{ | ||
_waitableTimer.Dispose(); | ||
_resetEvent.Dispose(); | ||
_thread.Dispose(); | ||
_waitHandles = null; | ||
} | ||
|
||
/// <summary> | ||
/// Stop the timer. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
lock (_lockObj) | ||
{ | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
_disposed = true; | ||
_resetEvent.Set(); | ||
_thread.Enqueue(DisposeResources); | ||
} | ||
} | ||
} | ||
} |
60 changes: 0 additions & 60 deletions
60
src/AsyncFiberWorks.Windows/Timer/WaitableTimerExFactory.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System; | ||
using System.Threading; | ||
|
||
namespace AsyncFiberWorks.Core | ||
{ | ||
/// <summary> | ||
/// Repeating timer. | ||
/// </summary> | ||
public interface IIntervalTimer : IDisposable | ||
{ | ||
/// <summary> | ||
/// Start a repeating timer. | ||
/// </summary> | ||
/// <param name="action">The process to be called when the timer expires.</param> | ||
/// <param name="firstIntervalMs">Initial wait time. Must be greater than or equal to 0.</param> | ||
/// <param name="intervalMs">The waiting interval time after the second time. Must be greater than 0.</param> | ||
/// <param name="cancellation">A handle to cancel the timer.</param> | ||
void ScheduleOnInterval(Action action, int firstIntervalMs, int intervalMs, CancellationToken cancellation = default); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.