TraceRegistry.cs
85 lines
| 2.8 KiB
| text/x-csharp
|
CSharpLexer
|
|
r289 | using System; | |
| using System.Collections.Generic; | |||
| using System.Diagnostics; | |||
| using Implab.Parallels; | |||
| namespace Implab.Diagnostics { | |||
| public class TraceRegistry: IObservable<TraceChannel> { | |||
| class Subscription : IDisposable { | |||
| readonly WeakReference<TraceRegistry> m_registry; | |||
| public Subscription(TraceRegistry registry) { | |||
| m_registry = new WeakReference<TraceRegistry>(registry); | |||
| } | |||
| public void Dispose() { | |||
| TraceRegistry t; | |||
| if (m_registry.TryGetTarget(out t)) | |||
| t.RemoveSubscription(this); | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// The global collection of available diagnostic channels | |||
| /// </summary> | |||
| /// <returns></returns> | |||
| public static TraceRegistry Global { get; } = new TraceRegistry(); | |||
| readonly object m_lock = new object(); | |||
| readonly Dictionary<object, IObserver<TraceChannel>> m_subscriptions = new Dictionary<object, IObserver<TraceChannel>>(); | |||
| readonly SimpleAsyncQueue<TraceChannel> m_channels = new SimpleAsyncQueue<TraceChannel>(); | |||
| public void Register(TraceChannel channel) { | |||
| // notifications can run in parallel | |||
| IObserver<TraceChannel>[] handlers = null; | |||
| lock(m_lock) { | |||
| m_channels.Enqueue(channel); | |||
| if (m_subscriptions.Count > 0) { | |||
| handlers = new IObserver<TraceChannel>[m_subscriptions.Count]; | |||
| m_subscriptions.Values.CopyTo(handlers, 0); | |||
| } | |||
| } | |||
| if (handlers != null) | |||
| foreach(var h in handlers) | |||
| h.OnNext(channel); | |||
| } | |||
| /// <summary> | |||
| /// Subscribes the specified handler to notifications about new trace | |||
| /// channels | |||
| /// </summary> | |||
| /// <param name="handler"></param> | |||
| /// <returns></returns> | |||
| public IDisposable Subscribe(IObserver<TraceChannel> handler) { | |||
| Safe.ArgumentNotNull(handler, nameof(handler)); | |||
| var cookie = new Subscription(this); | |||
| IEnumerable<TraceChannel> snap; | |||
| // lock to ensure that no new channels will be added | |||
| // while the subscription is added | |||
| lock(m_lock) { | |||
| m_subscriptions.Add(cookie, handler); | |||
| snap = m_channels.Snapshot(); | |||
| } | |||
| // announce previously declared channels if required | |||
| if (snap != null) { | |||
| foreach(var c in snap) | |||
| handler.OnNext(c); | |||
| } | |||
| // return the subscription | |||
| return cookie; | |||
| } | |||
| void RemoveSubscription(object cookie) { | |||
| lock(m_lock) | |||
| m_subscriptions.Remove(cookie); | |||
| } | |||
| } | |||
| } |
