TraceRegistry.cs
85 lines
| 2.8 KiB
| text/x-csharp
|
CSharpLexer
cin
|
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); | |||
} | |||
} | |||
} |