PeriodicTimerSystemClockMonitor
(Infrastructure) Monitors for system clock changes based on a periodic timer.
using System.ComponentModel;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace System.Reactive.PlatformServices
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
[EditorBrowsable(EditorBrowsableState.Never)]
public class PeriodicTimerSystemClockMonitor : INotifySystemClockChanged
{
private readonly TimeSpan _period;
private SerialDisposableValue _timer;
private long _lastTimeUnixMillis;
[System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
private EventHandler<SystemClockChangedEventArgs> _systemClockChanged;
private const int SyncMaxRetries = 100;
private const double SyncMaxDelta = 10;
private const int MaxError = 100;
public event EventHandler<SystemClockChangedEventArgs> SystemClockChanged {
add {
NewTimer();
_systemClockChanged = (EventHandler<SystemClockChangedEventArgs>)Delegate.Combine(_systemClockChanged, value);
}
remove {
_systemClockChanged = (EventHandler<SystemClockChangedEventArgs>)Delegate.Remove(_systemClockChanged, value);
_timer.Disposable = Disposable.Empty;
}
}
public PeriodicTimerSystemClockMonitor(TimeSpan period)
{
_period = period;
}
private void NewTimer()
{
_timer.Disposable = Disposable.Empty;
long num = 0;
while (true) {
DateTimeOffset utcNow = SystemClock.UtcNow;
long num2 = utcNow.ToUnixTimeMilliseconds();
Interlocked.Exchange(ref _lastTimeUnixMillis, num2);
_timer.Disposable = ConcurrencyAbstractionLayer.Current.StartPeriodicTimer(TimeChanged, _period);
utcNow = SystemClock.UtcNow;
if ((double)Math.Abs(utcNow.ToUnixTimeMilliseconds() - num2) <= 10 || _timer.Disposable == Disposable.Empty)
break;
if (++num >= 100)
Task.Delay(10).Wait();
}
}
private void TimeChanged()
{
DateTimeOffset utcNow = SystemClock.UtcNow;
long num = utcNow.ToUnixTimeMilliseconds();
long num2 = (long)((double)Volatile.Read(ref _lastTimeUnixMillis) + _period.TotalMilliseconds);
if (Math.Abs(num - num2) >= 100) {
_systemClockChanged?.Invoke(this, new SystemClockChangedEventArgs(DateTimeOffset.FromUnixTimeMilliseconds(num2), utcNow));
NewTimer();
} else
Interlocked.Exchange(ref _lastTimeUnixMillis, SystemClock.UtcNow.ToUnixTimeMilliseconds());
}
}
}