aboutsummaryrefslogtreecommitdiffstatsci
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CrowMonitor.cs61
-rw-r--r--src/CrowThread.cs2
-rw-r--r--src/GraphicObjects/GraphicObject.cs89
-rw-r--r--src/GraphicObjects/Image.cs6
-rw-r--r--src/GraphicObjects/MessageBox.cs26
-rw-r--r--src/GraphicObjects/TemplatedGroup.cs24
-rw-r--r--src/Interface.cs98
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;
}