diff options
Diffstat (limited to 'Rx.NET/System.Reactive.Core/Reactive/Internal/SystemClock.Default.cs')
-rw-r--r-- | Rx.NET/System.Reactive.Core/Reactive/Internal/SystemClock.Default.cs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/Rx.NET/System.Reactive.Core/Reactive/Internal/SystemClock.Default.cs b/Rx.NET/System.Reactive.Core/Reactive/Internal/SystemClock.Default.cs new file mode 100644 index 0000000..b9c8167 --- /dev/null +++ b/Rx.NET/System.Reactive.Core/Reactive/Internal/SystemClock.Default.cs @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System.ComponentModel; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; + +namespace System.Reactive.PlatformServices +{ + /// <summary> + /// (Infrastructure) Provides access to the local system clock. + /// </summary> + [EditorBrowsable(EditorBrowsableState.Never)] + public class DefaultSystemClock : ISystemClock + { + /// <summary> + /// Gets the current time. + /// </summary> + public DateTimeOffset UtcNow + { + get { return DateTimeOffset.UtcNow; } + } + } + + internal class DefaultSystemClockMonitor : PeriodicTimerSystemClockMonitor + { + private static readonly TimeSpan DEFAULT_PERIOD = TimeSpan.FromSeconds(1); + + public DefaultSystemClockMonitor() + : base(DEFAULT_PERIOD) + { + } + } + + /// <summary> + /// (Infrastructure) Monitors for system clock changes based on a periodic timer. + /// </summary> + [EditorBrowsable(EditorBrowsableState.Never)] + public class PeriodicTimerSystemClockMonitor : INotifySystemClockChanged + { + private readonly TimeSpan _period; + private readonly SerialDisposable _timer; + + private DateTimeOffset _lastTime; + private EventHandler<SystemClockChangedEventArgs> _systemClockChanged; + + private const int SYNC_MAXRETRIES = 100; + private const double SYNC_MAXDELTA = 10; + private const int MAXERROR = 100; + + /// <summary> + /// Creates a new monitor for system clock changes with the specified polling frequency. + /// </summary> + /// <param name="period">Polling frequency for system clock changes.</param> + public PeriodicTimerSystemClockMonitor(TimeSpan period) + { + _period = period; + _timer = new SerialDisposable(); + } + + /// <summary> + /// Event that gets raised when a system clock change is detected. + /// </summary> + public event EventHandler<SystemClockChangedEventArgs> SystemClockChanged + { + add + { + NewTimer(); + + _systemClockChanged += value; + } + + remove + { + _systemClockChanged -= value; + + _timer.Disposable = Disposable.Empty; + } + } + + private void NewTimer() + { + _timer.Disposable = Disposable.Empty; + + var n = 0; + do + { + _lastTime = SystemClock.UtcNow; + _timer.Disposable = ConcurrencyAbstractionLayer.Current.StartPeriodicTimer(TimeChanged, _period); + } while (Math.Abs((SystemClock.UtcNow - _lastTime).TotalMilliseconds) > SYNC_MAXDELTA && ++n < SYNC_MAXRETRIES); + + if (n >= SYNC_MAXRETRIES) + throw new InvalidOperationException(Strings_Core.FAILED_CLOCK_MONITORING); + } + + private void TimeChanged() + { + var now = SystemClock.UtcNow; + var diff = now - (_lastTime + _period); + if (Math.Abs(diff.TotalMilliseconds) >= MAXERROR) + { + var scc = _systemClockChanged; + if (scc != null) + scc(this, new SystemClockChangedEventArgs(_lastTime + _period, now)); + + NewTimer(); + } + else + { + _lastTime = SystemClock.UtcNow; + } + } + } +} |