diff Implab.Diagnostics.Interactive/InteractiveListener.cs @ 47:b181f7bcb259 interactive logger

refactoring, interactive tarce log almost complete
author cin
date Thu, 17 Apr 2014 18:49:36 +0400
parents
children d9d794b61bb9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Diagnostics.Interactive/InteractiveListener.cs	Thu Apr 17 18:49:36 2014 +0400
@@ -0,0 +1,107 @@
+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: Disposable
+    {
+        TraceForm m_form;
+        
+        SynchronizationContext m_syncGuiThread;
+        
+        readonly IPromiseBase m_guiFinished;
+        readonly Promise<object> m_guiStarted = new Promise<object>();
+
+        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() {
+            m_guiFinished = AsyncPool.InvokeNewThread(() => {
+                GuiThread();
+                return 0;
+            });
+
+            m_guiStarted.Join();
+        }
+
+        void GuiThread() {
+            m_form = new TraceForm(); // will create SynchronizationContext
+            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_syncGuiThread.Post(x => Application.ExitThread(), null);
+        }
+
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+                Terminate();
+                m_guiFinished.Join();
+            }
+            base.Dispose(disposing);
+        }
+    }
+}