view 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 source

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);
        }
    }
}