diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CrowMonitor.cs | 61 | ||||
| -rw-r--r-- | src/CrowThread.cs | 2 | ||||
| -rw-r--r-- | src/GraphicObjects/GraphicObject.cs | 89 | ||||
| -rw-r--r-- | src/GraphicObjects/Image.cs | 6 | ||||
| -rw-r--r-- | src/GraphicObjects/MessageBox.cs | 26 | ||||
| -rw-r--r-- | src/GraphicObjects/TemplatedGroup.cs | 24 | ||||
| -rw-r--r-- | src/Interface.cs | 98 |
7 files changed, 194 insertions, 112 deletions
diff --git a/src/CrowMonitor.cs b/src/CrowMonitor.cs new file mode 100644 index 00000000..53b20070 --- /dev/null +++ b/src/CrowMonitor.cs @@ -0,0 +1,61 @@ +// +// CrowMonitor.cs +// +// Author: +// Jean-Philippe Bruyère <jp.bruyere@hotmail.com> +// +// Copyright (c) 2013-2017 Jean-Philippe Bruyère +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Threading; +using System.Diagnostics; + +namespace Crow +{ + public class NamedMutex { + public string Name; + public NamedMutex (string name){ + Name = name; + } + } + public static class CrowMonitor + { + public static Stopwatch timer = Stopwatch.StartNew(); + + public static bool TryEnter (NamedMutex mutex, string ctxName = "?"){ + Console.WriteLine("{3}:TRY LCK:{0} => {1} ({2})", Thread.CurrentThread.Name, mutex.Name, ctxName, timer.ElapsedTicks); + bool locking = Monitor.TryEnter (mutex); + if (locking) + Console.WriteLine("{2}:\tLOCKED :{0} => {1} mutex", Thread.CurrentThread.Name, mutex.Name, timer.ElapsedTicks); + return locking; + + } + public static void Enter (NamedMutex mutex, string ctxName = "?") { + Console.WriteLine("{3}:WAIT :{0} => {1} ({2})", Thread.CurrentThread.Name, mutex.Name, ctxName, timer.ElapsedTicks); + Monitor.Enter (mutex); + Console.WriteLine("{3}:\tLOCKED :{0} => {1} mutex ({2})", Thread.CurrentThread.Name, mutex.Name, ctxName, timer.ElapsedTicks); + } + public static void Exit (NamedMutex mutex) { + Monitor.Exit (mutex); + Console.WriteLine("{2}:\tRELEASE:{0} => {1} mutex", Thread.CurrentThread.Name, mutex.Name, timer.ElapsedTicks); + } + } +} + diff --git a/src/CrowThread.cs b/src/CrowThread.cs index ece87fa8..1f0b1d76 100644 --- a/src/CrowThread.cs +++ b/src/CrowThread.cs @@ -33,7 +33,7 @@ namespace Crow /// Thread monitored by current interface with Finished event when state==Stopped /// </summary> public class CrowThread { - Thread thread; + internal Thread thread; public event EventHandler Finished; public GraphicObject Host; public CrowThread (GraphicObject host, ThreadStart start){ diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 5de94f60..559719a9 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -40,6 +40,7 @@ namespace Crow { public class GraphicObject : ILayoutable, IValueChange { + internal NamedMutex mutex = new NamedMutex("GRAPHIC OBJECT"); internal static ulong currentUid = 0; internal ulong uid = 0; @@ -162,8 +163,9 @@ namespace Crow if (parent == value) return; DataSourceChangeEventArgs e = new DataSourceChangeEventArgs (parent, value); - lock (this) - parent = value; + CrowMonitor.Enter (mutex, "set parent of object"); + parent = value; + CrowMonitor.Exit (mutex); onParentChanged (this, e); } @@ -887,12 +889,12 @@ namespace Crow public virtual void RegisterForLayouting(LayoutingType layoutType){ if (Parent == null) return; - lock (CurrentInterface.LayoutMutex) { - //prevent queueing same LayoutingType for this - layoutType &= (~RegisteredLayoutings); + CrowMonitor.Enter (CurrentInterface.LayoutMutex, "register for layouting"); + //prevent queueing same LayoutingType for this + layoutType &= (~RegisteredLayoutings); - if (layoutType == LayoutingType.None) - return; + if (layoutType != LayoutingType.None) { + //dont set position for stretched item if (Width == Measure.Stretched) layoutType &= (~LayoutingType.X); @@ -909,21 +911,21 @@ namespace Crow // //prevent queueing same LayoutingType for this // layoutType &= (~RegisteredLayoutings); - if (layoutType == LayoutingType.None) - return; - - //enqueue LQI LayoutingTypes separately - if (layoutType.HasFlag (LayoutingType.Width)) - CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Width, this)); - if (layoutType.HasFlag (LayoutingType.Height)) - CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Height, this)); - if (layoutType.HasFlag (LayoutingType.X)) - CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.X, this)); - if (layoutType.HasFlag (LayoutingType.Y)) - CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Y, this)); - if (layoutType.HasFlag (LayoutingType.ArrangeChildren)) - CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this)); + if (layoutType != LayoutingType.None) { + //enqueue LQI LayoutingTypes separately + if (layoutType.HasFlag (LayoutingType.Width)) + CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Width, this)); + if (layoutType.HasFlag (LayoutingType.Height)) + CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Height, this)); + if (layoutType.HasFlag (LayoutingType.X)) + CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.X, this)); + if (layoutType.HasFlag (LayoutingType.Y)) + CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Y, this)); + if (layoutType.HasFlag (LayoutingType.ArrangeChildren)) + CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this)); + } } + CrowMonitor.Exit (CurrentInterface.LayoutMutex); } /// <summary> trigger dependant sizing component update </summary> @@ -1154,33 +1156,36 @@ namespace Crow //TODO:this test should not be necessary if (Slot.Height < 0 || Slot.Width < 0 || parent == null) return; - lock (this) { - if (cacheEnabled) { - if (Slot.Width > Interface.MaxCacheSize || Slot.Height > Interface.MaxCacheSize) - cacheEnabled = false; - } + + CrowMonitor.Enter (mutex, "Paint"); - if (cacheEnabled) { - if (IsDirty) - RecreateCache (); + if (cacheEnabled) { + if (Slot.Width > Interface.MaxCacheSize || Slot.Height > Interface.MaxCacheSize) + cacheEnabled = false; + } - UpdateCache (ctx); - if (!isEnabled) - paintDisabled (ctx, Slot + Parent.ClientRectangle.Position); - } else { - Rectangle rb = Slot + Parent.ClientRectangle.Position; - ctx.Save (); + if (cacheEnabled) { + if (IsDirty) + RecreateCache (); - ctx.Translate (rb.X, rb.Y); + UpdateCache (ctx); + if (!isEnabled) + paintDisabled (ctx, Slot + Parent.ClientRectangle.Position); + } else { + Rectangle rb = Slot + Parent.ClientRectangle.Position; + ctx.Save (); - onDraw (ctx); - if (!isEnabled) - paintDisabled (ctx, Slot); + ctx.Translate (rb.X, rb.Y); - ctx.Restore (); - } - LastPaintedSlot = Slot; + onDraw (ctx); + if (!isEnabled) + paintDisabled (ctx, Slot); + + ctx.Restore (); } + LastPaintedSlot = Slot; + + CrowMonitor.Exit (mutex); } void paintDisabled(Context gr, Rectangle rb){ gr.Operator = Operator.Xor; diff --git a/src/GraphicObjects/Image.cs b/src/GraphicObjects/Image.cs index 6a4c590d..84385e85 100644 --- a/src/GraphicObjects/Image.cs +++ b/src/GraphicObjects/Image.cs @@ -79,9 +79,9 @@ namespace Crow if (string.IsNullOrEmpty(value)) Picture = null; else { - lock(CurrentInterface.LayoutMutex){ - LoadImage (value); - } + CrowMonitor.Enter(CurrentInterface.LayoutMutex, "load image"); + LoadImage (value); + CrowMonitor.Exit(CurrentInterface.LayoutMutex); } } catch (Exception ex) { Debug.WriteLine (ex.Message); diff --git a/src/GraphicObjects/MessageBox.cs b/src/GraphicObjects/MessageBox.cs index d8ce1dae..88be521e 100644 --- a/src/GraphicObjects/MessageBox.cs +++ b/src/GraphicObjects/MessageBox.cs @@ -132,18 +132,20 @@ namespace Crow close (); } public static MessageBox Show (Type msgBoxType, string message, string okMsg = "", string cancelMsg = ""){ - lock (Interface.CurrentInterface.UpdateMutex) { - MessageBox mb = new MessageBox (); - mb.Initialize (); - mb.CurrentInterface.AddWidget (mb); - mb.MsgType = msgBoxType; - mb.Message = message; - if (!string.IsNullOrEmpty(okMsg)) - mb.OkMessage = okMsg; - if (!string.IsNullOrEmpty(cancelMsg)) - mb.CancelMessage = cancelMsg; - return mb; - } + MessageBox mb = null; + CrowMonitor.Enter (Interface.CurrentInterface.UpdateMutex, "message box show"); + mb = new MessageBox (); + mb.Initialize (); + mb.CurrentInterface.AddWidget (mb); + mb.MsgType = msgBoxType; + mb.Message = message; + if (!string.IsNullOrEmpty(okMsg)) + mb.OkMessage = okMsg; + if (!string.IsNullOrEmpty(cancelMsg)) + mb.CancelMessage = cancelMsg; + CrowMonitor.Exit (Interface.CurrentInterface.UpdateMutex); + return mb; + } } } diff --git a/src/GraphicObjects/TemplatedGroup.cs b/src/GraphicObjects/TemplatedGroup.cs index eea3a184..c2184867 100644 --- a/src/GraphicObjects/TemplatedGroup.cs +++ b/src/GraphicObjects/TemplatedGroup.cs @@ -160,13 +160,15 @@ namespace Crow NotifyValueChanged ("Data", data); - lock (CurrentInterface.LayoutMutex) - ClearItems (); + CrowMonitor.Enter (CurrentInterface.LayoutMutex, "templated group enclosing clearItems"); + ClearItems (); + CrowMonitor.Exit (CurrentInterface.LayoutMutex); if (data == null) return; loadingThread = new CrowThread (this, loading); + loadingThread.thread.Name = "list loading thread"; loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e); loadingThread.Start (); @@ -324,8 +326,9 @@ namespace Crow if (page == items) return; - lock (CurrentInterface.LayoutMutex) - items.AddChild (page); + CrowMonitor.Enter (CurrentInterface.LayoutMutex, "templeted group add chile (page)"); + items.AddChild (page); + CrowMonitor.Exit (CurrentInterface.LayoutMutex); #if DEBUG_LOAD loadingTime.Stop (); @@ -377,12 +380,13 @@ namespace Crow iTemp = ItemTemplates ["default"]; } - lock (CurrentInterface.LayoutMutex) { - g = iTemp.CreateInstance(CurrentInterface); - page.AddChild (g); - //g.LogicalParent = this; - registerItemClick (g); - } + CrowMonitor.Enter (CurrentInterface.LayoutMutex, "templeted group add item to page"); + g = iTemp.CreateInstance(CurrentInterface); + page.AddChild (g); + //g.LogicalParent = this; + registerItemClick (g); + CrowMonitor.Exit (CurrentInterface.LayoutMutex); + if (iTemp.Expand != null && g is Expandable) { (g as Expandable).Expand += iTemp.Expand; diff --git a/src/Interface.cs b/src/Interface.cs index df6a5c67..ffb7e312 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -124,11 +124,13 @@ namespace Crow /// <summary>Coordinate of the dirty bmp on the original bmp</summary> public Rectangle DirtyRect; /// <summary>Locked for each layouting operation</summary> - public object LayoutMutex = new object(); + public NamedMutex LayoutMutex = new NamedMutex("LAYOUTING"); /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary> - public object RenderMutex = new object(); + public NamedMutex DrawingQueueMutex = new NamedMutex("DRAWING QUEUE"); + /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary> + public NamedMutex RenderMutex = new NamedMutex("RENDERING"); /// <summary>Global lock of the update cycle</summary> - public object UpdateMutex = new object(); + public NamedMutex UpdateMutex = new NamedMutex("UPDATE"); //TODO:share resource instances /// <summary> /// Store loaded resources instances shared among controls to reduce memory footprint @@ -255,12 +257,11 @@ namespace Crow /// of this Interface</summary> public GraphicObject LoadInterface (string path) { - lock (UpdateMutex) { - GraphicObject tmp = Load (path); - AddWidget (tmp); - - return tmp; - } + CrowMonitor.Enter (UpdateMutex, "load interface"); + GraphicObject tmp = Load (path); + AddWidget (tmp); + CrowMonitor.Exit (UpdateMutex); + return tmp; } /// <summary>Create an instance of a GraphicObject linked to this interface but /// not added to the GraphicTree</summary> @@ -368,12 +369,12 @@ namespace Crow /// GraphObj's property Set methods could trigger an update from another thread</summary> public void EnqueueForRepaint(GraphicObject g) { - lock (DrawingQueue) { - if (g.IsQueueForRedraw) - return; + CrowMonitor.Enter (DrawingQueueMutex, "engueue for repaint"); + if (!g.IsQueueForRedraw){ DrawingQueue.Enqueue (g); g.IsQueueForRedraw = true; } + CrowMonitor.Exit (DrawingQueueMutex); } /// <summary>Main Update loop, executed in this interface thread, lock the UpdateMutex /// Steps: @@ -406,8 +407,9 @@ namespace Crow for (int i = 0; i < tmpThreads.Length; i++) tmpThreads [i].CheckState (); - if (!Monitor.TryEnter (UpdateMutex)) + if (!CrowMonitor.TryEnter (UpdateMutex, "main update loop")) return; + #if MEASURE_TIME updateMeasure.StartCycle(); @@ -432,7 +434,7 @@ namespace Crow updateMeasure.StopCycle(); #endif - Monitor.Exit (UpdateMutex); + CrowMonitor.Exit (UpdateMutex); } /// <summary>Layouting loop, this is the first step of the udpate and process registered /// Layouting queue items. Failing LQI's are requeued in this cycle until MaxTry is reached which @@ -442,7 +444,7 @@ namespace Crow layoutingMeasure.StartCycle(); #endif - if (Monitor.TryEnter (LayoutMutex)) { + if (CrowMonitor.TryEnter (LayoutMutex, "main layouting loop")) { DiscardQueue = new Queue<LayoutingQueueItem> (); //Debug.WriteLine ("======= Layouting queue start ======="); LayoutingQueueItem lqi; @@ -455,7 +457,7 @@ namespace Crow lqi.ProcessLayouting (); } LayoutingQueue = DiscardQueue; - Monitor.Exit (LayoutMutex); + CrowMonitor.Exit (LayoutMutex); DiscardQueue = null; } @@ -472,10 +474,12 @@ namespace Crow #endif GraphicObject g = null; while (DrawingQueue.Count > 0) { - lock (DrawingQueue) - g = DrawingQueue.Dequeue (); - lock (g) - g.ClippingRegistration (); + CrowMonitor.Enter (DrawingQueueMutex, "clipping registration"); + g = DrawingQueue.Dequeue (); + CrowMonitor.Exit (DrawingQueueMutex); + CrowMonitor.Enter (g.mutex, "after dequeue, before entering clipping registration"); + g.ClippingRegistration (); + CrowMonitor.Exit (g.mutex); } #if MEASURE_TIME @@ -510,7 +514,7 @@ namespace Crow #if DEBUG_CLIP_RECTANGLE clipping.stroke (ctx, Color.Red.AdjustAlpha(0.5)); #endif - lock (RenderMutex) { + CrowMonitor.Enter (RenderMutex, "creating dirty rect"); // Array.Copy (bmp, dirtyBmp, bmp.Length); IsDirty = true; if (IsDirty) @@ -535,7 +539,7 @@ namespace Crow } else IsDirty = false; - } + CrowMonitor.Exit (RenderMutex); clipping.Reset (); } //surf.WriteToPng (@"/mnt/data/test.png"); @@ -565,8 +569,9 @@ namespace Crow } } - lock (UpdateMutex) - GraphicTree.Insert (ptr, g); + CrowMonitor.Enter (UpdateMutex, "interface add widget"); + GraphicTree.Insert (ptr, g); + CrowMonitor.Exit (UpdateMutex); g.RegisteredLayoutings = LayoutingType.None; g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren); @@ -578,11 +583,11 @@ namespace Crow if (g.Contains (_hoverWidget)) HoverWidget = null; } - lock (UpdateMutex) { - g.DataSource = null; - g.Visible = false; - GraphicTree.Remove (g); - } + CrowMonitor.Enter (UpdateMutex, "interface delete widget"); + g.DataSource = null; + g.Visible = false; + GraphicTree.Remove (g); + CrowMonitor.Exit (UpdateMutex); } /// <summary> Put widget on top of other root widgets</summary> public void PutOnTop(GraphicObject g, bool isOverlay = false) @@ -601,17 +606,20 @@ namespace Crow } if (GraphicTree.IndexOf(g) > ptr) { - lock (UpdateMutex) { + CrowMonitor.Enter (UpdateMutex, "interface put on top"); + GraphicTree.Remove (g); GraphicTree.Insert (ptr, g); - } + CrowMonitor.Exit (UpdateMutex); + EnqueueForRepaint (g); } } /// <summary> Remove all Graphic objects from top container </summary> public void ClearInterface() { - lock (UpdateMutex) { + CrowMonitor.Enter (UpdateMutex, "clear interface"); + while (GraphicTree.Count > 0) { //TODO:parent is not reset to null because object will be added //to ObjectToRedraw list, and without parent, it fails @@ -620,7 +628,8 @@ namespace Crow g.Visible = false; GraphicTree.RemoveAt (0); } - } + CrowMonitor.Exit (UpdateMutex); + #if DEBUG_LAYOUTING LQIsTries = new List<LQIList>(); curLQIsTries = new LQIList(); @@ -642,7 +651,8 @@ namespace Crow #endregion public void ProcessResize(Rectangle bounds){ - lock (UpdateMutex) { + CrowMonitor.Enter (UpdateMutex, "process resize"); + clientRectangle = bounds; int stride = 4 * ClientRectangle.Width; int bmpSize = Math.Abs (stride) * ClientRectangle.Height; @@ -653,7 +663,8 @@ namespace Crow g.RegisterForLayouting (LayoutingType.All); clipping.AddRectangle (clientRectangle); - } + CrowMonitor.Exit (UpdateMutex); + } #region Mouse and Keyboard Handling @@ -733,17 +744,16 @@ namespace Crow } //top level graphic obj's parsing - lock (GraphicTree) { - for (int i = 0; i < GraphicTree.Count; i++) { - GraphicObject g = GraphicTree [i]; - if (g.MouseIsIn (e.Position)) { - g.checkHoverWidget (e); - if (g is Window) - PutOnTop (g); - return true; - } + for (int i = 0; i < GraphicTree.Count; i++) { + GraphicObject g = GraphicTree [i]; + if (g.MouseIsIn (e.Position)) { + g.checkHoverWidget (e); + if (g is Window) + PutOnTop (g); + return true; } } + HoverWidget = null; return false; } |