SystemClock
(Infrastructure) Provides access to local system clock services.
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Concurrency;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Reactive.PlatformServices
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
[EditorBrowsable(EditorBrowsableState.Never)]
public static class SystemClock
{
private static readonly Lazy<ISystemClock> ServiceSystemClock = new Lazy<ISystemClock>(InitializeSystemClock);
private static readonly Lazy<INotifySystemClockChanged> ServiceSystemClockChanged = new Lazy<INotifySystemClockChanged>(InitializeSystemClockChanged);
internal static readonly HashSet<WeakReference<LocalScheduler>> SystemClockChanged = new HashSet<WeakReference<LocalScheduler>>();
[System.Runtime.CompilerServices.Nullable(2)]
private static IDisposable _systemClockChangedHandlerCollector;
private static int _refCount;
public static DateTimeOffset UtcNow => ServiceSystemClock.Value.UtcNow;
public static void AddRef()
{
if (Interlocked.Increment(ref _refCount) == 1)
ServiceSystemClockChanged.Value.SystemClockChanged += OnSystemClockChanged;
}
public static void Release()
{
if (Interlocked.Decrement(ref _refCount) == 0)
ServiceSystemClockChanged.Value.SystemClockChanged -= OnSystemClockChanged;
}
internal static void OnSystemClockChanged([System.Runtime.CompilerServices.Nullable(2)] object sender, SystemClockChangedEventArgs e)
{
lock (SystemClockChanged) {
foreach (WeakReference<LocalScheduler> item in new List<WeakReference<LocalScheduler>>(SystemClockChanged)) {
if (item.TryGetTarget(out LocalScheduler target))
target.SystemClockChanged(sender, e);
}
}
}
private static ISystemClock InitializeSystemClock()
{
return PlatformEnlightenmentProvider.Current.GetService<ISystemClock>(Array.Empty<object>()) ?? new DefaultSystemClock();
}
private static INotifySystemClockChanged InitializeSystemClockChanged()
{
return PlatformEnlightenmentProvider.Current.GetService<INotifySystemClockChanged>(Array.Empty<object>()) ?? new DefaultSystemClockMonitor();
}
internal static void Register(LocalScheduler scheduler)
{
lock (SystemClockChanged) {
SystemClockChanged.Add(new WeakReference<LocalScheduler>(scheduler));
if (SystemClockChanged.Count == 1)
_systemClockChangedHandlerCollector = ConcurrencyAbstractionLayer.Current.StartPeriodicTimer(CollectHandlers, TimeSpan.FromSeconds(30));
else if (SystemClockChanged.Count % 64 == 0) {
CollectHandlers();
}
}
}
private static void CollectHandlers()
{
lock (SystemClockChanged) {
HashSet<WeakReference<LocalScheduler>> hashSet = null;
HashSet<WeakReference<LocalScheduler>>.Enumerator enumerator = SystemClockChanged.GetEnumerator();
try {
while (enumerator.MoveNext()) {
WeakReference<LocalScheduler> current = enumerator.Current;
if (!current.TryGetTarget(out LocalScheduler _)) {
if (hashSet == null)
hashSet = new HashSet<WeakReference<LocalScheduler>>();
hashSet.Add(current);
}
}
} finally {
((IDisposable)enumerator).Dispose();
}
if (hashSet != null) {
enumerator = hashSet.GetEnumerator();
try {
while (enumerator.MoveNext()) {
WeakReference<LocalScheduler> current2 = enumerator.Current;
SystemClockChanged.Remove(current2);
}
} finally {
((IDisposable)enumerator).Dispose();
}
}
if (SystemClockChanged.Count == 0) {
_systemClockChangedHandlerCollector?.Dispose();
_systemClockChangedHandlerCollector = null;
}
}
}
}
}