TraceRegistry.cs
85 lines
| 2.8 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r286 | using System; | |
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using Implab.Parallels; | |||
namespace Implab.Diagnostics { | |||
cin
|
r288 | public class TraceRegistry: IObservable<TraceChannel> { | |
cin
|
r286 | ||
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); | |||
} | |||
} | |||
cin
|
r288 | /// <summary> | |
/// The global collection of available diagnostic channels | |||
/// </summary> | |||
/// <returns></returns> | |||
cin
|
r286 | public static TraceRegistry Global { get; } = new TraceRegistry(); | |
readonly object m_lock = new object(); | |||
cin
|
r288 | readonly Dictionary<object, IObserver<TraceChannel>> m_subscriptions = new Dictionary<object, IObserver<TraceChannel>>(); | |
cin
|
r286 | readonly SimpleAsyncQueue<TraceChannel> m_channels = new SimpleAsyncQueue<TraceChannel>(); | |
cin
|
r288 | public void Register(TraceChannel channel) { | |
cin
|
r286 | // notifications can run in parallel | |
cin
|
r288 | IObserver<TraceChannel>[] handlers = null; | |
cin
|
r286 | ||
lock(m_lock) { | |||
m_channels.Enqueue(channel); | |||
if (m_subscriptions.Count > 0) { | |||
cin
|
r288 | handlers = new IObserver<TraceChannel>[m_subscriptions.Count]; | |
cin
|
r286 | m_subscriptions.Values.CopyTo(handlers, 0); | |
} | |||
} | |||
if (handlers != null) | |||
foreach(var h in handlers) | |||
cin
|
r288 | h.OnNext(channel); | |
cin
|
r286 | } | |
/// <summary> | |||
/// Subscribes the specified handler to notifications about new trace | |||
/// channels | |||
/// </summary> | |||
/// <param name="handler"></param> | |||
/// <returns></returns> | |||
cin
|
r288 | public IDisposable Subscribe(IObserver<TraceChannel> handler) { | |
cin
|
r286 | 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 | |||
cin
|
r288 | if (snap != null) { | |
cin
|
r286 | foreach(var c in snap) | |
cin
|
r288 | handler.OnNext(c); | |
cin
|
r286 | } | |
// return the subscription | |||
return cookie; | |||
} | |||
void RemoveSubscription(object cookie) { | |||
lock(m_lock) | |||
m_subscriptions.Remove(cookie); | |||
} | |||
} | |||
} |