using System; using System.Collections.Generic; using System.Diagnostics; using Implab.Parallels; namespace Implab.Diagnostics { public class TraceChannelRegistry { class Subscription : IDisposable { readonly Action m_unsubscribe; public Subscription(Action unsubscribe) { m_unsubscribe = unsubscribe; } public void Dispose() { m_unsubscribe(this); } } public static TraceChannelRegistry AllCannels { get; } = new TraceChannelRegistry(); readonly object m_lock = new object(); readonly Dictionary> m_subscriptions = new Dictionary>(); readonly SimpleAsyncQueue m_channels = new SimpleAsyncQueue(); internal void NotifyChannelCreated(ChannelInfo channel) { // notifications can run in parallel Action[] handlers = null; lock(m_lock) { m_channels.Enqueue(channel); if (m_subscriptions.Count > 0) { handlers = new Action[m_subscriptions.Count]; m_subscriptions.Values.CopyTo(handlers, 0); } } if (handlers != null) foreach(var h in handlers) h(channel); } /// /// Subscribes the specified handler to notifications about new trace /// channels /// /// /// public IDisposable Subscribe(Action handler, bool existing) { Safe.ArgumentNotNull(handler, nameof(handler)); var cookie = new Subscription(RemoveSubscription); IEnumerable snap; lock(m_lock) { m_subscriptions.Add(cookie, handler); snap = m_channels.Snapshot(); } if (existing) { foreach(var c in snap) handler(c); } return cookie; } void RemoveSubscription(object cookie) { lock(m_lock) m_subscriptions.Remove(cookie); } } }