# HG changeset patch # User cin # Date 1503395101 -10800 # Node ID 1ba2127cfcd8896d2ca877aab1d4c4bfa34e94c6 # Parent 8808383fcb949eb102145e3942202179cc0b26e5# Parent 27ea7f07e2e407eb93561cf391fa53e7c4c39809 Слияние с default diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Diagnostics.Interactive/InteractiveListener.cs --- a/Implab.Diagnostics.Interactive/InteractiveListener.cs Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Diagnostics.Interactive/InteractiveListener.cs Tue Aug 22 12:45:01 2017 +0300 @@ -17,7 +17,6 @@ readonly Promise m_guiStarted = new Promise(); readonly IPromise m_guiFinished; - // readonly IPromise m_workerFinished = new Promise(); readonly MTQueue m_queue = new MTQueue(); readonly AutoResetEvent m_queueEvent = new AutoResetEvent(false); @@ -30,8 +29,8 @@ readonly ManualResetEvent m_pauseEvent = new ManualResetEvent(true); public InteractiveListener() { - m_guiFinished = AsyncPool.RunThread(GuiThread); - /*m_workerFinished = */AsyncPool.RunThread(QueueThread); + m_guiFinished = RunGuiThread(); + AsyncPool.RunThread(QueueThread); m_guiStarted.Join(); } @@ -56,13 +55,38 @@ if (m_queue.TryDequeue(out item)) { Interlocked.Decrement(ref m_queueLength); - m_syncGuiThread.Send(x => m_form.AddTraceEvent(item),null); + m_syncGuiThread.Post(x => m_form.AddTraceEvent(item),null); } else { m_queueEvent.WaitOne(); } } } + public IPromise RunGuiThread() { + var p = new Promise(); + + var caller = TraceContext.Instance.CurrentOperation; + + var worker = new Thread(() => { + TraceContext.Instance.EnterLogicalOperation(caller, false); + try { + Application.OleRequired(); + GuiThread(); + p.Resolve(); + } catch (Exception e) { + p.Reject(e); + } finally { + TraceContext.Instance.Leave(); + } + }); + worker.SetApartmentState(ApartmentState.STA); + worker.IsBackground = true; + worker.Name = string.Format("{0} GUI Thread", nameof(InteractiveListener)); + worker.Start(); + + return p; + } + public void Pause() { // for consistency we need to set this properties atomically lock (m_pauseLock) { @@ -112,8 +136,9 @@ Indent = args.Operation.Level, Message = entry.ToString(), Thread = args.ThreadId, - Channel = args.ChannelName, - Timestamp = Environment.TickCount + Channel = args.Channel.ToString(), + Timestamp = Environment.TickCount, + TimeDelta = args.OperationTimeOffset }; Enqueue(item); diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Diagnostics.Interactive/TraceForm.Designer.cs --- a/Implab.Diagnostics.Interactive/TraceForm.Designer.cs Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Diagnostics.Interactive/TraceForm.Designer.cs Tue Aug 22 12:45:01 2017 +0300 @@ -23,13 +23,14 @@ /// the contents of this method with the code editor. /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); this.eventsDataGrid = new System.Windows.Forms.DataGridView(); - this.traceViewItemBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.traceViewItemBindingSource = new System.Windows.Forms.BindingSource(); this.threadDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.TimeDelta = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Channel = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.messageDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.eventsDataGrid)).BeginInit(); @@ -56,20 +57,22 @@ this.eventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.eventsDataGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.threadDataGridViewTextBoxColumn, + this.TimeDelta, this.Channel, this.messageDataGridViewTextBoxColumn}); this.eventsDataGrid.DataSource = this.traceViewItemBindingSource; - dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle3.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - dataGridViewCellStyle3.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle3.SelectionBackColor = System.Drawing.SystemColors.Highlight; - dataGridViewCellStyle3.SelectionForeColor = System.Drawing.SystemColors.HighlightText; - dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.eventsDataGrid.DefaultCellStyle = dataGridViewCellStyle3; + dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle4.BackColor = System.Drawing.SystemColors.Window; + dataGridViewCellStyle4.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + dataGridViewCellStyle4.ForeColor = System.Drawing.SystemColors.ControlText; + dataGridViewCellStyle4.SelectionBackColor = System.Drawing.SystemColors.Highlight; + dataGridViewCellStyle4.SelectionForeColor = System.Drawing.SystemColors.HighlightText; + dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.eventsDataGrid.DefaultCellStyle = dataGridViewCellStyle4; this.eventsDataGrid.Location = new System.Drawing.Point(12, 12); this.eventsDataGrid.Name = "eventsDataGrid"; this.eventsDataGrid.ReadOnly = true; + this.eventsDataGrid.RowHeadersVisible = false; this.eventsDataGrid.RowHeadersWidth = 17; this.eventsDataGrid.RowTemplate.Resizable = System.Windows.Forms.DataGridViewTriState.False; this.eventsDataGrid.Size = new System.Drawing.Size(939, 480); @@ -82,31 +85,43 @@ // // threadDataGridViewTextBoxColumn // - this.threadDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader; + this.threadDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; this.threadDataGridViewTextBoxColumn.DataPropertyName = "Thread"; this.threadDataGridViewTextBoxColumn.HeaderText = "TID"; this.threadDataGridViewTextBoxColumn.Name = "threadDataGridViewTextBoxColumn"; this.threadDataGridViewTextBoxColumn.ReadOnly = true; - this.threadDataGridViewTextBoxColumn.Width = 5; + this.threadDataGridViewTextBoxColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.threadDataGridViewTextBoxColumn.Width = 32; + // + // TimeDelta + // + this.TimeDelta.DataPropertyName = "TimeDelta"; + dataGridViewCellStyle2.Format = "\'+\' 0 \'ms\'"; + dataGridViewCellStyle2.NullValue = null; + this.TimeDelta.DefaultCellStyle = dataGridViewCellStyle2; + this.TimeDelta.HeaderText = "TimeDelta"; + this.TimeDelta.Name = "TimeDelta"; + this.TimeDelta.ReadOnly = true; + this.TimeDelta.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // Channel // - this.Channel.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells; this.Channel.DataPropertyName = "Channel"; this.Channel.HeaderText = "Channel"; this.Channel.Name = "Channel"; this.Channel.ReadOnly = true; - this.Channel.Width = 79; + this.Channel.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // messageDataGridViewTextBoxColumn // this.messageDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; this.messageDataGridViewTextBoxColumn.DataPropertyName = "FormattedMessage"; - dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.messageDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2; + dataGridViewCellStyle3.WrapMode = System.Windows.Forms.DataGridViewTriState.False; + this.messageDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle3; this.messageDataGridViewTextBoxColumn.HeaderText = "Message"; this.messageDataGridViewTextBoxColumn.Name = "messageDataGridViewTextBoxColumn"; this.messageDataGridViewTextBoxColumn.ReadOnly = true; + this.messageDataGridViewTextBoxColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // TraceForm // @@ -127,8 +142,8 @@ private System.Windows.Forms.DataGridView eventsDataGrid; private System.Windows.Forms.BindingSource traceViewItemBindingSource; private System.Windows.Forms.DataGridViewTextBoxColumn threadDataGridViewTextBoxColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn TimeDelta; private System.Windows.Forms.DataGridViewTextBoxColumn Channel; private System.Windows.Forms.DataGridViewTextBoxColumn messageDataGridViewTextBoxColumn; - } } \ No newline at end of file diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Diagnostics.Interactive/TraceForm.cs --- a/Implab.Diagnostics.Interactive/TraceForm.cs Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Diagnostics.Interactive/TraceForm.cs Tue Aug 22 12:45:01 2017 +0300 @@ -31,7 +31,8 @@ public void AddTraceEvent(TraceViewItem item) { traceViewItemBindingSource.Add(item); - eventsDataGrid.FirstDisplayedScrollingRowIndex = eventsDataGrid.RowCount - 1; + if(eventsDataGrid.RowCount > 0) + eventsDataGrid.FirstDisplayedScrollingRowIndex = eventsDataGrid.RowCount - 1; } Color GetThreadColor(int thread) { diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Diagnostics.Interactive/TraceForm.resx --- a/Implab.Diagnostics.Interactive/TraceForm.resx Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Diagnostics.Interactive/TraceForm.resx Tue Aug 22 12:45:01 2017 +0300 @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + True + True diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Diagnostics.Interactive/TraceViewItem.cs --- a/Implab.Diagnostics.Interactive/TraceViewItem.cs Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Diagnostics.Interactive/TraceViewItem.cs Tue Aug 22 12:45:01 2017 +0300 @@ -9,6 +9,7 @@ string m_formattedValue; public string Message { get; set; } + public int TimeDelta { get; set; } public int Timestamp { get; set; } public int Indent { get; set; } public int Thread { get; set; } diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Fx.Test/Implab.Fx.Test.csproj --- a/Implab.Fx.Test/Implab.Fx.Test.csproj Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Fx.Test/Implab.Fx.Test.csproj Tue Aug 22 12:45:01 2017 +0300 @@ -80,6 +80,7 @@ OverlayForm.cs + diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Fx.Test/StaApartmentTests.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab.Fx.Test/StaApartmentTests.cs Tue Aug 22 12:45:01 2017 +0300 @@ -0,0 +1,52 @@ +using System; +using System.Reflection; +using System.Threading; +using Implab.Parallels; +using Implab.Components; + +#if MONO + +using NUnit.Framework; +using TestClassAttribute = NUnit.Framework.TestFixtureAttribute; +using TestMethodAttribute = NUnit.Framework.TestAttribute; +using AssertFailedException = NUnit.Framework.AssertionException; +#else + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +#endif +namespace Implab.Fx.Test { + [TestClass] + public class StaApartmentTests { + [TestMethod] + public void CreateDestroyApartment() { + var apartment = new StaApartment(); + try { + Assert.IsNotNull(apartment.SyncContext); + Assert.Fail(); + } catch (InvalidOperationException) { + // OK + } + + apartment.Start().Join(); + Assert.AreEqual(apartment.State, ExecutionState.Running); + + Assert.IsNotNull(apartment.SyncContext); + apartment.Stop().Join(); + + Assert.IsTrue(apartment.State == ExecutionState.Disposed); + } + + [TestMethod] + public void InvokeInApartment() { + var apartment = new StaApartment(); + + apartment.Start().Join(); + + var apType = apartment.Invoke(() => { return Thread.CurrentThread.GetApartmentState(); }).Join(); + Assert.AreEqual(apType, ApartmentState.STA); + + apartment.Stop().Join(); + } + } +} diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Fx/Implab.Fx.csproj --- a/Implab.Fx/Implab.Fx.csproj Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Fx/Implab.Fx.csproj Tue Aug 22 12:45:01 2017 +0300 @@ -70,6 +70,7 @@ + diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Fx/StaApartment.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab.Fx/StaApartment.cs Tue Aug 22 12:45:01 2017 +0300 @@ -0,0 +1,204 @@ +using Implab.Components; +using Implab.Diagnostics; +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.Fx { + public class StaApartment : RunnableComponent { + readonly Thread m_worker; + SynchronizationContext m_syncContext; + SyncContextPromise m_enterPromise; + + readonly Promise m_threadStarted; + readonly Promise m_threadTerminated; + + public StaApartment() : base(true) { + m_threadStarted = new Promise(); + m_threadTerminated = new Promise(); + + m_worker = new Thread(WorkerEntry); + m_worker.SetApartmentState(ApartmentState.STA); + m_worker.IsBackground = true; + m_worker.Name = "STA managed aparment"; + } + + public SynchronizationContext SyncContext { + get { + if (m_syncContext == null) + throw new InvalidOperationException(); + return m_syncContext; + } + } + + /// + /// Returns the promise which will dispatch all handlers inside the apartment using it's + /// + /// + /// Current implementation is optimized and will lost aync operation stack + /// + /// The promise + public IPromise Enter() { + if (m_enterPromise == null) + throw new InvalidOperationException(); + return m_enterPromise; + } + + public IPromise Invoke(Action action) { + Safe.ArgumentNotNull(action, "action"); + + if (m_syncContext == null) + throw new InvalidOperationException(); + var p = new Promise(); + var lop = TraceContext.Instance.CurrentOperation; + + m_syncContext.Post(x => { + TraceContext.Instance.EnterLogicalOperation(lop, false); + try { + if (p.CancelOperationIfRequested()) + return; + + action(p); + p.Resolve(); + } catch (Exception e) { + p.Reject(e); + } finally { + TraceContext.Instance.Leave(); + } + }, null); + + return p; + } + + public IPromise Invoke(Func action) { + Safe.ArgumentNotNull(action, "action"); + + if (m_syncContext == null) + throw new InvalidOperationException(); + var p = new Promise(); + var lop = TraceContext.Instance.CurrentOperation; + + m_syncContext.Post(x => { + TraceContext.Instance.EnterLogicalOperation(lop, false); + try { + if (p.CancelOperationIfRequested()) + return; + p.Resolve(action(p)); + } catch (Exception e) { + p.Reject(e); + } finally { + TraceContext.Instance.Leave(); + } + }, null); + + return p; + } + + public IPromise Invoke(Action action) { + Safe.ArgumentNotNull(action, "action"); + + if (m_syncContext == null) + throw new InvalidOperationException(); + var p = new Promise(); + var lop = TraceContext.Instance.CurrentOperation; + + m_syncContext.Post(x => { + TraceContext.Instance.EnterLogicalOperation(lop, false); + try { + if (p.CancelOperationIfRequested()) + return; + action(); + p.Resolve(); + } catch (Exception e) { + p.Reject(e); + } finally { + TraceContext.Instance.Leave(); + } + }, null); + + return p; + } + + public IPromise Invoke(Func action) { + Safe.ArgumentNotNull(action, "action"); + + if (m_syncContext == null) + throw new InvalidOperationException(); + var p = new Promise(); + var lop = TraceContext.Instance.CurrentOperation; + + m_syncContext.Post(x => { + TraceContext.Instance.EnterLogicalOperation(lop, false); + try { + if (p.CancelOperationIfRequested()) + return; + p.Resolve(action()); + } catch (Exception e) { + p.Reject(e); + } finally { + TraceContext.Instance.Leave(); + } + }, null); + + return p; + } + + + /// + /// Starts the apartment thread + /// + /// Promise which will be fullfiled when the syncronization + /// context will be ready to accept tasks. + protected override IPromise OnStart() { + m_worker.Start(); + return m_threadStarted; + } + + /// + /// Posts quit message to the message loop of the apartment + /// + /// Promise + protected override IPromise OnStop() { + m_syncContext.Post(x => Application.ExitThread(), null); + return m_threadTerminated; + } + + void WorkerEntry() { + m_syncContext = new WindowsFormsSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(m_syncContext); + m_enterPromise = new SyncContextPromise(m_syncContext); + m_threadStarted.Resolve(); + m_enterPromise.Resolve(); + + Application.OleRequired(); + Application.Run(); + + try { + OnShutdown(); + m_threadTerminated.Resolve(); + } catch(Exception err) { + m_threadTerminated.Reject(err); + } + } + + /// + /// Called from the STA apartment after the message loop is terminated, override this + /// method to handle apartment cleanup. + /// + protected virtual void OnShutdown() { + } + + protected override void Dispose(bool disposing) { + if (disposing) { + if (!m_threadTerminated.IsResolved) + m_syncContext.Post(x => Application.ExitThread(), null); + } + base.Dispose(disposing); + } + } +} diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Test/AsyncTests.cs --- a/Implab.Test/AsyncTests.cs Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Test/AsyncTests.cs Tue Aug 22 12:45:01 2017 +0300 @@ -336,7 +336,7 @@ Console.WriteLine("done reader #2: {0} ms", Environment.TickCount - t1); } ) - .Bundle() + .PromiseAll() .Join(); Assert.AreEqual(count * 3, res1 + res2); @@ -414,7 +414,7 @@ Console.WriteLine("done reader #2: {0} ms", Environment.TickCount - t1); } ) - .Bundle() + .PromiseAll() .Join(); Assert.AreEqual(summ , r1 + r2); @@ -490,7 +490,7 @@ Console.WriteLine("done reader #2: {0} ms, avg chunk size: {1}", Environment.TickCount - t1, avgchunk); } ) - .Bundle() + .PromiseAll() .Join(); Assert.AreEqual(summ , r1 + r2); @@ -593,7 +593,7 @@ Console.WriteLine("done reader #2: {0} ms, {1} items", Environment.TickCount - t1, count); } ) - .Bundle() + .PromiseAll() .Join(); Assert.AreEqual(summ , r1 + r2); @@ -835,7 +835,7 @@ log.Enqueue("Writer #1 lock released"); } } - ).Bundle().Join(1000); + ).PromiseAll().Join(1000); log.Enqueue("Done"); } catch(Exception error) { log.Enqueue(error.Message); diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Test/Implab.Format.Test/Implab.Format.Test.csproj --- a/Implab.Test/Implab.Format.Test/Implab.Format.Test.csproj Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Test/Implab.Format.Test/Implab.Format.Test.csproj Tue Aug 22 12:45:01 2017 +0300 @@ -1,52 +1,55 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {4D364996-7ECD-4193-8F90-F223FFEA49DA} - Library - Implab.Format.Test - Implab.Format.Test - v4.5 - 0.2 - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - full - true - bin\Release - prompt - 4 - false - - - - - ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - - - - - - - {F550F1F8-8746-4AD0-9614-855F4C4B7F05} - Implab - - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {4D364996-7ECD-4193-8F90-F223FFEA49DA} + Library + Implab.Format.Test + Implab.Format.Test + v4.5 + 0.2 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll + + + + + + + + + {F550F1F8-8746-4AD0-9614-855F4C4B7F05} + Implab + + + + + + + + \ No newline at end of file diff -r 27ea7f07e2e4 -r 1ba2127cfcd8 Implab.Test/Implab.Test.csproj --- a/Implab.Test/Implab.Test.csproj Tue Aug 22 09:35:54 2017 +0300 +++ b/Implab.Test/Implab.Test.csproj Tue Aug 22 12:45:01 2017 +0300 @@ -63,6 +63,9 @@ + + + @@ -73,6 +76,9 @@ Implab + + +