diff Implab.Diagnostics.Interactive/InteractiveListener.cs @ 50:f8cbe84cfdb1

Слияние с interactive logger
author cin
date Fri, 18 Apr 2014 12:37:48 +0400
parents d9d794b61bb9
children 790e8a997d30
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Diagnostics.Interactive/InteractiveListener.cs	Fri Apr 18 12:37:48 2014 +0400
@@ -0,0 +1,122 @@
+using Implab.Parallels;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Implab.Diagnostics.Interactive
+{
+    public class InteractiveListener: TextListenerBase
+    {
+        TraceForm m_form;
+        
+        SynchronizationContext m_syncGuiThread;
+        readonly Promise<object> m_guiStarted = new Promise<object>();
+        
+        readonly IPromiseBase m_guiFinished;
+        readonly IPromiseBase m_workerFinished = new Promise<object>();
+        
+        readonly MTQueue<TraceViewItem> m_queue = new MTQueue<TraceViewItem>();
+        readonly AutoResetEvent m_queueEvent = new AutoResetEvent(false);
+        
+        int m_queueLength;
+        bool m_exitPending;
+
+        readonly object m_pauseLock = new object();
+        bool m_paused;
+        readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
+
+        public InteractiveListener(bool global) : base(global) {
+            m_guiFinished = AsyncPool.InvokeNewThread(GuiThread);
+            m_workerFinished = AsyncPool.InvokeNewThread(QueueThread);
+
+            m_guiStarted.Join();
+        }
+
+        void GuiThread() {
+            m_form = new TraceForm(); // will create SynchronizationContext
+
+            m_form.PauseEvents += (s,a) => Pause();
+            m_form.ResumeEvents += (s, a) => Resume();
+
+            m_syncGuiThread = SynchronizationContext.Current;
+            m_guiStarted.Resolve();
+            Application.Run();
+        }
+
+        void QueueThread() {
+            while (!m_exitPending) {
+                if (m_paused)
+                    m_pauseEvent.WaitOne();
+                
+                TraceViewItem item;
+                if (m_queue.TryDequeue(out item)) {
+                    Interlocked.Decrement(ref m_queueLength);
+
+                    m_syncGuiThread.Send(x => m_form.AddTraceEvent(item),null);
+                } else {
+                    m_queueEvent.WaitOne();
+                }
+            }
+        }
+
+        public void Pause() {
+            // for consistency we need to set this properties atomically
+            lock (m_pauseLock) {
+                m_pauseEvent.Reset();
+                m_paused = true;
+            }
+        }
+
+        public void Resume() {
+            // for consistency we need to set this properties atomically
+            lock (m_pauseLock) {
+                m_paused = false;
+                m_pauseEvent.Set();
+            }
+        }
+
+        void Enqueue(TraceViewItem item) {
+            m_queue.Enqueue(item);
+            if (Interlocked.Increment(ref m_queueLength) == 1)
+                m_queueEvent.Set();
+        }
+
+        public void ShowForm() {
+            m_syncGuiThread.Post(x => m_form.Show(), null);
+        }
+
+        public void HideForm() {
+            m_syncGuiThread.Post(x => m_form.Hide(), null);
+        }
+
+        void Terminate() {
+            m_exitPending = true;
+            Resume();            
+            m_syncGuiThread.Post(x => Application.ExitThread(), null);
+        }
+
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+                Terminate();
+                m_guiFinished.Join();
+            }
+            base.Dispose(disposing);
+        }
+
+        protected override void WriteEntry(TraceContext context, EventText text, string channel) {
+            var item = new TraceViewItem {
+                Indent = text.indent,
+                Message = text.content,
+                Thread = context.ThreadId,
+                Channel = channel,
+                Timestamp = Environment.TickCount
+            };
+
+            Enqueue(item);
+        }
+    }
+}