aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-05-01 19:01:43 +0100
committerJustin Clark-Casey (justincc)2013-05-01 19:01:43 +0100
commit206fb306a7820cf593570e35ddfa8e7c5a10e449 (patch)
tree0ef0fdf42ddc0b63224af52b62b0bad42f62e352
parentFix CAPS to work like they should - do not send caps to the viewer if they're... (diff)
downloadopensim-SC_OLD-206fb306a7820cf593570e35ddfa8e7c5a10e449.zip
opensim-SC_OLD-206fb306a7820cf593570e35ddfa8e7c5a10e449.tar.gz
opensim-SC_OLD-206fb306a7820cf593570e35ddfa8e7c5a10e449.tar.bz2
opensim-SC_OLD-206fb306a7820cf593570e35ddfa8e7c5a10e449.tar.xz
Update SmartThreadPool to latest version 2.2.3 with a major and minor change.
SmartThreadPool code comes from http://www.codeproject.com/Articles/7933/Smart-Thread-Pool This version implements thread abort (via WorkItem.Cancel(true)), threadpool naming, max thread stack, etc. so we no longer need to manually patch those. However, two changes have been made to stock 2.2.3. Major change: WorkItem.Cancel(bool abortExecution) in our version does not succeed if the work item was in progress and thread abort was not specified. This is to match previous behaviour where we handle co-operative termination via another mechanism rather than checking WorkItem.IsCanceled. Minor change: Did not add STP's StopWatch implementation as this is only used WinCE and Silverlight and causes a build clash with System.Diagnostics.StopWatch The reason for updating is to see if this improves http://opensimulator.org/mantis/view.php?id=6557 and http://opensimulator.org/mantis/view.php?id=6586
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Util.cs20
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs9
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs6
-rw-r--r--ThirdParty/SmartThreadPool/AssemblyInfo.cs61
-rw-r--r--ThirdParty/SmartThreadPool/CallerThreadContext.cs361
-rw-r--r--ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs14
-rw-r--r--ThirdParty/SmartThreadPool/EventWaitHandle.cs104
-rw-r--r--ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs82
-rw-r--r--ThirdParty/SmartThreadPool/Exceptions.cs192
-rw-r--r--ThirdParty/SmartThreadPool/Interfaces.cs899
-rw-r--r--ThirdParty/SmartThreadPool/InternalInterfaces.cs27
-rw-r--r--ThirdParty/SmartThreadPool/PriorityQueue.cs479
-rw-r--r--ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs23
-rw-r--r--ThirdParty/SmartThreadPool/SLExt.cs16
-rw-r--r--ThirdParty/SmartThreadPool/STPEventWaitHandle.cs62
-rw-r--r--ThirdParty/SmartThreadPool/STPPerformanceCounter.cs802
-rw-r--r--ThirdParty/SmartThreadPool/STPStartInfo.cs325
-rw-r--r--ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs60
-rw-r--r--ThirdParty/SmartThreadPool/SmartThreadPool.cs3180
-rw-r--r--ThirdParty/SmartThreadPool/SynchronizedDictionary.cs89
-rw-r--r--ThirdParty/SmartThreadPool/WIGStartInfo.cs270
-rw-r--r--ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs190
-rw-r--r--ThirdParty/SmartThreadPool/WorkItem.cs649
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemFactory.cs676
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemInfo.cs171
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs128
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsGroup.cs873
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs471
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsQueue.cs1245
31 files changed, 6688 insertions, 4802 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index bde4673..a3602e9 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1840,7 +1840,7 @@ namespace OpenSim.Framework
1840 case FireAndForgetMethod.SmartThreadPool: 1840 case FireAndForgetMethod.SmartThreadPool:
1841 if (m_ThreadPool == null) 1841 if (m_ThreadPool == null)
1842 InitThreadPool(15); 1842 InitThreadPool(15);
1843 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1843 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
1844 break; 1844 break;
1845 case FireAndForgetMethod.Thread: 1845 case FireAndForgetMethod.Thread:
1846 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 1846 Thread thread = new Thread(delegate(object o) { realCallback(o); });
@@ -1910,15 +1910,15 @@ namespace OpenSim.Framework
1910 return sb.ToString(); 1910 return sb.ToString();
1911 } 1911 }
1912 1912
1913 private static object SmartThreadPoolCallback(object o) 1913// private static object SmartThreadPoolCallback(object o)
1914 { 1914// {
1915 object[] array = (object[])o; 1915// object[] array = (object[])o;
1916 WaitCallback callback = (WaitCallback)array[0]; 1916// WaitCallback callback = (WaitCallback)array[0];
1917 object obj = array[1]; 1917// object obj = array[1];
1918 1918//
1919 callback(obj); 1919// callback(obj);
1920 return null; 1920// return null;
1921 } 1921// }
1922 1922
1923 #endregion FireAndForget Threading Pattern 1923 #endregion FireAndForget Threading Pattern
1924 1924
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 35ae44c..b9a217b 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
51 public interface IScriptWorkItem 51 public interface IScriptWorkItem
52 { 52 {
53 bool Cancel(); 53 bool Cancel();
54 void Abort(); 54 bool Abort();
55 55
56 /// <summary> 56 /// <summary>
57 /// Wait for the work item to complete. 57 /// Wait for the work item to complete.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 1e6db43..f9d3afc 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -564,9 +564,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
564 564
565 public bool Stop(int timeout) 565 public bool Stop(int timeout)
566 { 566 {
567// m_log.DebugFormat( 567 if (DebugLevel >= 1)
568// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", 568 m_log.DebugFormat(
569// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); 569 "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
570 ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
570 571
571 IScriptWorkItem workItem; 572 IScriptWorkItem workItem;
572 573
@@ -627,6 +628,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
627 } 628 }
628 } 629 }
629 630
631 Console.WriteLine("Here9");
632
630 lock (EventQueue) 633 lock (EventQueue)
631 { 634 {
632 workItem = m_CurrentWorkItem; 635 workItem = m_CurrentWorkItem;
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 0d9babb..5804aa8 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -483,7 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
483 /// <param name="instance"></param> 483 /// <param name="instance"></param>
484 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> 484 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
485 private void HandleScriptsAction<TKey>( 485 private void HandleScriptsAction<TKey>(
486 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) 486 string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
487 { 487 {
488 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 488 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
489 return; 489 return;
@@ -1517,7 +1517,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1517 startInfo.MaxWorkerThreads = maxThreads; 1517 startInfo.MaxWorkerThreads = maxThreads;
1518 startInfo.MinWorkerThreads = minThreads; 1518 startInfo.MinWorkerThreads = minThreads;
1519 startInfo.ThreadPriority = threadPriority;; 1519 startInfo.ThreadPriority = threadPriority;;
1520 startInfo.StackSize = stackSize; 1520 startInfo.MaxStackSize = stackSize;
1521 startInfo.StartSuspended = true; 1521 startInfo.StartSuspended = true;
1522 1522
1523 m_ThreadPool = new SmartThreadPool(startInfo); 1523 m_ThreadPool = new SmartThreadPool(startInfo);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
index 8dd7677..9d9dee1 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
52 return wr.Cancel(); 52 return wr.Cancel();
53 } 53 }
54 54
55 public void Abort() 55 public bool Abort()
56 { 56 {
57 wr.Abort(); 57 return wr.Cancel(true);
58 } 58 }
59 59
60 public bool Wait(int t) 60 public bool Wait(int t)
61 { 61 {
62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the 62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an 63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
64 // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 64 // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8
65 // (or very likely other versions of Mono at least up until 3.0.3). 65 // (or very likely other versions of Mono at least up until 3.0.3).
66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); 66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
67 } 67 }
diff --git a/ThirdParty/SmartThreadPool/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/AssemblyInfo.cs
deleted file mode 100644
index e2465b0..0000000
--- a/ThirdParty/SmartThreadPool/AssemblyInfo.cs
+++ /dev/null
@@ -1,61 +0,0 @@
1using System;
2using System.Reflection;
3using System.Runtime.InteropServices;
4
5//
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9//
10[assembly: AssemblyTitle("")]
11[assembly: AssemblyDescription("")]
12[assembly: AssemblyConfiguration("")]
13[assembly: AssemblyCompany("")]
14[assembly: AssemblyProduct("")]
15[assembly: AssemblyCopyright("")]
16[assembly: AssemblyTrademark("")]
17[assembly: AssemblyCulture("")]
18[assembly: ComVisible(false)]
19[assembly: CLSCompliant(true)]
20
21//
22// Version information for an assembly consists of the following four values:
23//
24// Major Version
25// Minor Version
26// Build Number
27// Revision
28//
29// You can specify all the values or you can default the Revision and Build Numbers
30// by using the '*' as shown below:
31
32[assembly: AssemblyVersion("0.7.6.*")]
33
34//
35// In order to sign your assembly you must specify a key to use. Refer to the
36// Microsoft .NET Framework documentation for more information on assembly signing.
37//
38// Use the attributes below to control which key is used for signing.
39//
40// Notes:
41// (*) If no key is specified, the assembly is not signed.
42// (*) KeyName refers to a key that has been installed in the Crypto Service
43// Provider (CSP) on your machine. KeyFile refers to a file which contains
44// a key.
45// (*) If the KeyFile and the KeyName values are both specified, the
46// following processing occurs:
47// (1) If the KeyName can be found in the CSP, that key is used.
48// (2) If the KeyName does not exist and the KeyFile does exist, the key
49// in the KeyFile is installed into the CSP and used.
50// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
51// When specifying the KeyFile, the location of the KeyFile should be
52// relative to the project output directory which is
53// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
54// located in the project directory, you would specify the AssemblyKeyFile
55// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
56// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
57// documentation for more information on this.
58//
59[assembly: AssemblyDelaySign(false)]
60[assembly: AssemblyKeyFile("")]
61[assembly: AssemblyKeyName("")]
diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs
index 6ea53f6..2177241 100644
--- a/ThirdParty/SmartThreadPool/CallerThreadContext.cs
+++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs
@@ -1,223 +1,138 @@
1using System; 1
2using System.Diagnostics; 2#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
3using System.Threading; 3
4using System.Reflection; 4using System;
5using System.Web; 5using System.Diagnostics;
6using System.Runtime.Remoting.Messaging; 6using System.Threading;
7 7using System.Reflection;
8 8using System.Web;
9namespace Amib.Threading 9using System.Runtime.Remoting.Messaging;
10{ 10
11 #region CallerThreadContext class 11
12 12namespace Amib.Threading.Internal
13 /// <summary> 13{
14 /// This class stores the caller call context in order to restore 14#region CallerThreadContext class
15 /// it when the work item is executed in the thread pool environment. 15
16 /// </summary> 16 /// <summary>
17 internal class CallerThreadContext 17 /// This class stores the caller call context in order to restore
18 { 18 /// it when the work item is executed in the thread pool environment.
19 #region Prepare reflection information 19 /// </summary>
20 20 internal class CallerThreadContext
21 // Cached type information. 21 {
22 private static MethodInfo getLogicalCallContextMethodInfo = 22#region Prepare reflection information
23 typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); 23
24 24 // Cached type information.
25 private static MethodInfo setLogicalCallContextMethodInfo = 25 private static readonly MethodInfo getLogicalCallContextMethodInfo =
26 typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); 26 typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
27 27
28 private static string HttpContextSlotName = GetHttpContextSlotName(); 28 private static readonly MethodInfo setLogicalCallContextMethodInfo =
29 29 typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
30 private static string GetHttpContextSlotName() 30
31 { 31 private static string HttpContextSlotName = GetHttpContextSlotName();
32 FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); 32
33 33 private static string GetHttpContextSlotName()
34 if( fi != null ) 34 {
35 return (string)fi.GetValue(null); 35 FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
36 else // Use the default "HttpContext" slot name 36
37 return "HttpContext"; 37 if (fi != null)
38 } 38 {
39 39 return (string) fi.GetValue(null);
40 #endregion 40 }
41 41
42 #region Private fields 42 return "HttpContext";
43 43 }
44 private HttpContext _httpContext = null; 44
45 private LogicalCallContext _callContext = null; 45 #endregion
46 46
47 #endregion 47#region Private fields
48 48
49 /// <summary> 49 private HttpContext _httpContext;
50 /// Constructor 50 private LogicalCallContext _callContext;
51 /// </summary> 51
52 private CallerThreadContext() 52 #endregion
53 { 53
54 } 54 /// <summary>
55 55 /// Constructor
56 public bool CapturedCallContext 56 /// </summary>
57 { 57 private CallerThreadContext()
58 get 58 {
59 { 59 }
60 return (null != _callContext); 60
61 } 61 public bool CapturedCallContext
62 } 62 {
63 63 get
64 public bool CapturedHttpContext 64 {
65 { 65 return (null != _callContext);
66 get 66 }
67 { 67 }
68 return (null != _httpContext); 68
69 } 69 public bool CapturedHttpContext
70 } 70 {
71 71 get
72 /// <summary> 72 {
73 /// Captures the current thread context 73 return (null != _httpContext);
74 /// </summary> 74 }
75 /// <returns></returns> 75 }
76 public static CallerThreadContext Capture( 76
77 bool captureCallContext, 77 /// <summary>
78 bool captureHttpContext) 78 /// Captures the current thread context
79 { 79 /// </summary>
80 Debug.Assert(captureCallContext || captureHttpContext); 80 /// <returns></returns>
81 81 public static CallerThreadContext Capture(
82 CallerThreadContext callerThreadContext = new CallerThreadContext(); 82 bool captureCallContext,
83 83 bool captureHttpContext)
84 // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() 84 {
85 // Capture Call Context 85 Debug.Assert(captureCallContext || captureHttpContext);
86 if(captureCallContext && (getLogicalCallContextMethodInfo != null)) 86
87 { 87 CallerThreadContext callerThreadContext = new CallerThreadContext();
88 callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); 88
89 if (callerThreadContext._callContext != null) 89 // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
90 { 90 // Capture Call Context
91 callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); 91 if(captureCallContext && (getLogicalCallContextMethodInfo != null))
92 } 92 {
93 } 93 callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
94 94 if (callerThreadContext._callContext != null)
95 // Capture httpContext 95 {
96 if (captureHttpContext && (null != HttpContext.Current)) 96 callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
97 { 97 }
98 callerThreadContext._httpContext = HttpContext.Current; 98 }
99 } 99
100 100 // Capture httpContext
101 return callerThreadContext; 101 if (captureHttpContext && (null != HttpContext.Current))
102 } 102 {
103 103 callerThreadContext._httpContext = HttpContext.Current;
104 /// <summary> 104 }
105 /// Applies the thread context stored earlier 105
106 /// </summary> 106 return callerThreadContext;
107 /// <param name="callerThreadContext"></param> 107 }
108 public static void Apply(CallerThreadContext callerThreadContext) 108
109 { 109 /// <summary>
110 if (null == callerThreadContext) 110 /// Applies the thread context stored earlier
111 { 111 /// </summary>
112 throw new ArgumentNullException("callerThreadContext"); 112 /// <param name="callerThreadContext"></param>
113 } 113 public static void Apply(CallerThreadContext callerThreadContext)
114 114 {
115 // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() 115 if (null == callerThreadContext)
116 // Restore call context 116 {
117 if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) 117 throw new ArgumentNullException("callerThreadContext");
118 { 118 }
119 setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); 119
120 } 120 // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
121 121 // Restore call context
122 // Restore HttpContext 122 if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
123 if (callerThreadContext._httpContext != null) 123 {
124 { 124 setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
125 CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); 125 }
126 } 126
127 } 127 // Restore HttpContext
128 } 128 if (callerThreadContext._httpContext != null)
129 129 {
130 #endregion 130 HttpContext.Current = callerThreadContext._httpContext;
131 131 //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
132} 132 }
133 133 }
134 134 }
135/* 135
136// Ami Bar 136 #endregion
137// amibar@gmail.com 137}
138 138#endif
139using System;
140using System.Threading;
141using System.Globalization;
142using System.Security.Principal;
143using System.Reflection;
144using System.Runtime.Remoting.Contexts;
145
146namespace Amib.Threading.Internal
147{
148 #region CallerThreadContext class
149
150 /// <summary>
151 /// This class stores the caller thread context in order to restore
152 /// it when the work item is executed in the context of the thread
153 /// from the pool.
154 /// Note that we can't store the thread's CompressedStack, because
155 /// it throws a security exception
156 /// </summary>
157 public class CallerThreadContext
158 {
159 private CultureInfo _culture = null;
160 private CultureInfo _cultureUI = null;
161 private IPrincipal _principal;
162 private System.Runtime.Remoting.Contexts.Context _context;
163
164 private static FieldInfo _fieldInfo = GetFieldInfo();
165
166 private static FieldInfo GetFieldInfo()
167 {
168 Type threadType = typeof(Thread);
169 return threadType.GetField(
170 "m_Context",
171 BindingFlags.Instance | BindingFlags.NonPublic);
172 }
173
174 /// <summary>
175 /// Constructor
176 /// </summary>
177 private CallerThreadContext()
178 {
179 }
180
181 /// <summary>
182 /// Captures the current thread context
183 /// </summary>
184 /// <returns></returns>
185 public static CallerThreadContext Capture()
186 {
187 CallerThreadContext callerThreadContext = new CallerThreadContext();
188
189 Thread thread = Thread.CurrentThread;
190 callerThreadContext._culture = thread.CurrentCulture;
191 callerThreadContext._cultureUI = thread.CurrentUICulture;
192 callerThreadContext._principal = Thread.CurrentPrincipal;
193 callerThreadContext._context = Thread.CurrentContext;
194 return callerThreadContext;
195 }
196
197 /// <summary>
198 /// Applies the thread context stored earlier
199 /// </summary>
200 /// <param name="callerThreadContext"></param>
201 public static void Apply(CallerThreadContext callerThreadContext)
202 {
203 Thread thread = Thread.CurrentThread;
204 thread.CurrentCulture = callerThreadContext._culture;
205 thread.CurrentUICulture = callerThreadContext._cultureUI;
206 Thread.CurrentPrincipal = callerThreadContext._principal;
207
208 // Uncomment the following block to enable the Thread.CurrentThread
209/*
210 if (null != _fieldInfo)
211 {
212 _fieldInfo.SetValue(
213 Thread.CurrentThread,
214 callerThreadContext._context);
215 }
216* /
217 }
218 }
219
220 #endregion
221}
222*/
223
diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
new file mode 100644
index 0000000..4a2a3e7
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
@@ -0,0 +1,14 @@
1namespace Amib.Threading.Internal
2{
3 internal class CanceledWorkItemsGroup
4 {
5 public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
6
7 public CanceledWorkItemsGroup()
8 {
9 IsCanceled = false;
10 }
11
12 public bool IsCanceled { get; set; }
13 }
14} \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs
new file mode 100644
index 0000000..70a1a29
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs
@@ -0,0 +1,104 @@
1#if (_WINDOWS_CE)
2
3using System;
4using System.Runtime.InteropServices;
5using System.Threading;
6
7namespace Amib.Threading.Internal
8{
9 /// <summary>
10 /// EventWaitHandle class
11 /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation.
12 /// So I wrote this class to implement these two methods with some of their overloads.
13 /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny.
14 /// Note that this class doesn't even inherit from WaitHandle!
15 /// </summary>
16 public class STPEventWaitHandle
17 {
18 #region Public Constants
19
20 public const int WaitTimeout = Timeout.Infinite;
21
22 #endregion
23
24 #region Private External Constants
25
26 private const Int32 WAIT_FAILED = -1;
27 private const Int32 WAIT_TIMEOUT = 0x102;
28 private const UInt32 INFINITE = 0xFFFFFFFF;
29
30 #endregion
31
32 #region WaitAll and WaitAny
33
34 internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
35 {
36 return waitHandle.WaitOne(millisecondsTimeout, exitContext);
37 }
38
39 private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles)
40 {
41 IntPtr[] nativeHandles = new IntPtr[waitHandles.Length];
42 for (int i = 0; i < waitHandles.Length; i++)
43 {
44 nativeHandles[i] = waitHandles[i].Handle;
45 }
46 return nativeHandles;
47 }
48
49 public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
50 {
51 uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
52
53 IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
54
55 int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout);
56
57 if (result == WAIT_TIMEOUT || result == WAIT_FAILED)
58 {
59 return false;
60 }
61
62 return true;
63 }
64
65
66 public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
67 {
68 uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
69
70 IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
71
72 int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout);
73
74 if (result >= 0 && result < waitHandles.Length)
75 {
76 return result;
77 }
78
79 return -1;
80 }
81
82 public static int WaitAny(WaitHandle[] waitHandles)
83 {
84 return WaitAny(waitHandles, Timeout.Infinite, false);
85 }
86
87 public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
88 {
89 int millisecondsTimeout = (int)timeout.TotalMilliseconds;
90
91 return WaitAny(waitHandles, millisecondsTimeout, false);
92 }
93
94 #endregion
95
96 #region External methods
97
98 [DllImport("coredll.dll", SetLastError = true)]
99 public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds);
100
101 #endregion
102 }
103}
104#endif \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
new file mode 100644
index 0000000..2f8c55b
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
@@ -0,0 +1,82 @@
1using System.Threading;
2
3#if (_WINDOWS_CE)
4using System;
5using System.Runtime.InteropServices;
6#endif
7
8namespace Amib.Threading.Internal
9{
10 /// <summary>
11 /// EventWaitHandleFactory class.
12 /// This is a static class that creates AutoResetEvent and ManualResetEvent objects.
13 /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property
14 /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API.
15 /// Consequently this class creates the needed XxxResetEvent and replaces the handle if
16 /// it's a WindowsCE OS.
17 /// </summary>
18 public static class EventWaitHandleFactory
19 {
20 /// <summary>
21 /// Create a new AutoResetEvent object
22 /// </summary>
23 /// <returns>Return a new AutoResetEvent object</returns>
24 public static AutoResetEvent CreateAutoResetEvent()
25 {
26 AutoResetEvent waitHandle = new AutoResetEvent(false);
27
28#if (_WINDOWS_CE)
29 ReplaceEventHandle(waitHandle, false, false);
30#endif
31
32 return waitHandle;
33 }
34
35 /// <summary>
36 /// Create a new ManualResetEvent object
37 /// </summary>
38 /// <returns>Return a new ManualResetEvent object</returns>
39 public static ManualResetEvent CreateManualResetEvent(bool initialState)
40 {
41 ManualResetEvent waitHandle = new ManualResetEvent(initialState);
42
43#if (_WINDOWS_CE)
44 ReplaceEventHandle(waitHandle, true, initialState);
45#endif
46
47 return waitHandle;
48 }
49
50#if (_WINDOWS_CE)
51
52 /// <summary>
53 /// Replace the event handle
54 /// </summary>
55 /// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param>
56 /// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param>
57 /// <param name="initialState">The initial state of the event</param>
58 private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState)
59 {
60 // Store the old handle
61 IntPtr oldHandle = waitHandle.Handle;
62
63 // Create a new event
64 IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null);
65
66 // Replace the old event with the new event
67 waitHandle.Handle = newHandle;
68
69 // Close the old event
70 CloseHandle (oldHandle);
71 }
72
73 [DllImport("coredll.dll", SetLastError = true)]
74 public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
75
76 //Handle
77 [DllImport("coredll.dll", SetLastError = true)]
78 public static extern bool CloseHandle(IntPtr hObject);
79#endif
80
81 }
82}
diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs
index c454709..8e66ce9 100644
--- a/ThirdParty/SmartThreadPool/Exceptions.cs
+++ b/ThirdParty/SmartThreadPool/Exceptions.cs
@@ -1,81 +1,111 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2#if !(_WINDOWS_CE)
3 3using System.Runtime.Serialization;
4using System; 4#endif
5using System.Runtime.Serialization; 5
6 6namespace Amib.Threading
7namespace Amib.Threading 7{
8{ 8 #region Exceptions
9 #region Exceptions 9
10 10 /// <summary>
11 /// <summary> 11 /// Represents an exception in case IWorkItemResult.GetResult has been canceled
12 /// Represents an exception in case IWorkItemResult.GetResult has been canceled 12 /// </summary>
13 /// </summary> 13 public sealed partial class WorkItemCancelException : Exception
14 [Serializable] 14 {
15 public sealed class WorkItemCancelException : ApplicationException 15 public WorkItemCancelException()
16 { 16 {
17 public WorkItemCancelException() : base() 17 }
18 { 18
19 } 19 public WorkItemCancelException(string message)
20 20 : base(message)
21 public WorkItemCancelException(string message) : base(message) 21 {
22 { 22 }
23 } 23
24 24 public WorkItemCancelException(string message, Exception e)
25 public WorkItemCancelException(string message, Exception e) : base(message, e) 25 : base(message, e)
26 { 26 {
27 } 27 }
28 28 }
29 public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc) 29
30 { 30 /// <summary>
31 } 31 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
32 } 32 /// </summary>
33 33 public sealed partial class WorkItemTimeoutException : Exception
34 /// <summary> 34 {
35 /// Represents an exception in case IWorkItemResult.GetResult has been timed out 35 public WorkItemTimeoutException()
36 /// </summary> 36 {
37 [Serializable] 37 }
38 public sealed class WorkItemTimeoutException : ApplicationException 38
39 { 39 public WorkItemTimeoutException(string message)
40 public WorkItemTimeoutException() : base() 40 : base(message)
41 { 41 {
42 } 42 }
43 43
44 public WorkItemTimeoutException(string message) : base(message) 44 public WorkItemTimeoutException(string message, Exception e)
45 { 45 : base(message, e)
46 } 46 {
47 47 }
48 public WorkItemTimeoutException(string message, Exception e) : base(message, e) 48 }
49 { 49
50 } 50 /// <summary>
51 51 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
52 public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc) 52 /// </summary>
53 { 53 public sealed partial class WorkItemResultException : Exception
54 } 54 {
55 } 55 public WorkItemResultException()
56 56 {
57 /// <summary> 57 }
58 /// Represents an exception in case IWorkItemResult.GetResult has been timed out 58
59 /// </summary> 59 public WorkItemResultException(string message)
60 [Serializable] 60 : base(message)
61 public sealed class WorkItemResultException : ApplicationException 61 {
62 { 62 }
63 public WorkItemResultException() : base() 63
64 { 64 public WorkItemResultException(string message, Exception e)
65 } 65 : base(message, e)
66 66 {
67 public WorkItemResultException(string message) : base(message) 67 }
68 { 68 }
69 } 69
70 70
71 public WorkItemResultException(string message, Exception e) : base(message, e) 71#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
72 { 72 /// <summary>
73 } 73 /// Represents an exception in case IWorkItemResult.GetResult has been canceled
74 74 /// </summary>
75 public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc) 75 [Serializable]
76 { 76 public sealed partial class WorkItemCancelException
77 } 77 {
78 } 78 public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
79 79 : base(si, sc)
80 #endregion 80 {
81} 81 }
82 }
83
84 /// <summary>
85 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
86 /// </summary>
87 [Serializable]
88 public sealed partial class WorkItemTimeoutException
89 {
90 public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
91 : base(si, sc)
92 {
93 }
94 }
95
96 /// <summary>
97 /// Represents an exception in case IWorkItemResult.GetResult has been timed out
98 /// </summary>
99 [Serializable]
100 public sealed partial class WorkItemResultException
101 {
102 public WorkItemResultException(SerializationInfo si, StreamingContext sc)
103 : base(si, sc)
104 {
105 }
106 }
107
108#endif
109
110 #endregion
111}
diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs
index f1c1fcf..29c8a3e 100644
--- a/ThirdParty/SmartThreadPool/Interfaces.cs
+++ b/ThirdParty/SmartThreadPool/Interfaces.cs
@@ -1,271 +1,628 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2using System.Threading;
3 3
4using System; 4namespace Amib.Threading
5using System.Threading; 5{
6 6 #region Delegates
7namespace Amib.Threading 7
8{ 8 /// <summary>
9 #region Delegates 9 /// A delegate that represents the method to run as the work item
10 10 /// </summary>
11 /// <summary> 11 /// <param name="state">A state object for the method to run</param>
12 /// A delegate that represents the method to run as the work item 12 public delegate object WorkItemCallback(object state);
13 /// </summary> 13
14 /// <param name="state">A state object for the method to run</param> 14 /// <summary>
15 public delegate object WorkItemCallback(object state); 15 /// A delegate to call after the WorkItemCallback completed
16 16 /// </summary>
17 /// <summary> 17 /// <param name="wir">The work item result object</param>
18 /// A delegate to call after the WorkItemCallback completed 18 public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
19 /// </summary> 19
20 /// <param name="wir">The work item result object</param> 20 /// <summary>
21 public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); 21 /// A delegate to call after the WorkItemCallback completed
22 22 /// </summary>
23 /// <summary> 23 /// <param name="wir">The work item result object</param>
24 /// A delegate to call when a WorkItemsGroup becomes idle 24 public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
25 /// </summary> 25
26 /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param> 26 /// <summary>
27 public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); 27 /// A delegate to call when a WorkItemsGroup becomes idle
28 28 /// </summary>
29 #endregion 29 /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
30 30 public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
31 #region WorkItem Priority 31
32 32 /// <summary>
33 public enum WorkItemPriority 33 /// A delegate to call after a thread is created, but before
34 { 34 /// it's first use.
35 Lowest, 35 /// </summary>
36 BelowNormal, 36 public delegate void ThreadInitializationHandler();
37 Normal, 37
38 AboveNormal, 38 /// <summary>
39 Highest, 39 /// A delegate to call when a thread is about to exit, after
40 } 40 /// it is no longer belong to the pool.
41 41 /// </summary>
42 #endregion 42 public delegate void ThreadTerminationHandler();
43 43
44 #region IHasWorkItemPriority interface 44 #endregion
45 45
46 public interface IHasWorkItemPriority 46 #region WorkItem Priority
47 { 47
48 WorkItemPriority WorkItemPriority { get; } 48 /// <summary>
49 } 49 /// Defines the availeable priorities of a work item.
50 50 /// The higher the priority a work item has, the sooner
51 #endregion 51 /// it will be executed.
52 52 /// </summary>
53 #region IWorkItemsGroup interface 53 public enum WorkItemPriority
54 54 {
55 /// <summary> 55 Lowest,
56 /// IWorkItemsGroup interface 56 BelowNormal,
57 /// </summary> 57 Normal,
58 public interface IWorkItemsGroup 58 AboveNormal,
59 { 59 Highest,
60 /// <summary> 60 }
61 /// Get/Set the name of the WorkItemsGroup 61
62 /// </summary> 62 #endregion
63 string Name { get; set; } 63
64 64 #region IWorkItemsGroup interface
65 IWorkItemResult QueueWorkItem(WorkItemCallback callback); 65
66 IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); 66 /// <summary>
67 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); 67 /// IWorkItemsGroup interface
68 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); 68 /// Created by SmartThreadPool.CreateWorkItemsGroup()
69 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); 69 /// </summary>
70 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); 70 public interface IWorkItemsGroup
71 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); 71 {
72 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); 72 /// <summary>
73 73 /// Get/Set the name of the WorkItemsGroup
74 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); 74 /// </summary>
75 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); 75 string Name { get; set; }
76 76
77 void WaitForIdle(); 77 /// <summary>
78 bool WaitForIdle(TimeSpan timeout); 78 /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
79 bool WaitForIdle(int millisecondsTimeout); 79 /// </summary>
80 80 int Concurrency { get; set; }
81 int WaitingCallbacks { get; } 81
82 event WorkItemsGroupIdleHandler OnIdle; 82 /// <summary>
83 83 /// Get the number of work items waiting in the queue.
84 void Cancel(); 84 /// </summary>
85 void Start(); 85 int WaitingCallbacks { get; }
86 } 86
87 87 /// <summary>
88 #endregion 88 /// Get an array with all the state objects of the currently running items.
89 89 /// The array represents a snap shot and impact performance.
90 #region CallToPostExecute enumerator 90 /// </summary>
91 91 object[] GetStates();
92 [Flags] 92
93 public enum CallToPostExecute 93 /// <summary>
94 { 94 /// Get the WorkItemsGroup start information
95 Never = 0x00, 95 /// </summary>
96 WhenWorkItemCanceled = 0x01, 96 WIGStartInfo WIGStartInfo { get; }
97 WhenWorkItemNotCanceled = 0x02, 97
98 Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, 98 /// <summary>
99 } 99 /// Starts to execute work items
100 100 /// </summary>
101 #endregion 101 void Start();
102 102
103 #region IWorkItemResult interface 103 /// <summary>
104 104 /// Cancel all the work items.
105 /// <summary> 105 /// Same as Cancel(false)
106 /// IWorkItemResult interface 106 /// </summary>
107 /// </summary> 107 void Cancel();
108 public interface IWorkItemResult 108
109 { 109 /// <summary>
110 /// <summary> 110 /// Cancel all work items using thread abortion
111 /// Get the result of the work item. 111 /// </summary>
112 /// If the work item didn't run yet then the caller waits. 112 /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
113 /// </summary> 113 void Cancel(bool abortExecution);
114 /// <returns>The result of the work item</returns> 114
115 object GetResult(); 115 /// <summary>
116 116 /// Wait for all work item to complete.
117 /// <summary> 117 /// </summary>
118 /// Get the result of the work item. 118 void WaitForIdle();
119 /// If the work item didn't run yet then the caller waits until timeout. 119
120 /// </summary> 120 /// <summary>
121 /// <returns>The result of the work item</returns> 121 /// Wait for all work item to complete, until timeout expired
122 /// On timeout throws WorkItemTimeoutException 122 /// </summary>
123 object GetResult( 123 /// <param name="timeout">How long to wait for the work items to complete</param>
124 int millisecondsTimeout, 124 /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
125 bool exitContext); 125 bool WaitForIdle(TimeSpan timeout);
126 126
127 /// <summary> 127 /// <summary>
128 /// Get the result of the work item. 128 /// Wait for all work item to complete, until timeout expired
129 /// If the work item didn't run yet then the caller waits until timeout. 129 /// </summary>
130 /// </summary> 130 /// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
131 /// <returns>The result of the work item</returns> 131 /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
132 /// On timeout throws WorkItemTimeoutException 132 bool WaitForIdle(int millisecondsTimeout);
133 object GetResult( 133
134 TimeSpan timeout, 134 /// <summary>
135 bool exitContext); 135 /// IsIdle is true when there are no work items running or queued.
136 136 /// </summary>
137 void Abort(); 137 bool IsIdle { get; }
138 138
139 /// <summary> 139 /// <summary>
140 /// Get the result of the work item. 140 /// This event is fired when all work items are completed.
141 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. 141 /// (When IsIdle changes to true)
142 /// </summary> 142 /// This event only work on WorkItemsGroup. On SmartThreadPool
143 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> 143 /// it throws the NotImplementedException.
144 /// <param name="exitContext"> 144 /// </summary>
145 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 145 event WorkItemsGroupIdleHandler OnIdle;
146 /// </param> 146
147 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param> 147 #region QueueWorkItem
148 /// <returns>The result of the work item</returns> 148
149 /// On timeout throws WorkItemTimeoutException 149 /// <summary>
150 /// On cancel throws WorkItemCancelException 150 /// Queue a work item
151 object GetResult( 151 /// </summary>
152 int millisecondsTimeout, 152 /// <param name="callback">A callback to execute</param>
153 bool exitContext, 153 /// <returns>Returns a work item result</returns>
154 WaitHandle cancelWaitHandle); 154 IWorkItemResult QueueWorkItem(WorkItemCallback callback);
155 155
156 /// <summary> 156 /// <summary>
157 /// Get the result of the work item. 157 /// Queue a work item
158 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. 158 /// </summary>
159 /// </summary> 159 /// <param name="callback">A callback to execute</param>
160 /// <returns>The result of the work item</returns> 160 /// <param name="workItemPriority">The priority of the work item</param>
161 /// On timeout throws WorkItemTimeoutException 161 /// <returns>Returns a work item result</returns>
162 /// On cancel throws WorkItemCancelException 162 IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
163 object GetResult( 163
164 TimeSpan timeout, 164 /// <summary>
165 bool exitContext, 165 /// Queue a work item
166 WaitHandle cancelWaitHandle); 166 /// </summary>
167 167 /// <param name="callback">A callback to execute</param>
168 /// <summary> 168 /// <param name="state">
169 /// Get the result of the work item. 169 /// The context object of the work item. Used for passing arguments to the work item.
170 /// If the work item didn't run yet then the caller waits. 170 /// </param>
171 /// </summary> 171 /// <returns>Returns a work item result</returns>
172 /// <param name="e">Filled with the exception if one was thrown</param> 172 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
173 /// <returns>The result of the work item</returns> 173
174 object GetResult(out Exception e); 174 /// <summary>
175 175 /// Queue a work item
176 /// <summary> 176 /// </summary>
177 /// Get the result of the work item. 177 /// <param name="callback">A callback to execute</param>
178 /// If the work item didn't run yet then the caller waits until timeout. 178 /// <param name="state">
179 /// </summary> 179 /// The context object of the work item. Used for passing arguments to the work item.
180 /// <param name="e">Filled with the exception if one was thrown</param> 180 /// </param>
181 /// <returns>The result of the work item</returns> 181 /// <param name="workItemPriority">The work item priority</param>
182 /// On timeout throws WorkItemTimeoutException 182 /// <returns>Returns a work item result</returns>
183 object GetResult( 183 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
184 int millisecondsTimeout, 184
185 bool exitContext, 185 /// <summary>
186 out Exception e); 186 /// Queue a work item
187 187 /// </summary>
188 /// <summary> 188 /// <param name="callback">A callback to execute</param>
189 /// Get the result of the work item. 189 /// <param name="state">
190 /// If the work item didn't run yet then the caller waits until timeout. 190 /// The context object of the work item. Used for passing arguments to the work item.
191 /// </summary> 191 /// </param>
192 /// <param name="e">Filled with the exception if one was thrown</param> 192 /// <param name="postExecuteWorkItemCallback">
193 /// <returns>The result of the work item</returns> 193 /// A delegate to call after the callback completion
194 /// On timeout throws WorkItemTimeoutException 194 /// </param>
195 object GetResult( 195 /// <returns>Returns a work item result</returns>
196 TimeSpan timeout, 196 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
197 bool exitContext, 197
198 out Exception e); 198 /// <summary>
199 199 /// Queue a work item
200 /// <summary> 200 /// </summary>
201 /// Get the result of the work item. 201 /// <param name="callback">A callback to execute</param>
202 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. 202 /// <param name="state">
203 /// </summary> 203 /// The context object of the work item. Used for passing arguments to the work item.
204 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> 204 /// </param>
205 /// <param name="exitContext"> 205 /// <param name="postExecuteWorkItemCallback">
206 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 206 /// A delegate to call after the callback completion
207 /// </param> 207 /// </param>
208 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param> 208 /// <param name="workItemPriority">The work item priority</param>
209 /// <param name="e">Filled with the exception if one was thrown</param> 209 /// <returns>Returns a work item result</returns>
210 /// <returns>The result of the work item</returns> 210 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
211 /// On timeout throws WorkItemTimeoutException 211
212 /// On cancel throws WorkItemCancelException 212 /// <summary>
213 object GetResult( 213 /// Queue a work item
214 int millisecondsTimeout, 214 /// </summary>
215 bool exitContext, 215 /// <param name="callback">A callback to execute</param>
216 WaitHandle cancelWaitHandle, 216 /// <param name="state">
217 out Exception e); 217 /// The context object of the work item. Used for passing arguments to the work item.
218 218 /// </param>
219 /// <summary> 219 /// <param name="postExecuteWorkItemCallback">
220 /// Get the result of the work item. 220 /// A delegate to call after the callback completion
221 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. 221 /// </param>
222 /// </summary> 222 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
223 /// <returns>The result of the work item</returns> 223 /// <returns>Returns a work item result</returns>
224 /// <param name="e">Filled with the exception if one was thrown</param> 224 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
225 /// On timeout throws WorkItemTimeoutException 225
226 /// On cancel throws WorkItemCancelException 226 /// <summary>
227 object GetResult( 227 /// Queue a work item
228 TimeSpan timeout, 228 /// </summary>
229 bool exitContext, 229 /// <param name="callback">A callback to execute</param>
230 WaitHandle cancelWaitHandle, 230 /// <param name="state">
231 out Exception e); 231 /// The context object of the work item. Used for passing arguments to the work item.
232 232 /// </param>
233 /// <summary> 233 /// <param name="postExecuteWorkItemCallback">
234 /// Gets an indication whether the asynchronous operation has completed. 234 /// A delegate to call after the callback completion
235 /// </summary> 235 /// </param>
236 bool IsCompleted { get; } 236 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
237 237 /// <param name="workItemPriority">The work item priority</param>
238 /// <summary> 238 /// <returns>Returns a work item result</returns>
239 /// Gets an indication whether the asynchronous operation has been canceled. 239 IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
240 /// </summary> 240
241 bool IsCanceled { get; } 241 /// <summary>
242 242 /// Queue a work item
243 /// <summary> 243 /// </summary>
244 /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. 244 /// <param name="workItemInfo">Work item info</param>
245 /// </summary> 245 /// <param name="callback">A callback to execute</param>
246 object State { get; } 246 /// <returns>Returns a work item result</returns>
247 247 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
248 /// <summary> 248
249 /// Cancel the work item if it didn't start running yet. 249 /// <summary>
250 /// </summary> 250 /// Queue a work item
251 /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> 251 /// </summary>
252 bool Cancel(); 252 /// <param name="workItemInfo">Work item information</param>
253 253 /// <param name="callback">A callback to execute</param>
254 /// <summary> 254 /// <param name="state">
255 /// Get the work item's priority 255 /// The context object of the work item. Used for passing arguments to the work item.
256 /// </summary> 256 /// </param>
257 WorkItemPriority WorkItemPriority { get; } 257 /// <returns>Returns a work item result</returns>
258 258 IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
259 /// <summary> 259
260 /// Return the result, same as GetResult() 260 #endregion
261 /// </summary> 261
262 object Result { get; } 262 #region QueueWorkItem(Action<...>)
263 263
264 /// <summary> 264 /// <summary>
265 /// Returns the exception if occured otherwise returns null. 265 /// Queue a work item.
266 /// </summary> 266 /// </summary>
267 object Exception { get; } 267 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
268 } 268 IWorkItemResult QueueWorkItem(Action action);
269 269
270 #endregion 270 /// <summary>
271} 271 /// Queue a work item.
272 /// </summary>
273 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
274 IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority);
275
276 /// <summary>
277 /// Queue a work item.
278 /// </summary>
279 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
280 IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority);
281
282 /// <summary>
283 /// Queue a work item.
284 /// </summary>
285 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
286 IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg);
287
288 /// <summary>
289 /// Queue a work item.
290 /// </summary>
291 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
292 IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2);
293
294 /// <summary>
295 /// Queue a work item.
296 /// </summary>
297 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
298 IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority);
299
300 /// <summary>
301 /// Queue a work item.
302 /// </summary>
303 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
304 IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3);
305
306 /// <summary>
307 /// Queue a work item.
308 /// </summary>
309 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
310 IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority);
311
312 /// <summary>
313 /// Queue a work item.
314 /// </summary>
315 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
316 IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
317
318 /// <summary>
319 /// Queue a work item.
320 /// </summary>
321 /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
322 IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority);
323
324 #endregion
325
326 #region QueueWorkItem(Func<...>)
327
328 /// <summary>
329 /// Queue a work item.
330 /// </summary>
331 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
332 /// its GetResult() returns a TResult object</returns>
333 IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func);
334
335 /// <summary>
336 /// Queue a work item.
337 /// </summary>
338 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
339 /// its GetResult() returns a TResult object</returns>
340 IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg);
341
342 /// <summary>
343 /// Queue a work item.
344 /// </summary>
345 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
346 /// its GetResult() returns a TResult object</returns>
347 IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2);
348
349 /// <summary>
350 /// Queue a work item.
351 /// </summary>
352 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
353 /// its GetResult() returns a TResult object</returns>
354 IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3);
355
356 /// <summary>
357 /// Queue a work item.
358 /// </summary>
359 /// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
360 /// its GetResult() returns a TResult object</returns>
361 IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
362
363 #endregion
364 }
365
366 #endregion
367
368 #region CallToPostExecute enumerator
369
370 [Flags]
371 public enum CallToPostExecute
372 {
373 /// <summary>
374 /// Never call to the PostExecute call back
375 /// </summary>
376 Never = 0x00,
377
378 /// <summary>
379 /// Call to the PostExecute only when the work item is cancelled
380 /// </summary>
381 WhenWorkItemCanceled = 0x01,
382
383 /// <summary>
384 /// Call to the PostExecute only when the work item is not cancelled
385 /// </summary>
386 WhenWorkItemNotCanceled = 0x02,
387
388 /// <summary>
389 /// Always call to the PostExecute
390 /// </summary>
391 Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
392 }
393
394 #endregion
395
396 #region IWorkItemResult interface
397
398 /// <summary>
399 /// The common interface of IWorkItemResult and IWorkItemResult&lt;T&gt;
400 /// </summary>
401 public interface IWaitableResult
402 {
403 /// <summary>
404 /// This method intent is for internal use.
405 /// </summary>
406 /// <returns></returns>
407 IWorkItemResult GetWorkItemResult();
408
409 /// <summary>
410 /// This method intent is for internal use.
411 /// </summary>
412 /// <returns></returns>
413 IWorkItemResult<TResult> GetWorkItemResultT<TResult>();
414 }
415
416 /// <summary>
417 /// IWorkItemResult interface.
418 /// Created when a WorkItemCallback work item is queued.
419 /// </summary>
420 public interface IWorkItemResult : IWorkItemResult<object>
421 {
422 }
423
424 /// <summary>
425 /// IWorkItemResult&lt;TResult&gt; interface.
426 /// Created when a Func&lt;TResult&gt; work item is queued.
427 /// </summary>
428 public interface IWorkItemResult<TResult> : IWaitableResult
429 {
430 /// <summary>
431 /// Get the result of the work item.
432 /// If the work item didn't run yet then the caller waits.
433 /// </summary>
434 /// <returns>The result of the work item</returns>
435 TResult GetResult();
436
437 /// <summary>
438 /// Get the result of the work item.
439 /// If the work item didn't run yet then the caller waits until timeout.
440 /// </summary>
441 /// <returns>The result of the work item</returns>
442 /// On timeout throws WorkItemTimeoutException
443 TResult GetResult(
444 int millisecondsTimeout,
445 bool exitContext);
446
447 /// <summary>
448 /// Get the result of the work item.
449 /// If the work item didn't run yet then the caller waits until timeout.
450 /// </summary>
451 /// <returns>The result of the work item</returns>
452 /// On timeout throws WorkItemTimeoutException
453 TResult GetResult(
454 TimeSpan timeout,
455 bool exitContext);
456
457 /// <summary>
458 /// Get the result of the work item.
459 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
460 /// </summary>
461 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
462 /// <param name="exitContext">
463 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
464 /// </param>
465 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
466 /// <returns>The result of the work item</returns>
467 /// On timeout throws WorkItemTimeoutException
468 /// On cancel throws WorkItemCancelException
469 TResult GetResult(
470 int millisecondsTimeout,
471 bool exitContext,
472 WaitHandle cancelWaitHandle);
473
474 /// <summary>
475 /// Get the result of the work item.
476 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
477 /// </summary>
478 /// <returns>The result of the work item</returns>
479 /// On timeout throws WorkItemTimeoutException
480 /// On cancel throws WorkItemCancelException
481 TResult GetResult(
482 TimeSpan timeout,
483 bool exitContext,
484 WaitHandle cancelWaitHandle);
485
486 /// <summary>
487 /// Get the result of the work item.
488 /// If the work item didn't run yet then the caller waits.
489 /// </summary>
490 /// <param name="e">Filled with the exception if one was thrown</param>
491 /// <returns>The result of the work item</returns>
492 TResult GetResult(out Exception e);
493
494 /// <summary>
495 /// Get the result of the work item.
496 /// If the work item didn't run yet then the caller waits until timeout.
497 /// </summary>
498 /// <param name="millisecondsTimeout"></param>
499 /// <param name="exitContext"></param>
500 /// <param name="e">Filled with the exception if one was thrown</param>
501 /// <returns>The result of the work item</returns>
502 /// On timeout throws WorkItemTimeoutException
503 TResult GetResult(
504 int millisecondsTimeout,
505 bool exitContext,
506 out Exception e);
507
508 /// <summary>
509 /// Get the result of the work item.
510 /// If the work item didn't run yet then the caller waits until timeout.
511 /// </summary>
512 /// <param name="exitContext"></param>
513 /// <param name="e">Filled with the exception if one was thrown</param>
514 /// <param name="timeout"></param>
515 /// <returns>The result of the work item</returns>
516 /// On timeout throws WorkItemTimeoutException
517 TResult GetResult(
518 TimeSpan timeout,
519 bool exitContext,
520 out Exception e);
521
522 /// <summary>
523 /// Get the result of the work item.
524 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
525 /// </summary>
526 /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
527 /// <param name="exitContext">
528 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
529 /// </param>
530 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
531 /// <param name="e">Filled with the exception if one was thrown</param>
532 /// <returns>The result of the work item</returns>
533 /// On timeout throws WorkItemTimeoutException
534 /// On cancel throws WorkItemCancelException
535 TResult GetResult(
536 int millisecondsTimeout,
537 bool exitContext,
538 WaitHandle cancelWaitHandle,
539 out Exception e);
540
541 /// <summary>
542 /// Get the result of the work item.
543 /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
544 /// </summary>
545 /// <returns>The result of the work item</returns>
546 /// <param name="cancelWaitHandle"></param>
547 /// <param name="e">Filled with the exception if one was thrown</param>
548 /// <param name="timeout"></param>
549 /// <param name="exitContext"></param>
550 /// On timeout throws WorkItemTimeoutException
551 /// On cancel throws WorkItemCancelException
552 TResult GetResult(
553 TimeSpan timeout,
554 bool exitContext,
555 WaitHandle cancelWaitHandle,
556 out Exception e);
557
558 /// <summary>
559 /// Gets an indication whether the asynchronous operation has completed.
560 /// </summary>
561 bool IsCompleted { get; }
562
563 /// <summary>
564 /// Gets an indication whether the asynchronous operation has been canceled.
565 /// </summary>
566 bool IsCanceled { get; }
567
568 /// <summary>
569 /// Gets the user-defined object that contains context data
570 /// for the work item method.
571 /// </summary>
572 object State { get; }
573
574 /// <summary>
575 /// Same as Cancel(false).
576 /// </summary>
577 bool Cancel();
578
579 /// <summary>
580 /// Cancel the work item execution.
581 /// If the work item is in the queue then it won't execute
582 /// If the work item is completed, it will remain completed
583 /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled
584 /// property to check if the work item has been cancelled. If the abortExecution is set to true then
585 /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution
586 /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException.
587 /// If the work item is already cancelled it will remain cancelled
588 /// </summary>
589 /// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
590 /// <returns>Returns true if the work item was not completed, otherwise false.</returns>
591 bool Cancel(bool abortExecution);
592
593 /// <summary>
594 /// Get the work item's priority
595 /// </summary>
596 WorkItemPriority WorkItemPriority { get; }
597
598 /// <summary>
599 /// Return the result, same as GetResult()
600 /// </summary>
601 TResult Result { get; }
602
603 /// <summary>
604 /// Returns the exception if occured otherwise returns null.
605 /// </summary>
606 object Exception { get; }
607 }
608
609 #endregion
610
611 #region .NET 3.5
612
613 // All these delegate are built-in .NET 3.5
614 // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity.
615
616 public delegate void Action();
617 public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
618 public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
619 public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
620
621 public delegate TResult Func<TResult>();
622 public delegate TResult Func<T, TResult>(T arg1);
623 public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
624 public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
625 public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
626
627 #endregion
628}
diff --git a/ThirdParty/SmartThreadPool/InternalInterfaces.cs b/ThirdParty/SmartThreadPool/InternalInterfaces.cs
new file mode 100644
index 0000000..8be7161
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/InternalInterfaces.cs
@@ -0,0 +1,27 @@
1
2namespace Amib.Threading.Internal
3{
4 /// <summary>
5 /// An internal delegate to call when the WorkItem starts or completes
6 /// </summary>
7 internal delegate void WorkItemStateCallback(WorkItem workItem);
8
9 internal interface IInternalWorkItemResult
10 {
11 event WorkItemStateCallback OnWorkItemStarted;
12 event WorkItemStateCallback OnWorkItemCompleted;
13 }
14
15 internal interface IInternalWaitableResult
16 {
17 /// <summary>
18 /// This method is intent for internal use.
19 /// </summary>
20 IWorkItemResult GetWorkItemResult();
21 }
22
23 public interface IHasWorkItemPriority
24 {
25 WorkItemPriority WorkItemPriority { get; }
26 }
27}
diff --git a/ThirdParty/SmartThreadPool/PriorityQueue.cs b/ThirdParty/SmartThreadPool/PriorityQueue.cs
index 63d5e84..6245fd8 100644
--- a/ThirdParty/SmartThreadPool/PriorityQueue.cs
+++ b/ThirdParty/SmartThreadPool/PriorityQueue.cs
@@ -1,240 +1,239 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2using System.Collections;
3 3using System.Collections.Generic;
4using System; 4using System.Diagnostics;
5using System.Collections; 5
6using System.Diagnostics; 6namespace Amib.Threading.Internal
7 7{
8namespace Amib.Threading.Internal 8 #region PriorityQueue class
9{ 9
10 #region PriorityQueue class 10 /// <summary>
11 11 /// PriorityQueue class
12 /// <summary> 12 /// This class is not thread safe because we use external lock
13 /// PriorityQueue class 13 /// </summary>
14 /// This class is not thread safe because we use external lock 14 public sealed class PriorityQueue : IEnumerable
15 /// </summary> 15 {
16 public sealed class PriorityQueue : IEnumerable 16 #region Private members
17 { 17
18 #region Private members 18 /// <summary>
19 19 /// The number of queues, there is one for each type of priority
20 /// <summary> 20 /// </summary>
21 /// The number of queues, there is one for each type of priority 21 private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
22 /// </summary> 22
23 private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; 23 /// <summary>
24 24 /// Work items queues. There is one for each type of priority
25 /// <summary> 25 /// </summary>
26 /// Work items queues. There is one for each type of priority 26 private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
27 /// </summary> 27
28 private Queue [] _queues = new Queue[_queuesCount]; 28 /// <summary>
29 29 /// The total number of work items within the queues
30 /// <summary> 30 /// </summary>
31 /// The total number of work items within the queues 31 private int _workItemsCount;
32 /// </summary> 32
33 private int _workItemsCount = 0; 33 /// <summary>
34 34 /// Use with IEnumerable interface
35 /// <summary> 35 /// </summary>
36 /// Use with IEnumerable interface 36 private int _version;
37 /// </summary> 37
38 private int _version = 0; 38 #endregion
39 39
40 #endregion 40 #region Contructor
41 41
42 #region Contructor 42 public PriorityQueue()
43 43 {
44 public PriorityQueue() 44 for(int i = 0; i < _queues.Length; ++i)
45 { 45 {
46 for(int i = 0; i < _queues.Length; ++i) 46 _queues[i] = new LinkedList<IHasWorkItemPriority>();
47 { 47 }
48 _queues[i] = new Queue(); 48 }
49 } 49
50 } 50 #endregion
51 51
52 #endregion 52 #region Methods
53 53
54 #region Methods 54 /// <summary>
55 55 /// Enqueue a work item.
56 /// <summary> 56 /// </summary>
57 /// Enqueue a work item. 57 /// <param name="workItem">A work item</param>
58 /// </summary> 58 public void Enqueue(IHasWorkItemPriority workItem)
59 /// <param name="workItem">A work item</param> 59 {
60 public void Enqueue(IHasWorkItemPriority workItem) 60 Debug.Assert(null != workItem);
61 { 61
62 Debug.Assert(null != workItem); 62 int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
63 63 Debug.Assert(queueIndex >= 0);
64 int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; 64 Debug.Assert(queueIndex < _queuesCount);
65 Debug.Assert(queueIndex >= 0); 65
66 Debug.Assert(queueIndex < _queuesCount); 66 _queues[queueIndex].AddLast(workItem);
67 67 ++_workItemsCount;
68 _queues[queueIndex].Enqueue(workItem); 68 ++_version;
69 ++_workItemsCount; 69 }
70 ++_version; 70
71 } 71 /// <summary>
72 72 /// Dequeque a work item.
73 /// <summary> 73 /// </summary>
74 /// Dequeque a work item. 74 /// <returns>Returns the next work item</returns>
75 /// </summary> 75 public IHasWorkItemPriority Dequeue()
76 /// <returns>Returns the next work item</returns> 76 {
77 public IHasWorkItemPriority Dequeue() 77 IHasWorkItemPriority workItem = null;
78 { 78
79 IHasWorkItemPriority workItem = null; 79 if(_workItemsCount > 0)
80 80 {
81 if(_workItemsCount > 0) 81 int queueIndex = GetNextNonEmptyQueue(-1);
82 { 82 Debug.Assert(queueIndex >= 0);
83 int queueIndex = GetNextNonEmptyQueue(-1); 83 workItem = _queues[queueIndex].First.Value;
84 Debug.Assert(queueIndex >= 0); 84 _queues[queueIndex].RemoveFirst();
85 workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority; 85 Debug.Assert(null != workItem);
86 Debug.Assert(null != workItem); 86 --_workItemsCount;
87 --_workItemsCount; 87 ++_version;
88 ++_version; 88 }
89 } 89
90 90 return workItem;
91 return workItem; 91 }
92 } 92
93 93 /// <summary>
94 /// <summary> 94 /// Find the next non empty queue starting at queue queueIndex+1
95 /// Find the next non empty queue starting at queue queueIndex+1 95 /// </summary>
96 /// </summary> 96 /// <param name="queueIndex">The index-1 to start from</param>
97 /// <param name="queueIndex">The index-1 to start from</param> 97 /// <returns>
98 /// <returns> 98 /// The index of the next non empty queue or -1 if all the queues are empty
99 /// The index of the next non empty queue or -1 if all the queues are empty 99 /// </returns>
100 /// </returns> 100 private int GetNextNonEmptyQueue(int queueIndex)
101 private int GetNextNonEmptyQueue(int queueIndex) 101 {
102 { 102 for(int i = queueIndex+1; i < _queuesCount; ++i)
103 for(int i = queueIndex+1; i < _queuesCount; ++i) 103 {
104 { 104 if(_queues[i].Count > 0)
105 if(_queues[i].Count > 0) 105 {
106 { 106 return i;
107 return i; 107 }
108 } 108 }
109 } 109 return -1;
110 return -1; 110 }
111 } 111
112 112 /// <summary>
113 /// <summary> 113 /// The number of work items
114 /// The number of work items 114 /// </summary>
115 /// </summary> 115 public int Count
116 public int Count 116 {
117 { 117 get
118 get 118 {
119 { 119 return _workItemsCount;
120 return _workItemsCount; 120 }
121 } 121 }
122 } 122
123 123 /// <summary>
124 /// <summary> 124 /// Clear all the work items
125 /// Clear all the work items 125 /// </summary>
126 /// </summary> 126 public void Clear()
127 public void Clear() 127 {
128 { 128 if (_workItemsCount > 0)
129 if (_workItemsCount > 0) 129 {
130 { 130 foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
131 foreach(Queue queue in _queues) 131 {
132 { 132 queue.Clear();
133 queue.Clear(); 133 }
134 } 134 _workItemsCount = 0;
135 _workItemsCount = 0; 135 ++_version;
136 ++_version; 136 }
137 } 137 }
138 } 138
139 139 #endregion
140 #endregion 140
141 141 #region IEnumerable Members
142 #region IEnumerable Members 142
143 143 /// <summary>
144 /// <summary> 144 /// Returns an enumerator to iterate over the work items
145 /// Returns an enumerator to iterate over the work items 145 /// </summary>
146 /// </summary> 146 /// <returns>Returns an enumerator</returns>
147 /// <returns>Returns an enumerator</returns> 147 public IEnumerator GetEnumerator()
148 public IEnumerator GetEnumerator() 148 {
149 { 149 return new PriorityQueueEnumerator(this);
150 return new PriorityQueueEnumerator(this); 150 }
151 } 151
152 152 #endregion
153 #endregion 153
154 154 #region PriorityQueueEnumerator
155 #region PriorityQueueEnumerator 155
156 156 /// <summary>
157 /// <summary> 157 /// The class the implements the enumerator
158 /// The class the implements the enumerator 158 /// </summary>
159 /// </summary> 159 private class PriorityQueueEnumerator : IEnumerator
160 private class PriorityQueueEnumerator : IEnumerator 160 {
161 { 161 private readonly PriorityQueue _priorityQueue;
162 private PriorityQueue _priorityQueue; 162 private int _version;
163 private int _version; 163 private int _queueIndex;
164 private int _queueIndex; 164 private IEnumerator _enumerator;
165 private IEnumerator _enumerator; 165
166 166 public PriorityQueueEnumerator(PriorityQueue priorityQueue)
167 public PriorityQueueEnumerator(PriorityQueue priorityQueue) 167 {
168 { 168 _priorityQueue = priorityQueue;
169 _priorityQueue = priorityQueue; 169 _version = _priorityQueue._version;
170 _version = _priorityQueue._version; 170 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
171 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); 171 if (_queueIndex >= 0)
172 if (_queueIndex >= 0) 172 {
173 { 173 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
174 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 174 }
175 } 175 else
176 else 176 {
177 { 177 _enumerator = null;
178 _enumerator = null; 178 }
179 } 179 }
180 } 180
181 181 #region IEnumerator Members
182 #region IEnumerator Members 182
183 183 public void Reset()
184 public void Reset() 184 {
185 { 185 _version = _priorityQueue._version;
186 _version = _priorityQueue._version; 186 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
187 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); 187 if (_queueIndex >= 0)
188 if (_queueIndex >= 0) 188 {
189 { 189 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
190 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 190 }
191 } 191 else
192 else 192 {
193 { 193 _enumerator = null;
194 _enumerator = null; 194 }
195 } 195 }
196 } 196
197 197 public object Current
198 public object Current 198 {
199 { 199 get
200 get 200 {
201 { 201 Debug.Assert(null != _enumerator);
202 Debug.Assert(null != _enumerator); 202 return _enumerator.Current;
203 return _enumerator.Current; 203 }
204 } 204 }
205 } 205
206 206 public bool MoveNext()
207 public bool MoveNext() 207 {
208 { 208 if (null == _enumerator)
209 if (null == _enumerator) 209 {
210 { 210 return false;
211 return false; 211 }
212 } 212
213 213 if(_version != _priorityQueue._version)
214 if(_version != _priorityQueue._version) 214 {
215 { 215 throw new InvalidOperationException("The collection has been modified");
216 throw new InvalidOperationException("The collection has been modified"); 216
217 217 }
218 } 218 if (!_enumerator.MoveNext())
219 if (!_enumerator.MoveNext()) 219 {
220 { 220 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
221 _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); 221 if(-1 == _queueIndex)
222 if(-1 == _queueIndex) 222 {
223 { 223 return false;
224 return false; 224 }
225 } 225 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
226 _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); 226 _enumerator.MoveNext();
227 _enumerator.MoveNext(); 227 return true;
228 return true; 228 }
229 } 229 return true;
230 return true; 230 }
231 } 231
232 232 #endregion
233 #endregion 233 }
234 } 234
235 235 #endregion
236 #endregion 236 }
237 } 237
238 238 #endregion
239 #endregion 239}
240}
diff --git a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1651e78
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs
@@ -0,0 +1,23 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5[assembly: AssemblyTitle("Amib.Threading")]
6[assembly: AssemblyDescription("Smart Thread Pool")]
7[assembly: AssemblyConfiguration("")]
8[assembly: AssemblyCompany("")]
9[assembly: AssemblyProduct("Amib.Threading")]
10[assembly: AssemblyCopyright("")]
11[assembly: AssemblyTrademark("")]
12[assembly: AssemblyCulture("")]
13[assembly: ComVisible(false)]
14[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")]
15[assembly: AssemblyVersion("2.2.3.0")]
16
17#if (_PUBLISH)
18[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")]
19#else
20[assembly: InternalsVisibleTo("STPTests")]
21#endif
22
23
diff --git a/ThirdParty/SmartThreadPool/SLExt.cs b/ThirdParty/SmartThreadPool/SLExt.cs
new file mode 100644
index 0000000..fafff19
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/SLExt.cs
@@ -0,0 +1,16 @@
1#if _SILVERLIGHT
2
3using System.Threading;
4
5namespace Amib.Threading
6{
7 public enum ThreadPriority
8 {
9 Lowest,
10 BelowNormal,
11 Normal,
12 AboveNormal,
13 Highest,
14 }
15}
16#endif
diff --git a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs
new file mode 100644
index 0000000..3b92645
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs
@@ -0,0 +1,62 @@
1#if !(_WINDOWS_CE)
2
3using System;
4using System.Threading;
5
6namespace Amib.Threading.Internal
7{
8#if _WINDOWS || WINDOWS_PHONE
9 internal static class STPEventWaitHandle
10 {
11 public const int WaitTimeout = Timeout.Infinite;
12
13 internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
14 {
15 return WaitHandle.WaitAll(waitHandles, millisecondsTimeout);
16 }
17
18 internal static int WaitAny(WaitHandle[] waitHandles)
19 {
20 return WaitHandle.WaitAny(waitHandles);
21 }
22
23 internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
24 {
25 return WaitHandle.WaitAny(waitHandles, millisecondsTimeout);
26 }
27
28 internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
29 {
30 return waitHandle.WaitOne(millisecondsTimeout);
31 }
32 }
33#else
34 internal static class STPEventWaitHandle
35 {
36 public const int WaitTimeout = Timeout.Infinite;
37
38 internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
39 {
40 return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
41 }
42
43 internal static int WaitAny(WaitHandle[] waitHandles)
44 {
45 return WaitHandle.WaitAny(waitHandles);
46 }
47
48 internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
49 {
50 return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
51 }
52
53 internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
54 {
55 return waitHandle.WaitOne(millisecondsTimeout, exitContext);
56 }
57 }
58#endif
59
60}
61
62#endif \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
index 077cf17..2508661 100644
--- a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
+++ b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
@@ -1,354 +1,448 @@
1using System; 1using System;
2using System.Diagnostics; 2using System.Diagnostics;
3 3using System.Threading;
4namespace Amib.Threading.Internal 4
5{ 5namespace Amib.Threading
6 internal enum STPPerformanceCounterType 6{
7 { 7 public interface ISTPPerformanceCountersReader
8 // Fields 8 {
9 ActiveThreads = 0, 9 long InUseThreads { get; }
10 InUseThreads = 1, 10 long ActiveThreads { get; }
11 OverheadThreads = 2, 11 long WorkItemsQueued { get; }
12 OverheadThreadsPercent = 3, 12 long WorkItemsProcessed { get; }
13 OverheadThreadsPercentBase = 4, 13 }
14 14}
15 WorkItems = 5, 15
16 WorkItemsInQueue = 6, 16namespace Amib.Threading.Internal
17 WorkItemsProcessed = 7, 17{
18 18 internal interface ISTPInstancePerformanceCounters : IDisposable
19 WorkItemsQueuedPerSecond = 8, 19 {
20 WorkItemsProcessedPerSecond = 9, 20 void Close();
21 21 void SampleThreads(long activeThreads, long inUseThreads);
22 AvgWorkItemWaitTime = 10, 22 void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
23 AvgWorkItemWaitTimeBase = 11, 23 void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
24 24 void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
25 AvgWorkItemProcessTime = 12, 25 }
26 AvgWorkItemProcessTimeBase = 13, 26#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
27 27
28 WorkItemsGroups = 14, 28 internal enum STPPerformanceCounterType
29 29 {
30 LastCounter = 14, 30 // Fields
31 } 31 ActiveThreads = 0,
32 32 InUseThreads = 1,
33 33 OverheadThreads = 2,
34 /// <summary> 34 OverheadThreadsPercent = 3,
35 /// Summary description for STPPerformanceCounter. 35 OverheadThreadsPercentBase = 4,
36 /// </summary> 36
37 internal class STPPerformanceCounter 37 WorkItems = 5,
38 { 38 WorkItemsInQueue = 6,
39 // Fields 39 WorkItemsProcessed = 7,
40 private PerformanceCounterType _pcType; 40
41 protected string _counterHelp; 41 WorkItemsQueuedPerSecond = 8,
42 protected string _counterName; 42 WorkItemsProcessedPerSecond = 9,
43 43
44 // Methods 44 AvgWorkItemWaitTime = 10,
45 public STPPerformanceCounter( 45 AvgWorkItemWaitTimeBase = 11,
46 string counterName, 46
47 string counterHelp, 47 AvgWorkItemProcessTime = 12,
48 PerformanceCounterType pcType) 48 AvgWorkItemProcessTimeBase = 13,
49 { 49
50 this._counterName = counterName; 50 WorkItemsGroups = 14,
51 this._counterHelp = counterHelp; 51
52 this._pcType = pcType; 52 LastCounter = 14,
53 } 53 }
54 54
55 public void AddCounterToCollection(CounterCreationDataCollection counterData) 55
56 { 56 /// <summary>
57 CounterCreationData counterCreationData = new CounterCreationData( 57 /// Summary description for STPPerformanceCounter.
58 _counterName, 58 /// </summary>
59 _counterHelp, 59 internal class STPPerformanceCounter
60 _pcType); 60 {
61 61 // Fields
62 counterData.Add(counterCreationData); 62 private readonly PerformanceCounterType _pcType;
63 } 63 protected string _counterHelp;
64 64 protected string _counterName;
65 // Properties 65
66 public string Name 66 // Methods
67 { 67 public STPPerformanceCounter(
68 get 68 string counterName,
69 { 69 string counterHelp,
70 return _counterName; 70 PerformanceCounterType pcType)
71 } 71 {
72 } 72 _counterName = counterName;
73 } 73 _counterHelp = counterHelp;
74 74 _pcType = pcType;
75 internal class STPPerformanceCounters 75 }
76 { 76
77 // Fields 77 public void AddCounterToCollection(CounterCreationDataCollection counterData)
78 internal STPPerformanceCounter[] _stpPerformanceCounters; 78 {
79 private static STPPerformanceCounters _instance; 79 CounterCreationData counterCreationData = new CounterCreationData(
80 internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; 80 _counterName,
81 internal const string _stpCategoryName = "SmartThreadPool"; 81 _counterHelp,
82 82 _pcType);
83 // Methods 83
84 static STPPerformanceCounters() 84 counterData.Add(counterCreationData);
85 { 85 }
86 _instance = new STPPerformanceCounters(); 86
87 } 87 // Properties
88 88 public string Name
89 private STPPerformanceCounters() 89 {
90 { 90 get
91 STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] 91 {
92 { 92 return _counterName;
93 new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), 93 }
94 new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), 94 }
95 new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), 95 }
96 new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), 96
97 new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), 97 internal class STPPerformanceCounters
98 98 {
99 new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), 99 // Fields
100 new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), 100 internal STPPerformanceCounter[] _stpPerformanceCounters;
101 new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), 101 private static readonly STPPerformanceCounters _instance;
102 102 internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
103 new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), 103 internal const string _stpCategoryName = "SmartThreadPool";
104 new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), 104
105 105 // Methods
106 new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), 106 static STPPerformanceCounters()
107 new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), 107 {
108 108 _instance = new STPPerformanceCounters();
109 new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), 109 }
110 new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), 110
111 111 private STPPerformanceCounters()
112 new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), 112 {
113 }; 113 STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[]
114 114 {
115 _stpPerformanceCounters = stpPerformanceCounters; 115 new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32),
116 SetupCategory(); 116 new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32),
117 } 117 new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32),
118 118 new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction),
119 private void SetupCategory() 119 new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase),
120 { 120
121 if (!PerformanceCounterCategory.Exists(_stpCategoryName)) 121 new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32),
122 { 122 new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32),
123 CounterCreationDataCollection counters = new CounterCreationDataCollection(); 123 new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32),
124 124
125 for (int i = 0; i < _stpPerformanceCounters.Length; i++) 125 new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32),
126 { 126 new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32),
127 _stpPerformanceCounters[i].AddCounterToCollection(counters); 127
128 } 128 new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64),
129 129 new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase),
130 130
131 // *********** Remark for .NET 2.0 *********** 131 new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64),
132 // If you are here, it means you got the warning that this overload 132 new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase),
133 // of the method is deprecated in .NET 2.0. To use the correct 133
134 // method overload, uncomment the third argument of 134 new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32),
135 // the method. 135 };
136 #pragma warning disable 0618 136
137 PerformanceCounterCategory.Create( 137 _stpPerformanceCounters = stpPerformanceCounters;
138 _stpCategoryName, 138 SetupCategory();
139 _stpCategoryHelp, 139 }
140 //PerformanceCounterCategoryType.MultiInstance, 140
141 counters); 141 private void SetupCategory()
142 #pragma warning restore 0618 142 {
143 } 143 if (!PerformanceCounterCategory.Exists(_stpCategoryName))
144 } 144 {
145 145 CounterCreationDataCollection counters = new CounterCreationDataCollection();
146 // Properties 146
147 public static STPPerformanceCounters Instance 147 for (int i = 0; i < _stpPerformanceCounters.Length; i++)
148 { 148 {
149 get 149 _stpPerformanceCounters[i].AddCounterToCollection(counters);
150 { 150 }
151 return _instance; 151
152 } 152 PerformanceCounterCategory.Create(
153 } 153 _stpCategoryName,
154 } 154 _stpCategoryHelp,
155 155 PerformanceCounterCategoryType.MultiInstance,
156 internal class STPInstancePerformanceCounter : IDisposable 156 counters);
157 { 157
158 // Fields 158 }
159 private PerformanceCounter _pcs; 159 }
160 160
161 // Methods 161 // Properties
162 protected STPInstancePerformanceCounter() 162 public static STPPerformanceCounters Instance
163 { 163 {
164 } 164 get
165 165 {
166 public STPInstancePerformanceCounter( 166 return _instance;
167 string instance, 167 }
168 STPPerformanceCounterType spcType) 168 }
169 { 169 }
170 STPPerformanceCounters counters = STPPerformanceCounters.Instance; 170
171 _pcs = new PerformanceCounter( 171 internal class STPInstancePerformanceCounter : IDisposable
172 STPPerformanceCounters._stpCategoryName, 172 {
173 counters._stpPerformanceCounters[(int) spcType].Name, 173 // Fields
174 instance, 174 private bool _isDisposed;
175 false); 175 private PerformanceCounter _pcs;
176 _pcs.RawValue = _pcs.RawValue; 176
177 } 177 // Methods
178 178 protected STPInstancePerformanceCounter()
179 ~STPInstancePerformanceCounter() 179 {
180 { 180 _isDisposed = false;
181 Close(); 181 }
182 } 182
183 183 public STPInstancePerformanceCounter(
184 public void Close() 184 string instance,
185 { 185 STPPerformanceCounterType spcType) : this()
186 if (_pcs != null) 186 {
187 { 187 STPPerformanceCounters counters = STPPerformanceCounters.Instance;
188 _pcs.RemoveInstance(); 188 _pcs = new PerformanceCounter(
189 _pcs.Close(); 189 STPPerformanceCounters._stpCategoryName,
190 _pcs = null; 190 counters._stpPerformanceCounters[(int) spcType].Name,
191 } 191 instance,
192 } 192 false);
193 193 _pcs.RawValue = _pcs.RawValue;
194 public void Dispose() 194 }
195 { 195
196 Close(); 196
197 GC.SuppressFinalize(this); 197 public void Close()
198 } 198 {
199 199 if (_pcs != null)
200 public virtual void Increment() 200 {
201 { 201 _pcs.RemoveInstance();
202 _pcs.Increment(); 202 _pcs.Close();
203 } 203 _pcs = null;
204 204 }
205 public virtual void IncrementBy(long val) 205 }
206 { 206
207 _pcs.IncrementBy(val); 207 public void Dispose()
208 } 208 {
209 209 Dispose(true);
210 public virtual void Set(long val) 210 }
211 { 211
212 _pcs.RawValue = val; 212 public virtual void Dispose(bool disposing)
213 } 213 {
214 } 214 if (!_isDisposed)
215 215 {
216 internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter 216 if (disposing)
217 { 217 {
218 // Methods 218 Close();
219 public STPInstanceNullPerformanceCounter() {} 219 }
220 public override void Increment() {} 220 }
221 public override void IncrementBy(long value) {} 221 _isDisposed = true;
222 public override void Set(long val) {} 222 }
223 } 223
224 224 public virtual void Increment()
225 internal interface ISTPInstancePerformanceCounters : IDisposable 225 {
226 { 226 _pcs.Increment();
227 void Close(); 227 }
228 void SampleThreads(long activeThreads, long inUseThreads); 228
229 void SampleWorkItems(long workItemsQueued, long workItemsProcessed); 229 public virtual void IncrementBy(long val)
230 void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); 230 {
231 void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); 231 _pcs.IncrementBy(val);
232 } 232 }
233 233
234 234 public virtual void Set(long val)
235 internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable 235 {
236 { 236 _pcs.RawValue = val;
237 // Fields 237 }
238 private STPInstancePerformanceCounter[] _pcs; 238 }
239 private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; 239
240 240 internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
241 // Methods 241 {
242 static STPInstancePerformanceCounters() 242 // Methods
243 { 243 public override void Increment() {}
244 _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); 244 public override void IncrementBy(long value) {}
245 } 245 public override void Set(long val) {}
246 246 }
247 public STPInstancePerformanceCounters(string instance) 247
248 { 248
249 _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; 249
250 // STPPerformanceCounters counters = STPPerformanceCounters.Instance; 250 internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
251 for (int i = 0; i < _pcs.Length; i++) 251 {
252 { 252 private bool _isDisposed;
253 if (instance != null) 253 // Fields
254 { 254 private STPInstancePerformanceCounter[] _pcs;
255 _pcs[i] = new STPInstancePerformanceCounter( 255 private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
256 instance, 256
257 (STPPerformanceCounterType) i); 257 // Methods
258 } 258 static STPInstancePerformanceCounters()
259 else 259 {
260 { 260 _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
261 _pcs[i] = _stpInstanceNullPerformanceCounter; 261 }
262 } 262
263 } 263 public STPInstancePerformanceCounters(string instance)
264 } 264 {
265 265 _isDisposed = false;
266 266 _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
267 public void Close() 267
268 { 268 // Call the STPPerformanceCounters.Instance so the static constructor will
269 if (null != _pcs) 269 // intialize the STPPerformanceCounters singleton.
270 { 270 STPPerformanceCounters.Instance.GetHashCode();
271 for (int i = 0; i < _pcs.Length; i++) 271
272 { 272 for (int i = 0; i < _pcs.Length; i++)
273 if (null != _pcs[i]) 273 {
274 { 274 if (instance != null)
275 _pcs[i].Close(); 275 {
276 } 276 _pcs[i] = new STPInstancePerformanceCounter(
277 } 277 instance,
278 _pcs = null; 278 (STPPerformanceCounterType) i);
279 } 279 }
280 } 280 else
281 281 {
282 ~STPInstancePerformanceCounters() 282 _pcs[i] = _stpInstanceNullPerformanceCounter;
283 { 283 }
284 Close(); 284 }
285 } 285 }
286 286
287 public void Dispose() 287
288 { 288 public void Close()
289 Close(); 289 {
290 GC.SuppressFinalize(this); 290 if (null != _pcs)
291 } 291 {
292 292 for (int i = 0; i < _pcs.Length; i++)
293 private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) 293 {
294 { 294 if (null != _pcs[i])
295 return _pcs[(int) spcType]; 295 {
296 } 296 _pcs[i].Dispose();
297 297 }
298 public void SampleThreads(long activeThreads, long inUseThreads) 298 }
299 { 299 _pcs = null;
300 GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); 300 }
301 GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); 301 }
302 GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); 302
303 303 public void Dispose()
304 GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); 304 {
305 GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); 305 Dispose(true);
306 } 306 }
307 307
308 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) 308 public virtual void Dispose(bool disposing)
309 { 309 {
310 GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); 310 if (!_isDisposed)
311 GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); 311 {
312 GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); 312 if (disposing)
313 313 {
314 GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); 314 Close();
315 GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); 315 }
316 } 316 }
317 317 _isDisposed = true;
318 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) 318 }
319 { 319
320 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); 320 private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
321 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); 321 {
322 } 322 return _pcs[(int) spcType];
323 323 }
324 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) 324
325 { 325 public void SampleThreads(long activeThreads, long inUseThreads)
326 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); 326 {
327 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); 327 GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
328 } 328 GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
329 } 329 GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
330 330
331 internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable 331 GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
332 { 332 GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
333 static NullSTPInstancePerformanceCounters() 333 }
334 { 334
335 } 335 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
336 336 {
337 private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null); 337 GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
338 338 GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
339 public static NullSTPInstancePerformanceCounters Instance 339 GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
340 { 340
341 get { return _instance; } 341 GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
342 } 342 GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
343 343 }
344 public NullSTPInstancePerformanceCounters(string instance) {} 344
345 public void Close() {} 345 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
346 public void Dispose() {} 346 {
347 347 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
348 public void SampleThreads(long activeThreads, long inUseThreads) {} 348 GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
349 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} 349 }
350 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} 350
351 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} 351 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
352 } 352 {
353 353 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
354} 354 GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
355 }
356 }
357#endif
358
359 internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
360 {
361 private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
362
363 public static NullSTPInstancePerformanceCounters Instance
364 {
365 get { return _instance; }
366 }
367
368 public void Close() {}
369 public void Dispose() {}
370
371 public void SampleThreads(long activeThreads, long inUseThreads) {}
372 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
373 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
374 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
375 public long InUseThreads
376 {
377 get { return 0; }
378 }
379
380 public long ActiveThreads
381 {
382 get { return 0; }
383 }
384
385 public long WorkItemsQueued
386 {
387 get { return 0; }
388 }
389
390 public long WorkItemsProcessed
391 {
392 get { return 0; }
393 }
394 }
395
396 internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
397 {
398 public void Close() { }
399 public void Dispose() { }
400
401 private long _activeThreads;
402 private long _inUseThreads;
403 private long _workItemsQueued;
404 private long _workItemsProcessed;
405
406 public long InUseThreads
407 {
408 get { return _inUseThreads; }
409 }
410
411 public long ActiveThreads
412 {
413 get { return _activeThreads; }
414 }
415
416 public long WorkItemsQueued
417 {
418 get { return _workItemsQueued; }
419 }
420
421 public long WorkItemsProcessed
422 {
423 get { return _workItemsProcessed; }
424 }
425
426 public void SampleThreads(long activeThreads, long inUseThreads)
427 {
428 _activeThreads = activeThreads;
429 _inUseThreads = inUseThreads;
430 }
431
432 public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
433 {
434 _workItemsQueued = workItemsQueued;
435 _workItemsProcessed = workItemsProcessed;
436 }
437
438 public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
439 {
440 // Not supported
441 }
442
443 public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
444 {
445 // Not supported
446 }
447 }
448}
diff --git a/ThirdParty/SmartThreadPool/STPStartInfo.cs b/ThirdParty/SmartThreadPool/STPStartInfo.cs
index fa9ceb4..2ec8dc6 100644
--- a/ThirdParty/SmartThreadPool/STPStartInfo.cs
+++ b/ThirdParty/SmartThreadPool/STPStartInfo.cs
@@ -1,113 +1,212 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2using System.Threading;
3 3
4using System.Threading; 4namespace Amib.Threading
5 5{
6namespace Amib.Threading 6 /// <summary>
7{ 7 /// Summary description for STPStartInfo.
8 /// <summary> 8 /// </summary>
9 /// Summary description for STPStartInfo. 9 public class STPStartInfo : WIGStartInfo
10 /// </summary> 10 {
11 public class STPStartInfo : WIGStartInfo 11 private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
12 { 12 private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
13 /// <summary> 13 private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
14 /// Idle timeout in milliseconds. 14#if !(WINDOWS_PHONE)
15 /// If a thread is idle for _idleTimeout milliseconds then 15 private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
16 /// it may quit. 16#endif
17 /// </summary> 17 private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
18 private int _idleTimeout; 18 private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
19 19 private bool _enableLocalPerformanceCounters;
20 /// <summary> 20 private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
21 /// The lower limit of threads in the pool. 21 private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
22 /// </summary> 22
23 private int _minWorkerThreads; 23 public STPStartInfo()
24 24 {
25 /// <summary> 25 _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
26 /// The upper limit of threads in the pool. 26#if !(WINDOWS_PHONE)
27 /// </summary> 27 _threadPriority = SmartThreadPool.DefaultThreadPriority;
28 private int _maxWorkerThreads; 28#endif
29 29 _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
30 /// <summary> 30 _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
31 /// The priority of the threads in the pool 31 _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
32 /// </summary> 32 }
33 private ThreadPriority _threadPriority; 33
34 34 public STPStartInfo(STPStartInfo stpStartInfo)
35 /// <summary> 35 : base(stpStartInfo)
36 /// The thread pool name. Threads will get names depending on this. 36 {
37 /// </summary> 37 _idleTimeout = stpStartInfo.IdleTimeout;
38 private string _threadPoolName; 38 _minWorkerThreads = stpStartInfo.MinWorkerThreads;
39 39 _maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
40 /// <summary> 40#if !(WINDOWS_PHONE)
41 /// If this field is not null then the performance counters are enabled 41 _threadPriority = stpStartInfo.ThreadPriority;
42 /// and use the string as the name of the instance. 42#endif
43 /// </summary> 43 _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
44 private string _pcInstanceName; 44 _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
45 45 _threadPoolName = stpStartInfo._threadPoolName;
46 private int _stackSize; 46 _areThreadsBackground = stpStartInfo.AreThreadsBackground;
47 47#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
48 public STPStartInfo() : base() 48 _apartmentState = stpStartInfo._apartmentState;
49 { 49#endif
50 _idleTimeout = SmartThreadPool.DefaultIdleTimeout; 50 }
51 _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; 51
52 _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; 52 /// <summary>
53 _threadPriority = SmartThreadPool.DefaultThreadPriority; 53 /// Get/Set the idle timeout in milliseconds.
54 _threadPoolName = SmartThreadPool.DefaultThreadPoolName; 54 /// If a thread is idle (starved) longer than IdleTimeout then it may quit.
55 _pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; 55 /// </summary>
56 _stackSize = SmartThreadPool.DefaultStackSize; 56 public virtual int IdleTimeout
57 } 57 {
58 58 get { return _idleTimeout; }
59 public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo) 59 set
60 { 60 {
61 _idleTimeout = stpStartInfo._idleTimeout; 61 ThrowIfReadOnly();
62 _minWorkerThreads = stpStartInfo._minWorkerThreads; 62 _idleTimeout = value;
63 _maxWorkerThreads = stpStartInfo._maxWorkerThreads; 63 }
64 _threadPriority = stpStartInfo._threadPriority; 64 }
65 _threadPoolName = stpStartInfo._threadPoolName; 65
66 _pcInstanceName = stpStartInfo._pcInstanceName; 66
67 _stackSize = stpStartInfo._stackSize; 67 /// <summary>
68 } 68 /// Get/Set the lower limit of threads in the pool.
69 69 /// </summary>
70 public int IdleTimeout 70 public virtual int MinWorkerThreads
71 { 71 {
72 get { return _idleTimeout; } 72 get { return _minWorkerThreads; }
73 set { _idleTimeout = value; } 73 set
74 } 74 {
75 75 ThrowIfReadOnly();
76 public int MinWorkerThreads 76 _minWorkerThreads = value;
77 { 77 }
78 get { return _minWorkerThreads; } 78 }
79 set { _minWorkerThreads = value; } 79
80 } 80
81 81 /// <summary>
82 public int MaxWorkerThreads 82 /// Get/Set the upper limit of threads in the pool.
83 { 83 /// </summary>
84 get { return _maxWorkerThreads; } 84 public virtual int MaxWorkerThreads
85 set { _maxWorkerThreads = value; } 85 {
86 } 86 get { return _maxWorkerThreads; }
87 87 set
88 public ThreadPriority ThreadPriority 88 {
89 { 89 ThrowIfReadOnly();
90 get { return _threadPriority; } 90 _maxWorkerThreads = value;
91 set { _threadPriority = value; } 91 }
92 } 92 }
93 93
94 public virtual string ThreadPoolName 94#if !(WINDOWS_PHONE)
95 { 95 /// <summary>
96 get { return _threadPoolName; } 96 /// Get/Set the scheduling priority of the threads in the pool.
97 set { _threadPoolName = value; } 97 /// The Os handles the scheduling.
98 } 98 /// </summary>
99 99 public virtual ThreadPriority ThreadPriority
100 100 {
101 public string PerformanceCounterInstanceName 101 get { return _threadPriority; }
102 { 102 set
103 get { return _pcInstanceName; } 103 {
104 set { _pcInstanceName = value; } 104 ThrowIfReadOnly();
105 } 105 _threadPriority = value;
106 106 }
107 public int StackSize 107 }
108 { 108#endif
109 get { return _stackSize; } 109 /// <summary>
110 set { _stackSize = value; } 110 /// Get/Set the thread pool name. Threads will get names depending on this.
111 } 111 /// </summary>
112 } 112 public virtual string ThreadPoolName {
113} 113 get { return _threadPoolName; }
114 set
115 {
116 ThrowIfReadOnly ();
117 _threadPoolName = value;
118 }
119 }
120
121 /// <summary>
122 /// Get/Set the performance counter instance name of this SmartThreadPool
123 /// The default is null which indicate not to use performance counters at all.
124 /// </summary>
125 public virtual string PerformanceCounterInstanceName
126 {
127 get { return _performanceCounterInstanceName; }
128 set
129 {
130 ThrowIfReadOnly();
131 _performanceCounterInstanceName = value;
132 }
133 }
134
135 /// <summary>
136 /// Enable/Disable the local performance counter.
137 /// This enables the user to get some performance information about the SmartThreadPool
138 /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.)
139 /// The default is false.
140 /// </summary>
141 public virtual bool EnableLocalPerformanceCounters
142 {
143 get { return _enableLocalPerformanceCounters; }
144 set
145 {
146 ThrowIfReadOnly();
147 _enableLocalPerformanceCounters = value;
148 }
149 }
150
151 /// <summary>
152 /// Get/Set backgroundness of thread in thread pool.
153 /// </summary>
154 public virtual bool AreThreadsBackground
155 {
156 get { return _areThreadsBackground; }
157 set
158 {
159 ThrowIfReadOnly ();
160 _areThreadsBackground = value;
161 }
162 }
163
164 /// <summary>
165 /// Get a readonly version of this STPStartInfo.
166 /// </summary>
167 /// <returns>Returns a readonly reference to this STPStartInfo</returns>
168 public new STPStartInfo AsReadOnly()
169 {
170 return new STPStartInfo(this) { _readOnly = true };
171 }
172
173#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
174
175 private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState;
176
177 /// <summary>
178 /// Get/Set the apartment state of threads in the thread pool
179 /// </summary>
180 public ApartmentState ApartmentState
181 {
182 get { return _apartmentState; }
183 set
184 {
185 ThrowIfReadOnly();
186 _apartmentState = value;
187 }
188 }
189
190#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
191
192 /// <summary>
193 /// Get/Set the max stack size of threads in the thread pool
194 /// </summary>
195 public int? MaxStackSize
196 {
197 get { return _maxStackSize; }
198 set
199 {
200 ThrowIfReadOnly();
201 if (value.HasValue && value.Value < 0)
202 {
203 throw new ArgumentOutOfRangeException("value", "Value must be greater than 0.");
204 }
205 _maxStackSize = value;
206 }
207 }
208#endif
209
210#endif
211 }
212}
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
new file mode 100644
index 0000000..ba7d73f
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
@@ -0,0 +1,60 @@
1
2using System;
3using Amib.Threading.Internal;
4
5namespace Amib.Threading
6{
7 public partial class SmartThreadPool
8 {
9 #region ThreadEntry class
10
11 internal class ThreadEntry
12 {
13 /// <summary>
14 /// The thread creation time
15 /// The value is stored as UTC value.
16 /// </summary>
17 private readonly DateTime _creationTime;
18
19 /// <summary>
20 /// The last time this thread has been running
21 /// It is updated by IAmAlive() method
22 /// The value is stored as UTC value.
23 /// </summary>
24 private DateTime _lastAliveTime;
25
26 /// <summary>
27 /// A reference from each thread in the thread pool to its SmartThreadPool
28 /// object container.
29 /// With this variable a thread can know whatever it belongs to a
30 /// SmartThreadPool.
31 /// </summary>
32 private readonly SmartThreadPool _associatedSmartThreadPool;
33
34 /// <summary>
35 /// A reference to the current work item a thread from the thread pool
36 /// is executing.
37 /// </summary>
38 public WorkItem CurrentWorkItem { get; set; }
39
40 public ThreadEntry(SmartThreadPool stp)
41 {
42 _associatedSmartThreadPool = stp;
43 _creationTime = DateTime.UtcNow;
44 _lastAliveTime = DateTime.MinValue;
45 }
46
47 public SmartThreadPool AssociatedSmartThreadPool
48 {
49 get { return _associatedSmartThreadPool; }
50 }
51
52 public void IAmAlive()
53 {
54 _lastAliveTime = DateTime.UtcNow;
55 }
56 }
57
58 #endregion
59 }
60} \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs
index 19a0007..9256777 100644
--- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs
+++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs
@@ -1,1448 +1,1732 @@
1// Ami Bar 1#region Release History
2// amibar@gmail.com 2
3// 3// Smart Thread Pool
4// Smart thread pool in C#. 4// 7 Aug 2004 - Initial release
5// 7 Aug 2004 - Initial release 5//
6// 14 Sep 2004 - Bug fixes 6// 14 Sep 2004 - Bug fixes
7// 15 Oct 2004 - Added new features 7//
8// - Work items return result. 8// 15 Oct 2004 - Added new features
9// - Support waiting synchronization for multiple work items. 9// - Work items return result.
10// - Work items can be cancelled. 10// - Support waiting synchronization for multiple work items.
11// - Passage of the caller thread’s context to the thread in the pool. 11// - Work items can be cancelled.
12// - Minimal usage of WIN32 handles. 12// - Passage of the caller thread’s context to the thread in the pool.
13// - Minor bug fixes. 13// - Minimal usage of WIN32 handles.
14// 26 Dec 2004 - Changes: 14// - Minor bug fixes.
15// - Removed static constructors. 15//
16// - Added finalizers. 16// 26 Dec 2004 - Changes:
17// - Changed Exceptions so they are serializable. 17// - Removed static constructors.
18// - Fixed the bug in one of the SmartThreadPool constructors. 18// - Added finalizers.
19// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. 19// - Changed Exceptions so they are serializable.
20// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. 20// - Fixed the bug in one of the SmartThreadPool constructors.
21// - Added PostExecute with options on which cases to call it. 21// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters.
22// - Added option to dispose of the state objects. 22// The SmartThreadPool.WaitAny() is still limited by the .NET Framework.
23// - Added a WaitForIdle() method that waits until the work items queue is empty. 23// - Added PostExecute with options on which cases to call it.
24// - Added an STPStartInfo class for the initialization of the thread pool. 24// - Added option to dispose of the state objects.
25// - Changed exception handling so if a work item throws an exception it 25// - Added a WaitForIdle() method that waits until the work items queue is empty.
26// is rethrown at GetResult(), rather then firing an UnhandledException event. 26// - Added an STPStartInfo class for the initialization of the thread pool.
27// Note that PostExecute exception are always ignored. 27// - Changed exception handling so if a work item throws an exception it
28// 25 Mar 2005 - Changes: 28// is rethrown at GetResult(), rather then firing an UnhandledException event.
29// - Fixed lost of work items bug 29// Note that PostExecute exception are always ignored.
30// 3 Jul 2005: Changes. 30//
31// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. 31// 25 Mar 2005 - Changes:
32// 16 Aug 2005: Changes. 32// - Fixed lost of work items bug
33// - Fixed bug where the InUseThreads becomes negative when canceling work items. 33//
34// 34// 3 Jul 2005: Changes.
35// 31 Jan 2006 - Changes: 35// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed.
36// - Added work items priority 36//
37// - Removed support of chained delegates in callbacks and post executes (nobody really use this) 37// 16 Aug 2005: Changes.
38// - Added work items groups 38// - Fixed bug where the InUseThreads becomes negative when canceling work items.
39// - Added work items groups idle event 39//
40// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array 40// 31 Jan 2006 - Changes:
41// it returns true rather then throwing an exception. 41// - Added work items priority
42// - Added option to start the STP and the WIG as suspended 42// - Removed support of chained delegates in callbacks and post executes (nobody really use this)
43// - Exception behavior changed, the real exception is returned by an 43// - Added work items groups
44// inner exception 44// - Added work items groups idle event
45// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) 45// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array
46// - Added performance counters 46// it returns true rather then throwing an exception.
47// - Added priority to the threads in the pool 47// - Added option to start the STP and the WIG as suspended
48// 48// - Exception behavior changed, the real exception is returned by an
49// 13 Feb 2006 - Changes: 49// inner exception
50// - Added a call to the dispose of the Performance Counter so 50// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.)
51// their won't be a Performance Counter leak. 51// - Added performance counters
52// - Added exception catch in case the Performance Counters cannot 52// - Added priority to the threads in the pool
53// be created. 53//
54 54// 13 Feb 2006 - Changes:
55using System; 55// - Added a call to the dispose of the Performance Counter so
56using System.Security; 56// their won't be a Performance Counter leak.
57using System.Threading; 57// - Added exception catch in case the Performance Counters cannot
58using System.Collections; 58// be created.
59using System.Diagnostics; 59//
60using System.Runtime.CompilerServices; 60// 17 May 2008 - Changes:
61 61// - Changed the dispose behavior and removed the Finalizers.
62using Amib.Threading.Internal; 62// - Enabled the change of the MaxThreads and MinThreads at run time.
63 63// - Enabled the change of the Concurrency of a IWorkItemsGroup at run
64namespace Amib.Threading 64// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency
65{ 65// refers to the MaxThreads.
66 #region SmartThreadPool class 66// - Improved the cancel behavior.
67 /// <summary> 67// - Added events for thread creation and termination.
68 /// Smart thread pool class. 68// - Fixed the HttpContext context capture.
69 /// </summary> 69// - Changed internal collections so they use generic collections
70 public class SmartThreadPool : IWorkItemsGroup, IDisposable 70// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup
71 { 71// - Added support for WinCE
72 #region Default Constants 72// - Added support for Action<T> and Func<T>
73 73//
74 /// <summary> 74// 07 April 2009 - Changes:
75 /// Default minimum number of threads the thread pool contains. (0) 75// - Added support for Silverlight and Mono
76 /// </summary> 76// - Added Join, Choice, and Pipe to SmartThreadPool.
77 public const int DefaultMinWorkerThreads = 0; 77// - Added local performance counters (for Mono, Silverlight, and WindowsCE)
78 78// - Changed duration measures from DateTime.Now to Stopwatch.
79 /// <summary> 79// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList<T>.
80 /// Default maximum number of threads the thread pool contains. (25) 80//
81 /// </summary> 81// 21 December 2009 - Changes:
82 public const int DefaultMaxWorkerThreads = 25; 82// - Added work item timeout (passive)
83 83//
84 /// <summary> 84// 20 August 2012 - Changes:
85 /// Default idle timeout in milliseconds. (One minute) 85// - Added set name to threads
86 /// </summary> 86// - Fixed the WorkItemsQueue.Dequeue.
87 public const int DefaultIdleTimeout = 60*1000; // One minute 87// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... }
88 88// - Fixed SmartThreadPool.Pipe
89 /// <summary> 89// - Added IsBackground option to threads
90 /// Indicate to copy the security context of the caller and then use it in the call. (false) 90// - Added ApartmentState to threads
91 /// </summary> 91// - Fixed thread creation when queuing many work items at the same time.
92 public const bool DefaultUseCallerCallContext = false; 92//
93 93// 24 August 2012 - Changes:
94 /// <summary> 94// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan
95 /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) 95// - Added option to set MaxStackSize of threads
96 /// </summary> 96
97 public const bool DefaultUseCallerHttpContext = false; 97#endregion
98 98
99 /// <summary> 99using System;
100 /// Indicate to dispose of the state objects if they support the IDispose interface. (false) 100using System.Security;
101 /// </summary> 101using System.Threading;
102 public const bool DefaultDisposeOfStateObjects = false; 102using System.Collections;
103 103using System.Collections.Generic;
104 /// <summary> 104using System.Diagnostics;
105 /// The default option to run the post execute 105using System.Runtime.CompilerServices;
106 /// </summary> 106
107 public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; 107using Amib.Threading.Internal;
108 108
109 /// <summary> 109namespace Amib.Threading
110 /// The default post execute method to run. 110{
111 /// When null it means not to call it. 111 #region SmartThreadPool class
112 /// </summary> 112 /// <summary>
113 public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback = null; 113 /// Smart thread pool class.
114 114 /// </summary>
115 /// <summary> 115 public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable
116 /// The default work item priority 116 {
117 /// </summary> 117 #region Public Default Constants
118 public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; 118
119 119 /// <summary>
120 /// <summary> 120 /// Default minimum number of threads the thread pool contains. (0)
121 /// The default is to work on work items as soon as they arrive 121 /// </summary>
122 /// and not to wait for the start. 122 public const int DefaultMinWorkerThreads = 0;
123 /// </summary> 123
124 public const bool DefaultStartSuspended = false; 124 /// <summary>
125 125 /// Default maximum number of threads the thread pool contains. (25)
126 /// <summary> 126 /// </summary>
127 /// The default is not to use the performance counters 127 public const int DefaultMaxWorkerThreads = 25;
128 /// </summary> 128
129 public static readonly string DefaultPerformanceCounterInstanceName = null; 129 /// <summary>
130 130 /// Default idle timeout in milliseconds. (One minute)
131 public static readonly int DefaultStackSize = 0; 131 /// </summary>
132 132 public const int DefaultIdleTimeout = 60*1000; // One minute
133 /// <summary> 133
134 /// The default thread priority 134 /// <summary>
135 /// </summary> 135 /// Indicate to copy the security context of the caller and then use it in the call. (false)
136 public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; 136 /// </summary>
137 137 public const bool DefaultUseCallerCallContext = false;
138 /// <summary> 138
139 /// The default thread pool name 139 /// <summary>
140 /// </summary> 140 /// Indicate to copy the HTTP context of the caller and then use it in the call. (false)
141 public const string DefaultThreadPoolName = "SmartThreadPool"; 141 /// </summary>
142 142 public const bool DefaultUseCallerHttpContext = false;
143 #endregion 143
144 144 /// <summary>
145 #region Member Variables 145 /// Indicate to dispose of the state objects if they support the IDispose interface. (false)
146 146 /// </summary>
147 /// <summary> 147 public const bool DefaultDisposeOfStateObjects = false;
148 /// Contains the name of this instance of SmartThreadPool. 148
149 /// Can be changed by the user. 149 /// <summary>
150 /// </summary> 150 /// The default option to run the post execute (CallToPostExecute.Always)
151 private string _name = DefaultThreadPoolName; 151 /// </summary>
152 152 public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always;
153 /// <summary> 153
154 /// Hashtable of all the threads in the thread pool. 154 /// <summary>
155 /// </summary> 155 /// The default post execute method to run. (None)
156 private Hashtable _workerThreads = Hashtable.Synchronized(new Hashtable()); 156 /// When null it means not to call it.
157 157 /// </summary>
158 /// <summary> 158 public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback;
159 /// Queue of work items. 159
160 /// </summary> 160 /// <summary>
161 private WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); 161 /// The default work item priority (WorkItemPriority.Normal)
162 162 /// </summary>
163 /// <summary> 163 public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal;
164 /// Count the work items handled. 164
165 /// Used by the performance counter. 165 /// <summary>
166 /// </summary> 166 /// The default is to work on work items as soon as they arrive
167 private long _workItemsProcessed = 0; 167 /// and not to wait for the start. (false)
168 168 /// </summary>
169 /// <summary> 169 public const bool DefaultStartSuspended = false;
170 /// Number of threads that currently work (not idle). 170
171 /// </summary> 171 /// <summary>
172 private int _inUseWorkerThreads = 0; 172 /// The default name to use for the performance counters instance. (null)
173 173 /// </summary>
174 /// <summary> 174 public static readonly string DefaultPerformanceCounterInstanceName;
175 /// Start information to use. 175
176 /// It is simpler than providing many constructors. 176#if !(WINDOWS_PHONE)
177 /// </summary> 177
178 private STPStartInfo _stpStartInfo = new STPStartInfo(); 178 /// <summary>
179 179 /// The default thread priority (ThreadPriority.Normal)
180 /// <summary> 180 /// </summary>
181 /// Total number of work items that are stored in the work items queue 181 public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal;
182 /// plus the work items that the threads in the pool are working on. 182#endif
183 /// </summary> 183 /// <summary>
184 private int _currentWorkItemsCount = 0; 184 /// The default thread pool name. (SmartThreadPool)
185 185 /// </summary>
186 /// <summary> 186 public const string DefaultThreadPoolName = "SmartThreadPool";
187 /// Signaled when the thread pool is idle, i.e. no thread is busy 187
188 /// and the work items queue is empty 188 /// <summary>
189 /// </summary> 189 /// The default Max Stack Size. (SmartThreadPool)
190 private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); 190 /// </summary>
191 191 public static readonly int? DefaultMaxStackSize = null;
192 /// <summary> 192
193 /// An event to signal all the threads to quit immediately. 193 /// <summary>
194 /// </summary> 194 /// The default fill state with params. (false)
195 private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); 195 /// It is relevant only to QueueWorkItem of Action&lt;...&gt;/Func&lt;...&gt;
196 196 /// </summary>
197 /// <summary> 197 public const bool DefaultFillStateWithArgs = false;
198 /// A flag to indicate the threads to quit. 198
199 /// </summary> 199 /// <summary>
200 private bool _shutdown = false; 200 /// The default thread backgroundness. (true)
201 201 /// </summary>
202 /// <summary> 202 public const bool DefaultAreThreadsBackground = true;
203 /// Counts the threads created in the pool. 203
204 /// It is used to name the threads. 204#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
205 /// </summary> 205 /// <summary>
206 private int _threadCounter = 0; 206 /// The default apartment state of a thread in the thread pool.
207 207 /// The default is ApartmentState.Unknown which means the STP will not
208 /// <summary> 208 /// set the apartment of the thread. It will use the .NET default.
209 /// Indicate that the SmartThreadPool has been disposed 209 /// </summary>
210 /// </summary> 210 public const ApartmentState DefaultApartmentState = ApartmentState.Unknown;
211 private bool _isDisposed = false; 211#endif
212 212
213 /// <summary> 213 #endregion
214 /// Event to send that the thread pool is idle 214
215 /// </summary> 215 #region Member Variables
216 private event EventHandler _stpIdle; 216
217 217 /// <summary>
218 /// <summary> 218 /// Dictionary of all the threads in the thread pool.
219 /// On idle event 219 /// </summary>
220 /// </summary> 220 private readonly SynchronizedDictionary<Thread, ThreadEntry> _workerThreads = new SynchronizedDictionary<Thread, ThreadEntry>();
221 //private event WorkItemsGroupIdleHandler _onIdle; 221
222 222 /// <summary>
223 /// <summary> 223 /// Queue of work items.
224 /// Holds all the WorkItemsGroup instaces that have at least one 224 /// </summary>
225 /// work item int the SmartThreadPool 225 private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue();
226 /// This variable is used in case of Shutdown 226
227 /// </summary> 227 /// <summary>
228 private Hashtable _workItemsGroups = Hashtable.Synchronized(new Hashtable()); 228 /// Count the work items handled.
229 229 /// Used by the performance counter.
230 /// <summary> 230 /// </summary>
231 /// A reference from each thread in the thread pool to its SmartThreadPool 231 private int _workItemsProcessed;
232 /// object container. 232
233 /// With this variable a thread can know whatever it belongs to a 233 /// <summary>
234 /// SmartThreadPool. 234 /// Number of threads that currently work (not idle).
235 /// </summary> 235 /// </summary>
236 [ThreadStatic] 236 private int _inUseWorkerThreads;
237 private static SmartThreadPool _smartThreadPool; 237
238 238 /// <summary>
239 /// <summary> 239 /// Stores a copy of the original STPStartInfo.
240 /// A reference to the current work item a thread from the thread pool 240 /// It is used to change the MinThread and MaxThreads
241 /// is executing. 241 /// </summary>
242 /// </summary> 242 private STPStartInfo _stpStartInfo;
243 [ThreadStatic] 243
244 private static WorkItem _currentWorkItem; 244 /// <summary>
245 245 /// Total number of work items that are stored in the work items queue
246 /// <summary> 246 /// plus the work items that the threads in the pool are working on.
247 /// STP performance counters 247 /// </summary>
248 /// </summary> 248 private int _currentWorkItemsCount;
249 private ISTPInstancePerformanceCounters _pcs = NullSTPInstancePerformanceCounters.Instance; 249
250 250 /// <summary>
251 #endregion 251 /// Signaled when the thread pool is idle, i.e. no thread is busy
252 252 /// and the work items queue is empty
253 #region Construction and Finalization 253 /// </summary>
254 254 //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
255 /// <summary> 255 private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
256 /// Constructor 256
257 /// </summary> 257 /// <summary>
258 public SmartThreadPool() 258 /// An event to signal all the threads to quit immediately.
259 { 259 /// </summary>
260 Initialize(); 260 //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false);
261 } 261 private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false);
262 262
263 /// <summary> 263 /// <summary>
264 /// Constructor 264 /// A flag to indicate if the Smart Thread Pool is now suspended.
265 /// </summary> 265 /// </summary>
266 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 266 private bool _isSuspended;
267 public SmartThreadPool(int idleTimeout) 267
268 { 268 /// <summary>
269 _stpStartInfo.IdleTimeout = idleTimeout; 269 /// A flag to indicate the threads to quit.
270 Initialize(); 270 /// </summary>
271 } 271 private bool _shutdown;
272 272
273 /// <summary> 273 /// <summary>
274 /// Constructor 274 /// Counts the threads created in the pool.
275 /// </summary> 275 /// It is used to name the threads.
276 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 276 /// </summary>
277 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> 277 private int _threadCounter;
278 public SmartThreadPool( 278
279 int idleTimeout, 279 /// <summary>
280 int maxWorkerThreads) 280 /// Indicate that the SmartThreadPool has been disposed
281 { 281 /// </summary>
282 _stpStartInfo.IdleTimeout = idleTimeout; 282 private bool _isDisposed;
283 _stpStartInfo.MaxWorkerThreads = maxWorkerThreads; 283
284 Initialize(); 284 /// <summary>
285 } 285 /// Holds all the WorkItemsGroup instaces that have at least one
286 286 /// work item int the SmartThreadPool
287 /// <summary> 287 /// This variable is used in case of Shutdown
288 /// Constructor 288 /// </summary>
289 /// </summary> 289 private readonly SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup> _workItemsGroups = new SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup>();
290 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 290
291 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> 291 /// <summary>
292 /// <param name="minWorkerThreads">Lower limit of threads in the pool</param> 292 /// A common object for all the work items int the STP
293 public SmartThreadPool( 293 /// so we can mark them to cancel in O(1)
294 int idleTimeout, 294 /// </summary>
295 int maxWorkerThreads, 295 private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup();
296 int minWorkerThreads) 296
297 { 297 /// <summary>
298 _stpStartInfo.IdleTimeout = idleTimeout; 298 /// Windows STP performance counters
299 _stpStartInfo.MaxWorkerThreads = maxWorkerThreads; 299 /// </summary>
300 _stpStartInfo.MinWorkerThreads = minWorkerThreads; 300 private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
301 Initialize(); 301
302 } 302 /// <summary>
303 303 /// Local STP performance counters
304 /// <summary> 304 /// </summary>
305 /// Constructor 305 private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance;
306 /// </summary> 306
307 public SmartThreadPool(STPStartInfo stpStartInfo) 307
308 { 308#if (WINDOWS_PHONE)
309 _stpStartInfo = new STPStartInfo(stpStartInfo); 309 private static readonly Dictionary<int, ThreadEntry> _threadEntries = new Dictionary<int, ThreadEntry>();
310 Initialize(); 310#elif (_WINDOWS_CE)
311 } 311 private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot();
312 312#else
313 private void Initialize() 313 [ThreadStatic]
314 { 314 private static ThreadEntry _threadEntry;
315 Name = _stpStartInfo.ThreadPoolName; 315
316 ValidateSTPStartInfo(); 316#endif
317 317
318 if (null != _stpStartInfo.PerformanceCounterInstanceName) 318 /// <summary>
319 { 319 /// An event to call after a thread is created, but before
320 try 320 /// it's first use.
321 { 321 /// </summary>
322 _pcs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); 322 private event ThreadInitializationHandler _onThreadInitialization;
323 } 323
324 catch(Exception e) 324 /// <summary>
325 { 325 /// An event to call when a thread is about to exit, after
326 Debug.WriteLine("Unable to create Performance Counters: " + e.ToString()); 326 /// it is no longer belong to the pool.
327 _pcs = NullSTPInstancePerformanceCounters.Instance; 327 /// </summary>
328 } 328 private event ThreadTerminationHandler _onThreadTermination;
329 } 329
330 330 #endregion
331 StartOptimalNumberOfThreads(); 331
332 } 332 #region Per thread properties
333 333
334 private void StartOptimalNumberOfThreads() 334 /// <summary>
335 { 335 /// A reference to the current work item a thread from the thread pool
336 int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); 336 /// is executing.
337 threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); 337 /// </summary>
338 StartThreads(threadsCount); 338 internal static ThreadEntry CurrentThreadEntry
339 } 339 {
340 340#if (WINDOWS_PHONE)
341 private void ValidateSTPStartInfo() 341 get
342 { 342 {
343 if (_stpStartInfo.MinWorkerThreads < 0) 343 lock(_threadEntries)
344 { 344 {
345 throw new ArgumentOutOfRangeException( 345 ThreadEntry threadEntry;
346 "MinWorkerThreads", "MinWorkerThreads cannot be negative"); 346 if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry))
347 } 347 {
348 348 return threadEntry;
349 if (_stpStartInfo.MaxWorkerThreads <= 0) 349 }
350 { 350 }
351 throw new ArgumentOutOfRangeException( 351 return null;
352 "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); 352 }
353 } 353 set
354 354 {
355 if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) 355 lock(_threadEntries)
356 { 356 {
357 throw new ArgumentOutOfRangeException( 357 _threadEntries[Thread.CurrentThread.ManagedThreadId] = value;
358 "MinWorkerThreads, maxWorkerThreads", 358 }
359 "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); 359 }
360 } 360#elif (_WINDOWS_CE)
361 } 361 get
362 362 {
363 private void ValidateCallback(Delegate callback) 363 //Thread.CurrentThread.ManagedThreadId
364 { 364 return Thread.GetData(_threadEntrySlot) as ThreadEntry;
365 if(callback.GetInvocationList().Length > 1) 365 }
366 { 366 set
367 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); 367 {
368 } 368 Thread.SetData(_threadEntrySlot, value);
369 } 369 }
370 370#else
371 #endregion 371 get
372 372 {
373 #region Thread Processing 373 return _threadEntry;
374 374 }
375 /// <summary> 375 set
376 /// Waits on the queue for a work item, shutdown, or timeout. 376 {
377 /// </summary> 377 _threadEntry = value;
378 /// <returns> 378 }
379 /// Returns the WaitingCallback or null in case of timeout or shutdown. 379#endif
380 /// </returns> 380 }
381 private WorkItem Dequeue() 381 #endregion
382 { 382
383 WorkItem workItem = 383 #region Construction and Finalization
384 _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); 384
385 385 /// <summary>
386 return workItem; 386 /// Constructor
387 } 387 /// </summary>
388 388 public SmartThreadPool()
389 /// <summary> 389 {
390 /// Put a new work item in the queue 390 _stpStartInfo = new STPStartInfo();
391 /// </summary> 391 Initialize();
392 /// <param name="workItem">A work item to queue</param> 392 }
393 private void Enqueue(WorkItem workItem) 393
394 { 394 /// <summary>
395 Enqueue(workItem, true); 395 /// Constructor
396 } 396 /// </summary>
397 397 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
398 /// <summary> 398 public SmartThreadPool(int idleTimeout)
399 /// Put a new work item in the queue 399 {
400 /// </summary> 400 _stpStartInfo = new STPStartInfo
401 /// <param name="workItem">A work item to queue</param> 401 {
402 internal void Enqueue(WorkItem workItem, bool incrementWorkItems) 402 IdleTimeout = idleTimeout,
403 { 403 };
404 // Make sure the workItem is not null 404 Initialize();
405 Debug.Assert(null != workItem); 405 }
406 406
407 if (incrementWorkItems) 407 /// <summary>
408 { 408 /// Constructor
409 IncrementWorkItemsCount(); 409 /// </summary>
410 } 410 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
411 411 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
412 _workItemsQueue.EnqueueWorkItem(workItem); 412 public SmartThreadPool(
413 workItem.WorkItemIsQueued(); 413 int idleTimeout,
414 414 int maxWorkerThreads)
415 // If all the threads are busy then try to create a new one 415 {
416 if ((InUseThreads + WaitingCallbacks) > _workerThreads.Count) 416 _stpStartInfo = new STPStartInfo
417 { 417 {
418 StartThreads(1); 418 IdleTimeout = idleTimeout,
419 } 419 MaxWorkerThreads = maxWorkerThreads,
420 } 420 };
421 421 Initialize();
422 private void IncrementWorkItemsCount() 422 }
423 { 423
424 _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); 424 /// <summary>
425 425 /// Constructor
426 int count = Interlocked.Increment(ref _currentWorkItemsCount); 426 /// </summary>
427 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); 427 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
428 if (count == 1) 428 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
429 { 429 /// <param name="minWorkerThreads">Lower limit of threads in the pool</param>
430 //Trace.WriteLine("STP is NOT idle"); 430 public SmartThreadPool(
431 _isIdleWaitHandle.Reset(); 431 int idleTimeout,
432 } 432 int maxWorkerThreads,
433 } 433 int minWorkerThreads)
434 434 {
435 private void DecrementWorkItemsCount() 435 _stpStartInfo = new STPStartInfo
436 { 436 {
437 ++_workItemsProcessed; 437 IdleTimeout = idleTimeout,
438 438 MaxWorkerThreads = maxWorkerThreads,
439 // The counter counts even if the work item was cancelled 439 MinWorkerThreads = minWorkerThreads,
440 _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); 440 };
441 441 Initialize();
442 int count = Interlocked.Decrement(ref _currentWorkItemsCount); 442 }
443 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); 443
444 if (count == 0) 444 /// <summary>
445 { 445 /// Constructor
446 //Trace.WriteLine("STP is idle"); 446 /// </summary>
447 _isIdleWaitHandle.Set(); 447 /// <param name="stpStartInfo">A SmartThreadPool configuration that overrides the default behavior</param>
448 } 448 public SmartThreadPool(STPStartInfo stpStartInfo)
449 } 449 {
450 450 _stpStartInfo = new STPStartInfo(stpStartInfo);
451 internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) 451 Initialize();
452 { 452 }
453 _workItemsGroups[workItemsGroup] = workItemsGroup; 453
454 } 454 private void Initialize()
455 455 {
456 internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) 456 Name = _stpStartInfo.ThreadPoolName;
457 { 457 ValidateSTPStartInfo();
458 if (_workItemsGroups.Contains(workItemsGroup)) 458
459 { 459 // _stpStartInfoRW stores a read/write copy of the STPStartInfo.
460 _workItemsGroups.Remove(workItemsGroup); 460 // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten
461 } 461
462 } 462 _isSuspended = _stpStartInfo.StartSuspended;
463 463
464 /// <summary> 464#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE)
465 /// Inform that the current thread is about to quit or quiting. 465 if (null != _stpStartInfo.PerformanceCounterInstanceName)
466 /// The same thread may call this method more than once. 466 {
467 /// </summary> 467 throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters");
468 private void InformCompleted() 468 }
469 { 469#else
470 // There is no need to lock the two methods together 470 if (null != _stpStartInfo.PerformanceCounterInstanceName)
471 // since only the current thread removes itself 471 {
472 // and the _workerThreads is a synchronized hashtable 472 try
473 if (_workerThreads.Contains(Thread.CurrentThread)) 473 {
474 { 474 _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName);
475 _workerThreads.Remove(Thread.CurrentThread); 475 }
476 _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 476 catch (Exception e)
477 } 477 {
478 } 478 Debug.WriteLine("Unable to create Performance Counters: " + e);
479 479 _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
480 /// <summary> 480 }
481 /// Starts new threads 481 }
482 /// </summary> 482#endif
483 /// <param name="threadsCount">The number of threads to start</param> 483
484 private void StartThreads(int threadsCount) 484 if (_stpStartInfo.EnableLocalPerformanceCounters)
485 { 485 {
486 if (_stpStartInfo.StartSuspended) 486 _localPCs = new LocalSTPInstancePerformanceCounters();
487 { 487 }
488 return; 488
489 } 489 // If the STP is not started suspended then start the threads.
490 490 if (!_isSuspended)
491 lock(_workerThreads.SyncRoot) 491 {
492 { 492 StartOptimalNumberOfThreads();
493 // Don't start threads on shut down 493 }
494 if (_shutdown) 494 }
495 { 495
496 return; 496 private void StartOptimalNumberOfThreads()
497 } 497 {
498 498 int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads);
499 for(int i = 0; i < threadsCount; ++i) 499 threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads);
500 { 500 threadsCount -= _workerThreads.Count;
501 // Don't create more threads then the upper limit 501 if (threadsCount > 0)
502 if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) 502 {
503 { 503 StartThreads(threadsCount);
504 return; 504 }
505 } 505 }
506 506
507 // Create a new thread 507 private void ValidateSTPStartInfo()
508 Thread workerThread; 508 {
509 if (_stpStartInfo.StackSize > 0) 509 if (_stpStartInfo.MinWorkerThreads < 0)
510 workerThread = new Thread(ProcessQueuedItems, _stpStartInfo.StackSize); 510 {
511 else 511 throw new ArgumentOutOfRangeException(
512 workerThread = new Thread(ProcessQueuedItems); 512 "MinWorkerThreads", "MinWorkerThreads cannot be negative");
513 513 }
514 // Configure the new thread and start it 514
515 workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; 515 if (_stpStartInfo.MaxWorkerThreads <= 0)
516 workerThread.IsBackground = true; 516 {
517 workerThread.Priority = _stpStartInfo.ThreadPriority; 517 throw new ArgumentOutOfRangeException(
518 workerThread.Start(); 518 "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero");
519 ++_threadCounter; 519 }
520 520
521 // Add the new thread to the hashtable and update its creation 521 if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads)
522 // time. 522 {
523 _workerThreads[workerThread] = DateTime.Now; 523 throw new ArgumentOutOfRangeException(
524 _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 524 "MinWorkerThreads, maxWorkerThreads",
525 } 525 "MaxWorkerThreads must be greater or equal to MinWorkerThreads");
526 } 526 }
527 } 527 }
528 528
529 /// <summary> 529 private static void ValidateCallback(Delegate callback)
530 /// A worker thread method that processes work items from the work items queue. 530 {
531 /// </summary> 531 if(callback.GetInvocationList().Length > 1)
532 private void ProcessQueuedItems() 532 {
533 { 533 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
534 // Initialize the _smartThreadPool variable 534 }
535 _smartThreadPool = this; 535 }
536 536
537 try 537 #endregion
538 { 538
539 bool bInUseWorkerThreadsWasIncremented = false; 539 #region Thread Processing
540 540
541 // Process until shutdown. 541 /// <summary>
542 while(!_shutdown) 542 /// Waits on the queue for a work item, shutdown, or timeout.
543 { 543 /// </summary>
544 // Update the last time this thread was seen alive. 544 /// <returns>
545 // It's good for debugging. 545 /// Returns the WaitingCallback or null in case of timeout or shutdown.
546 _workerThreads[Thread.CurrentThread] = DateTime.Now; 546 /// </returns>
547 547 private WorkItem Dequeue()
548 // Wait for a work item, shutdown, or timeout 548 {
549 WorkItem workItem = Dequeue(); 549 WorkItem workItem =
550 550 _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent);
551 // Update the last time this thread was seen alive. 551
552 // It's good for debugging. 552 return workItem;
553 _workerThreads[Thread.CurrentThread] = DateTime.Now; 553 }
554 554
555 // On timeout or shut down. 555 /// <summary>
556 if (null == workItem) 556 /// Put a new work item in the queue
557 { 557 /// </summary>
558 // Double lock for quit. 558 /// <param name="workItem">A work item to queue</param>
559 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) 559 internal override void Enqueue(WorkItem workItem)
560 { 560 {
561 lock(_workerThreads.SyncRoot) 561 // Make sure the workItem is not null
562 { 562 Debug.Assert(null != workItem);
563 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) 563
564 { 564 IncrementWorkItemsCount();
565 // Inform that the thread is quiting and then quit. 565
566 // This method must be called within this lock or else 566 workItem.CanceledSmartThreadPool = _canceledSmartThreadPool;
567 // more threads will quit and the thread pool will go 567 _workItemsQueue.EnqueueWorkItem(workItem);
568 // below the lower limit. 568 workItem.WorkItemIsQueued();
569 InformCompleted(); 569
570 break; 570 // If all the threads are busy then try to create a new one
571 } 571 if (_currentWorkItemsCount > _workerThreads.Count)
572 } 572 {
573 } 573 StartThreads(1);
574 } 574 }
575 575 }
576 // If we didn't quit then skip to the next iteration. 576
577 if (null == workItem) 577 private void IncrementWorkItemsCount()
578 { 578 {
579 continue; 579 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
580 } 580 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
581 581
582 try 582 int count = Interlocked.Increment(ref _currentWorkItemsCount);
583 { 583 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
584 // Initialize the value to false 584 if (count == 1)
585 bInUseWorkerThreadsWasIncremented = false; 585 {
586 586 IsIdle = false;
587 // Change the state of the work item to 'in progress' if possible. 587 _isIdleWaitHandle.Reset();
588 // We do it here so if the work item has been canceled we won't 588 }
589 // increment the _inUseWorkerThreads. 589 }
590 // The cancel mechanism doesn't delete items from the queue, 590
591 // it marks the work item as canceled, and when the work item 591 private void DecrementWorkItemsCount()
592 // is dequeued, we just skip it. 592 {
593 // If the post execute of work item is set to always or to 593 int count = Interlocked.Decrement(ref _currentWorkItemsCount);
594 // call when the work item is canceled then the StartingWorkItem() 594 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
595 // will return true, so the post execute can run. 595 if (count == 0)
596 if (!workItem.StartingWorkItem()) 596 {
597 { 597 IsIdle = true;
598 continue; 598 _isIdleWaitHandle.Set();
599 } 599 }
600 600
601 // Execute the callback. Make sure to accurately 601 Interlocked.Increment(ref _workItemsProcessed);
602 // record how many callbacks are currently executing. 602
603 int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); 603 if (!_shutdown)
604 _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 604 {
605 605 // The counter counts even if the work item was cancelled
606 // Mark that the _inUseWorkerThreads incremented, so in the finally{} 606 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
607 // statement we will decrement it correctly. 607 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
608 bInUseWorkerThreadsWasIncremented = true; 608 }
609 609
610 // Set the _currentWorkItem to the current work item 610 }
611 _currentWorkItem = workItem; 611
612 612 internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
613 lock(workItem) 613 {
614 { 614 _workItemsGroups[workItemsGroup] = workItemsGroup;
615 workItem.currentThread = Thread.CurrentThread; 615 }
616 } 616
617 617 internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
618 ExecuteWorkItem(workItem); 618 {
619 619 if (_workItemsGroups.Contains(workItemsGroup))
620 lock(workItem) 620 {
621 { 621 _workItemsGroups.Remove(workItemsGroup);
622 workItem.currentThread = null; 622 }
623 } 623 }
624 624
625 } 625 /// <summary>
626 catch(ThreadAbortException ex) 626 /// Inform that the current thread is about to quit or quiting.
627 { 627 /// The same thread may call this method more than once.
628 lock(workItem) 628 /// </summary>
629 { 629 private void InformCompleted()
630 workItem.currentThread = null; 630 {
631 } 631 // There is no need to lock the two methods together
632 ex.GetHashCode(); 632 // since only the current thread removes itself
633 Thread.ResetAbort(); 633 // and the _workerThreads is a synchronized dictionary
634 } 634 if (_workerThreads.Contains(Thread.CurrentThread))
635 catch(Exception ex) 635 {
636 { 636 _workerThreads.Remove(Thread.CurrentThread);
637 ex.GetHashCode(); 637 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
638 // Do nothing 638 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
639 } 639 }
640 finally 640 }
641 { 641
642 lock(workItem) 642 /// <summary>
643 { 643 /// Starts new threads
644 workItem.currentThread = null; 644 /// </summary>
645 } 645 /// <param name="threadsCount">The number of threads to start</param>
646 646 private void StartThreads(int threadsCount)
647 if (null != workItem) 647 {
648 { 648 if (_isSuspended)
649 workItem.DisposeOfState(); 649 {
650 } 650 return;
651 651 }
652 // Set the _currentWorkItem to null, since we 652
653 // no longer run user's code. 653 lock(_workerThreads.SyncRoot)
654 _currentWorkItem = null; 654 {
655 655 // Don't start threads on shut down
656 // Decrement the _inUseWorkerThreads only if we had 656 if (_shutdown)
657 // incremented it. Note the cancelled work items don't 657 {
658 // increment _inUseWorkerThreads. 658 return;
659 if (bInUseWorkerThreadsWasIncremented) 659 }
660 { 660
661 int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); 661 for(int i = 0; i < threadsCount; ++i)
662 _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 662 {
663 } 663 // Don't create more threads then the upper limit
664 664 if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads)
665 // Notify that the work item has been completed. 665 {
666 // WorkItemsGroup may enqueue their next work item. 666 return;
667 workItem.FireWorkItemCompleted(); 667 }
668 668
669 // Decrement the number of work items here so the idle 669 // Create a new thread
670 // ManualResetEvent won't fluctuate. 670
671 DecrementWorkItemsCount(); 671#if (_SILVERLIGHT) || (WINDOWS_PHONE)
672 } 672 Thread workerThread = new Thread(ProcessQueuedItems);
673 } 673#else
674 } 674 Thread workerThread =
675 catch(ThreadAbortException tae) 675 _stpStartInfo.MaxStackSize.HasValue
676 { 676 ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value)
677 tae.GetHashCode(); 677 : new Thread(ProcessQueuedItems);
678 // Handle the abort exception gracfully. 678#endif
679 Thread.ResetAbort(); 679 // Configure the new thread and start it
680 } 680 workerThread.Name = "STP " + Name + " Thread #" + _threadCounter;
681 catch(Exception e) 681 workerThread.IsBackground = _stpStartInfo.AreThreadsBackground;
682 { 682
683 Debug.Assert(null != e); 683#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE)
684 } 684 if (_stpStartInfo.ApartmentState != ApartmentState.Unknown)
685 finally 685 {
686 { 686 workerThread.SetApartmentState(_stpStartInfo.ApartmentState);
687 InformCompleted(); 687 }
688 } 688#endif
689 } 689
690 690#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
691 private void ExecuteWorkItem(WorkItem workItem) 691 workerThread.Priority = _stpStartInfo.ThreadPriority;
692 { 692#endif
693 _pcs.SampleWorkItemsWaitTime(workItem.WaitingTime); 693 workerThread.Start();
694 try 694 ++_threadCounter;
695 { 695
696 workItem.Execute(); 696 // Add it to the dictionary and update its creation time.
697 } 697 _workerThreads[workerThread] = new ThreadEntry(this);
698 catch 698
699 { 699 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
700 throw; 700 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
701 } 701 }
702 finally 702 }
703 { 703 }
704 _pcs.SampleWorkItemsProcessTime(workItem.ProcessTime); 704
705 } 705 /// <summary>
706 } 706 /// A worker thread method that processes work items from the work items queue.
707 707 /// </summary>
708 708 private void ProcessQueuedItems()
709 #endregion 709 {
710 710 // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks
711 #region Public Methods 711 // of the dictionary.
712 712 CurrentThreadEntry = _workerThreads[Thread.CurrentThread];
713 /// <summary> 713
714 /// Queue a work item 714 FireOnThreadInitialization();
715 /// </summary> 715
716 /// <param name="callback">A callback to execute</param> 716 try
717 /// <returns>Returns a work item result</returns> 717 {
718 public IWorkItemResult QueueWorkItem(WorkItemCallback callback) 718 bool bInUseWorkerThreadsWasIncremented = false;
719 { 719
720 ValidateNotDisposed(); 720 // Process until shutdown.
721 ValidateCallback(callback); 721 while(!_shutdown)
722 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback); 722 {
723 Enqueue(workItem); 723 // Update the last time this thread was seen alive.
724 return workItem.GetWorkItemResult(); 724 // It's good for debugging.
725 } 725 CurrentThreadEntry.IAmAlive();
726 726
727 /// <summary> 727 // The following block handles the when the MaxWorkerThreads has been
728 /// Queue a work item 728 // incremented by the user at run-time.
729 /// </summary> 729 // Double lock for quit.
730 /// <param name="callback">A callback to execute</param> 730 if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads)
731 /// <param name="workItemPriority">The priority of the work item</param> 731 {
732 /// <returns>Returns a work item result</returns> 732 lock (_workerThreads.SyncRoot)
733 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) 733 {
734 { 734 if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads)
735 ValidateNotDisposed(); 735 {
736 ValidateCallback(callback); 736 // Inform that the thread is quiting and then quit.
737 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, workItemPriority); 737 // This method must be called within this lock or else
738 Enqueue(workItem); 738 // more threads will quit and the thread pool will go
739 return workItem.GetWorkItemResult(); 739 // below the lower limit.
740 } 740 InformCompleted();
741 741 break;
742 /// <summary> 742 }
743 /// Queue a work item 743 }
744 /// </summary> 744 }
745 /// <param name="workItemInfo">Work item info</param> 745
746 /// <param name="callback">A callback to execute</param> 746 // Wait for a work item, shutdown, or timeout
747 /// <returns>Returns a work item result</returns> 747 WorkItem workItem = Dequeue();
748 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) 748
749 { 749 // Update the last time this thread was seen alive.
750 ValidateNotDisposed(); 750 // It's good for debugging.
751 ValidateCallback(callback); 751 CurrentThreadEntry.IAmAlive();
752 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback); 752
753 Enqueue(workItem); 753 // On timeout or shut down.
754 return workItem.GetWorkItemResult(); 754 if (null == workItem)
755 } 755 {
756 756 // Double lock for quit.
757 /// <summary> 757 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
758 /// Queue a work item 758 {
759 /// </summary> 759 lock(_workerThreads.SyncRoot)
760 /// <param name="callback">A callback to execute</param> 760 {
761 /// <param name="state"> 761 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
762 /// The context object of the work item. Used for passing arguments to the work item. 762 {
763 /// </param> 763 // Inform that the thread is quiting and then quit.
764 /// <returns>Returns a work item result</returns> 764 // This method must be called within this lock or else
765 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) 765 // more threads will quit and the thread pool will go
766 { 766 // below the lower limit.
767 ValidateNotDisposed(); 767 InformCompleted();
768 ValidateCallback(callback); 768 break;
769 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state); 769 }
770 Enqueue(workItem); 770 }
771 return workItem.GetWorkItemResult(); 771 }
772 } 772 }
773 773
774 /// <summary> 774 // If we didn't quit then skip to the next iteration.
775 /// Queue a work item 775 if (null == workItem)
776 /// </summary> 776 {
777 /// <param name="callback">A callback to execute</param> 777 continue;
778 /// <param name="state"> 778 }
779 /// The context object of the work item. Used for passing arguments to the work item. 779
780 /// </param> 780 try
781 /// <param name="workItemPriority">The work item priority</param> 781 {
782 /// <returns>Returns a work item result</returns> 782 // Initialize the value to false
783 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) 783 bInUseWorkerThreadsWasIncremented = false;
784 { 784
785 ValidateNotDisposed(); 785 // Set the Current Work Item of the thread.
786 ValidateCallback(callback); 786 // Store the Current Work Item before the workItem.StartingWorkItem() is called,
787 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, workItemPriority); 787 // so WorkItem.Cancel can work when the work item is between InQueue and InProgress
788 Enqueue(workItem); 788 // states.
789 return workItem.GetWorkItemResult(); 789 // If the work item has been cancelled BEFORE the workItem.StartingWorkItem()
790 } 790 // (work item is in InQueue state) then workItem.StartingWorkItem() will return false.
791 791 // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then
792 /// <summary> 792 // (work item is in InProgress state) then the thread will be aborted
793 /// Queue a work item 793 CurrentThreadEntry.CurrentWorkItem = workItem;
794 /// </summary> 794
795 /// <param name="workItemInfo">Work item information</param> 795 // Change the state of the work item to 'in progress' if possible.
796 /// <param name="callback">A callback to execute</param> 796 // We do it here so if the work item has been canceled we won't
797 /// <param name="state"> 797 // increment the _inUseWorkerThreads.
798 /// The context object of the work item. Used for passing arguments to the work item. 798 // The cancel mechanism doesn't delete items from the queue,
799 /// </param> 799 // it marks the work item as canceled, and when the work item
800 /// <returns>Returns a work item result</returns> 800 // is dequeued, we just skip it.
801 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) 801 // If the post execute of work item is set to always or to
802 { 802 // call when the work item is canceled then the StartingWorkItem()
803 ValidateNotDisposed(); 803 // will return true, so the post execute can run.
804 ValidateCallback(callback); 804 if (!workItem.StartingWorkItem())
805 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback, state); 805 {
806 Enqueue(workItem); 806 continue;
807 return workItem.GetWorkItemResult(); 807 }
808 } 808
809 809 // Execute the callback. Make sure to accurately
810 /// <summary> 810 // record how many callbacks are currently executing.
811 /// Queue a work item 811 int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads);
812 /// </summary> 812 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
813 /// <param name="callback">A callback to execute</param> 813 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
814 /// <param name="state"> 814
815 /// The context object of the work item. Used for passing arguments to the work item. 815 // Mark that the _inUseWorkerThreads incremented, so in the finally{}
816 /// </param> 816 // statement we will decrement it correctly.
817 /// <param name="postExecuteWorkItemCallback"> 817 bInUseWorkerThreadsWasIncremented = true;
818 /// A delegate to call after the callback completion 818
819 /// </param> 819 workItem.FireWorkItemStarted();
820 /// <returns>Returns a work item result</returns> 820
821 public IWorkItemResult QueueWorkItem( 821 ExecuteWorkItem(workItem);
822 WorkItemCallback callback, 822 }
823 object state, 823 catch(Exception ex)
824 PostExecuteWorkItemCallback postExecuteWorkItemCallback) 824 {
825 { 825 ex.GetHashCode();
826 ValidateNotDisposed(); 826 // Do nothing
827 ValidateCallback(callback); 827 }
828 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback); 828 finally
829 Enqueue(workItem); 829 {
830 return workItem.GetWorkItemResult(); 830 workItem.DisposeOfState();
831 } 831
832 832 // Set the CurrentWorkItem to null, since we
833 /// <summary> 833 // no longer run user's code.
834 /// Queue a work item 834 CurrentThreadEntry.CurrentWorkItem = null;
835 /// </summary> 835
836 /// <param name="callback">A callback to execute</param> 836 // Decrement the _inUseWorkerThreads only if we had
837 /// <param name="state"> 837 // incremented it. Note the cancelled work items don't
838 /// The context object of the work item. Used for passing arguments to the work item. 838 // increment _inUseWorkerThreads.
839 /// </param> 839 if (bInUseWorkerThreadsWasIncremented)
840 /// <param name="postExecuteWorkItemCallback"> 840 {
841 /// A delegate to call after the callback completion 841 int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads);
842 /// </param> 842 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
843 /// <param name="workItemPriority">The work item priority</param> 843 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
844 /// <returns>Returns a work item result</returns> 844 }
845 public IWorkItemResult QueueWorkItem( 845
846 WorkItemCallback callback, 846 // Notify that the work item has been completed.
847 object state, 847 // WorkItemsGroup may enqueue their next work item.
848 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 848 workItem.FireWorkItemCompleted();
849 WorkItemPriority workItemPriority) 849
850 { 850 // Decrement the number of work items here so the idle
851 ValidateNotDisposed(); 851 // ManualResetEvent won't fluctuate.
852 ValidateCallback(callback); 852 DecrementWorkItemsCount();
853 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); 853 }
854 Enqueue(workItem); 854 }
855 return workItem.GetWorkItemResult(); 855 }
856 } 856 catch(ThreadAbortException tae)
857 857 {
858 /// <summary> 858 tae.GetHashCode();
859 /// Queue a work item 859 // Handle the abort exception gracfully.
860 /// </summary> 860#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
861 /// <param name="callback">A callback to execute</param> 861 Thread.ResetAbort();
862 /// <param name="state"> 862#endif
863 /// The context object of the work item. Used for passing arguments to the work item. 863 }
864 /// </param> 864 catch(Exception e)
865 /// <param name="postExecuteWorkItemCallback"> 865 {
866 /// A delegate to call after the callback completion 866 Debug.Assert(null != e);
867 /// </param> 867 }
868 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 868 finally
869 /// <returns>Returns a work item result</returns> 869 {
870 public IWorkItemResult QueueWorkItem( 870 InformCompleted();
871 WorkItemCallback callback, 871 FireOnThreadTermination();
872 object state, 872 }
873 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 873 }
874 CallToPostExecute callToPostExecute) 874
875 { 875 private void ExecuteWorkItem(WorkItem workItem)
876 ValidateNotDisposed(); 876 {
877 ValidateCallback(callback); 877 _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime);
878 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); 878 _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime);
879 Enqueue(workItem); 879 try
880 return workItem.GetWorkItemResult(); 880 {
881 } 881 workItem.Execute();
882 882 }
883 /// <summary> 883 finally
884 /// Queue a work item 884 {
885 /// </summary> 885 _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime);
886 /// <param name="callback">A callback to execute</param> 886 _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime);
887 /// <param name="state"> 887 }
888 /// The context object of the work item. Used for passing arguments to the work item. 888 }
889 /// </param> 889
890 /// <param name="postExecuteWorkItemCallback"> 890
891 /// A delegate to call after the callback completion 891 #endregion
892 /// </param> 892
893 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 893 #region Public Methods
894 /// <param name="workItemPriority">The work item priority</param> 894
895 /// <returns>Returns a work item result</returns> 895 private void ValidateWaitForIdle()
896 public IWorkItemResult QueueWorkItem( 896 {
897 WorkItemCallback callback, 897 if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this)
898 object state, 898 {
899 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 899 throw new NotSupportedException(
900 CallToPostExecute callToPostExecute, 900 "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
901 WorkItemPriority workItemPriority) 901 }
902 { 902 }
903 ValidateNotDisposed(); 903
904 ValidateCallback(callback); 904 internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup)
905 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); 905 {
906 Enqueue(workItem); 906 if (null == CurrentThreadEntry)
907 return workItem.GetWorkItemResult(); 907 {
908 } 908 return;
909 909 }
910 /// <summary> 910
911 /// Wait for the thread pool to be idle 911 WorkItem workItem = CurrentThreadEntry.CurrentWorkItem;
912 /// </summary> 912 ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem);
913 public void WaitForIdle() 913 if ((null != workItemsGroup) &&
914 { 914 (null != workItem) &&
915 WaitForIdle(Timeout.Infinite); 915 CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup))
916 } 916 {
917 917 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
918 /// <summary> 918 }
919 /// Wait for the thread pool to be idle 919 }
920 /// </summary> 920
921 public bool WaitForIdle(TimeSpan timeout) 921 [MethodImpl(MethodImplOptions.NoInlining)]
922 { 922 private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem)
923 return WaitForIdle((int)timeout.TotalMilliseconds); 923 {
924 } 924 if ((null != workItemsGroup) &&
925 925 (null != workItem) &&
926 /// <summary> 926 workItem.WasQueuedBy(workItemsGroup))
927 /// Wait for the thread pool to be idle 927 {
928 /// </summary> 928 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
929 public bool WaitForIdle(int millisecondsTimeout) 929 }
930 { 930 }
931 ValidateWaitForIdle(); 931
932 return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false); 932 /// <summary>
933 } 933 /// Force the SmartThreadPool to shutdown
934 934 /// </summary>
935 private void ValidateWaitForIdle() 935 public void Shutdown()
936 { 936 {
937 if(_smartThreadPool == this) 937 Shutdown(true, 0);
938 { 938 }
939 throw new NotSupportedException( 939
940 "WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); 940 /// <summary>
941 } 941 /// Force the SmartThreadPool to shutdown with timeout
942 } 942 /// </summary>
943 943 public void Shutdown(bool forceAbort, TimeSpan timeout)
944 internal void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) 944 {
945 { 945 Shutdown(forceAbort, (int)timeout.TotalMilliseconds);
946 ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, SmartThreadPool._currentWorkItem); 946 }
947 if ((null != workItemsGroup) && 947
948 (null != SmartThreadPool._currentWorkItem) && 948 /// <summary>
949 SmartThreadPool._currentWorkItem.WasQueuedBy(workItemsGroup)) 949 /// Empties the queue of work items and abort the threads in the pool.
950 { 950 /// </summary>
951 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); 951 public void Shutdown(bool forceAbort, int millisecondsTimeout)
952 } 952 {
953 } 953 ValidateNotDisposed();
954 954
955 [MethodImpl(MethodImplOptions.NoInlining)] 955 ISTPInstancePerformanceCounters pcs = _windowsPCs;
956 private void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) 956
957 { 957 if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs)
958 if ((null != workItemsGroup) && 958 {
959 (null != workItem) && 959 // Set the _pcs to "null" to stop updating the performance
960 workItem.WasQueuedBy(workItemsGroup)) 960 // counters
961 { 961 _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
962 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); 962
963 } 963 pcs.Dispose();
964 } 964 }
965 965
966 966 Thread [] threads;
967 967 lock(_workerThreads.SyncRoot)
968 /// <summary> 968 {
969 /// Force the SmartThreadPool to shutdown 969 // Shutdown the work items queue
970 /// </summary> 970 _workItemsQueue.Dispose();
971 public void Shutdown() 971
972 { 972 // Signal the threads to exit
973 Shutdown(true, 0); 973 _shutdown = true;
974 } 974 _shuttingDownEvent.Set();
975 975
976 public void Shutdown(bool forceAbort, TimeSpan timeout) 976 // Make a copy of the threads' references in the pool
977 { 977 threads = new Thread [_workerThreads.Count];
978 Shutdown(forceAbort, (int)timeout.TotalMilliseconds); 978 _workerThreads.Keys.CopyTo(threads, 0);
979 } 979 }
980 980
981 /// <summary> 981 int millisecondsLeft = millisecondsTimeout;
982 /// Empties the queue of work items and abort the threads in the pool. 982 Stopwatch stopwatch = Stopwatch.StartNew();
983 /// </summary> 983 //DateTime start = DateTime.UtcNow;
984 public void Shutdown(bool forceAbort, int millisecondsTimeout) 984 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
985 { 985 bool timeout = false;
986 ValidateNotDisposed(); 986
987 987 // Each iteration we update the time left for the timeout.
988 ISTPInstancePerformanceCounters pcs = _pcs; 988 foreach(Thread thread in threads)
989 989 {
990 if (NullSTPInstancePerformanceCounters.Instance != _pcs) 990 // Join don't work with negative numbers
991 { 991 if (!waitInfinitely && (millisecondsLeft < 0))
992 _pcs.Dispose(); 992 {
993 // Set the _pcs to "null" to stop updating the performance 993 timeout = true;
994 // counters 994 break;
995 _pcs = NullSTPInstancePerformanceCounters.Instance; 995 }
996 } 996
997 997 // Wait for the thread to terminate
998 Thread [] threads = null; 998 bool success = thread.Join(millisecondsLeft);
999 lock(_workerThreads.SyncRoot) 999 if(!success)
1000 { 1000 {
1001 // Shutdown the work items queue 1001 timeout = true;
1002 _workItemsQueue.Dispose(); 1002 break;
1003 1003 }
1004 // Signal the threads to exit 1004
1005 _shutdown = true; 1005 if(!waitInfinitely)
1006 _shuttingDownEvent.Set(); 1006 {
1007 1007 // Update the time left to wait
1008 // Make a copy of the threads' references in the pool 1008 //TimeSpan ts = DateTime.UtcNow - start;
1009 threads = new Thread [_workerThreads.Count]; 1009 millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
1010 _workerThreads.Keys.CopyTo(threads, 0); 1010 }
1011 } 1011 }
1012 1012
1013 int millisecondsLeft = millisecondsTimeout; 1013 if (timeout && forceAbort)
1014 DateTime start = DateTime.Now; 1014 {
1015 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); 1015 // Abort the threads in the pool
1016 bool timeout = false; 1016 foreach(Thread thread in threads)
1017 1017 {
1018 // Each iteration we update the time left for the timeout. 1018
1019 foreach(Thread thread in threads) 1019 if ((thread != null)
1020 { 1020#if !(_WINDOWS_CE)
1021 // Join don't work with negative numbers 1021 && thread.IsAlive
1022 if (!waitInfinitely && (millisecondsLeft < 0)) 1022#endif
1023 { 1023 )
1024 timeout = true; 1024 {
1025 break; 1025 try
1026 } 1026 {
1027 1027 thread.Abort(); // Shutdown
1028 // Wait for the thread to terminate 1028 }
1029 bool success = thread.Join(millisecondsLeft); 1029 catch(SecurityException e)
1030 if(!success) 1030 {
1031 { 1031 e.GetHashCode();
1032 timeout = true; 1032 }
1033 break; 1033 catch(ThreadStateException ex)
1034 } 1034 {
1035 1035 ex.GetHashCode();
1036 if(!waitInfinitely) 1036 // In case the thread has been terminated
1037 { 1037 // after the check if it is alive.
1038 // Update the time left to wait 1038 }
1039 TimeSpan ts = DateTime.Now - start; 1039 }
1040 millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds; 1040 }
1041 } 1041 }
1042 } 1042 }
1043 1043
1044 if (timeout && forceAbort) 1044 /// <summary>
1045 { 1045 /// Wait for all work items to complete
1046 // Abort the threads in the pool 1046 /// </summary>
1047 foreach(Thread thread in threads) 1047 /// <param name="waitableResults">Array of work item result objects</param>
1048 { 1048 /// <returns>
1049 if ((thread != null) && thread.IsAlive) 1049 /// true when every work item in workItemResults has completed; otherwise false.
1050 { 1050 /// </returns>
1051 try 1051 public static bool WaitAll(
1052 { 1052 IWaitableResult [] waitableResults)
1053 thread.Abort("Shutdown"); 1053 {
1054 } 1054 return WaitAll(waitableResults, Timeout.Infinite, true);
1055 catch(SecurityException e) 1055 }
1056 { 1056
1057 e.GetHashCode(); 1057 /// <summary>
1058 } 1058 /// Wait for all work items to complete
1059 catch(ThreadStateException ex) 1059 /// </summary>
1060 { 1060 /// <param name="waitableResults">Array of work item result objects</param>
1061 ex.GetHashCode(); 1061 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1062 // In case the thread has been terminated 1062 /// <param name="exitContext">
1063 // after the check if it is alive. 1063 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1064 } 1064 /// </param>
1065 } 1065 /// <returns>
1066 } 1066 /// true when every work item in workItemResults has completed; otherwise false.
1067 } 1067 /// </returns>
1068 1068 public static bool WaitAll(
1069 // Dispose of the performance counters 1069 IWaitableResult [] waitableResults,
1070 pcs.Dispose(); 1070 TimeSpan timeout,
1071 } 1071 bool exitContext)
1072 1072 {
1073 /// <summary> 1073 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext);
1074 /// Wait for all work items to complete 1074 }
1075 /// </summary> 1075
1076 /// <param name="workItemResults">Array of work item result objects</param> 1076 /// <summary>
1077 /// <returns> 1077 /// Wait for all work items to complete
1078 /// true when every work item in workItemResults has completed; otherwise false. 1078 /// </summary>
1079 /// </returns> 1079 /// <param name="waitableResults">Array of work item result objects</param>
1080 public static bool WaitAll( 1080 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1081 IWorkItemResult [] workItemResults) 1081 /// <param name="exitContext">
1082 { 1082 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1083 return WaitAll(workItemResults, Timeout.Infinite, true); 1083 /// </param>
1084 } 1084 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1085 1085 /// <returns>
1086 /// <summary> 1086 /// true when every work item in workItemResults has completed; otherwise false.
1087 /// Wait for all work items to complete 1087 /// </returns>
1088 /// </summary> 1088 public static bool WaitAll(
1089 /// <param name="workItemResults">Array of work item result objects</param> 1089 IWaitableResult[] waitableResults,
1090 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1090 TimeSpan timeout,
1091 /// <param name="exitContext"> 1091 bool exitContext,
1092 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1092 WaitHandle cancelWaitHandle)
1093 /// </param> 1093 {
1094 /// <returns> 1094 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
1095 /// true when every work item in workItemResults has completed; otherwise false. 1095 }
1096 /// </returns> 1096
1097 public static bool WaitAll( 1097 /// <summary>
1098 IWorkItemResult [] workItemResults, 1098 /// Wait for all work items to complete
1099 TimeSpan timeout, 1099 /// </summary>
1100 bool exitContext) 1100 /// <param name="waitableResults">Array of work item result objects</param>
1101 { 1101 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1102 return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext); 1102 /// <param name="exitContext">
1103 } 1103 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1104 1104 /// </param>
1105 /// <summary> 1105 /// <returns>
1106 /// Wait for all work items to complete 1106 /// true when every work item in workItemResults has completed; otherwise false.
1107 /// </summary> 1107 /// </returns>
1108 /// <param name="workItemResults">Array of work item result objects</param> 1108 public static bool WaitAll(
1109 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1109 IWaitableResult [] waitableResults,
1110 /// <param name="exitContext"> 1110 int millisecondsTimeout,
1111 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1111 bool exitContext)
1112 /// </param> 1112 {
1113 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1113 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null);
1114 /// <returns> 1114 }
1115 /// true when every work item in workItemResults has completed; otherwise false. 1115
1116 /// </returns> 1116 /// <summary>
1117 public static bool WaitAll( 1117 /// Wait for all work items to complete
1118 IWorkItemResult [] workItemResults, 1118 /// </summary>
1119 TimeSpan timeout, 1119 /// <param name="waitableResults">Array of work item result objects</param>
1120 bool exitContext, 1120 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1121 WaitHandle cancelWaitHandle) 1121 /// <param name="exitContext">
1122 { 1122 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1123 return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 1123 /// </param>
1124 } 1124 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1125 1125 /// <returns>
1126 /// <summary> 1126 /// true when every work item in workItemResults has completed; otherwise false.
1127 /// Wait for all work items to complete 1127 /// </returns>
1128 /// </summary> 1128 public static bool WaitAll(
1129 /// <param name="workItemResults">Array of work item result objects</param> 1129 IWaitableResult[] waitableResults,
1130 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1130 int millisecondsTimeout,
1131 /// <param name="exitContext"> 1131 bool exitContext,
1132 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1132 WaitHandle cancelWaitHandle)
1133 /// </param> 1133 {
1134 /// <returns> 1134 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1135 /// true when every work item in workItemResults has completed; otherwise false. 1135 }
1136 /// </returns> 1136
1137 public static bool WaitAll( 1137
1138 IWorkItemResult [] workItemResults, 1138 /// <summary>
1139 int millisecondsTimeout, 1139 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1140 bool exitContext) 1140 /// </summary>
1141 { 1141 /// <param name="waitableResults">Array of work item result objects</param>
1142 return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, null); 1142 /// <returns>
1143 } 1143 /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled.
1144 1144 /// </returns>
1145 /// <summary> 1145 public static int WaitAny(
1146 /// Wait for all work items to complete 1146 IWaitableResult [] waitableResults)
1147 /// </summary> 1147 {
1148 /// <param name="workItemResults">Array of work item result objects</param> 1148 return WaitAny(waitableResults, Timeout.Infinite, true);
1149 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1149 }
1150 /// <param name="exitContext"> 1150
1151 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1151 /// <summary>
1152 /// </param> 1152 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1153 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1153 /// </summary>
1154 /// <returns> 1154 /// <param name="waitableResults">Array of work item result objects</param>
1155 /// true when every work item in workItemResults has completed; otherwise false. 1155 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1156 /// </returns> 1156 /// <param name="exitContext">
1157 public static bool WaitAll( 1157 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1158 IWorkItemResult [] workItemResults, 1158 /// </param>
1159 int millisecondsTimeout, 1159 /// <returns>
1160 bool exitContext, 1160 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1161 WaitHandle cancelWaitHandle) 1161 /// </returns>
1162 { 1162 public static int WaitAny(
1163 return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle); 1163 IWaitableResult[] waitableResults,
1164 } 1164 TimeSpan timeout,
1165 1165 bool exitContext)
1166 1166 {
1167 /// <summary> 1167 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext);
1168 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1168 }
1169 /// </summary> 1169
1170 /// <param name="workItemResults">Array of work item result objects</param> 1170 /// <summary>
1171 /// <returns> 1171 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1172 /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. 1172 /// </summary>
1173 /// </returns> 1173 /// <param name="waitableResults">Array of work item result objects</param>
1174 public static int WaitAny( 1174 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1175 IWorkItemResult [] workItemResults) 1175 /// <param name="exitContext">
1176 { 1176 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1177 return WaitAny(workItemResults, Timeout.Infinite, true); 1177 /// </param>
1178 } 1178 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1179 1179 /// <returns>
1180 /// <summary> 1180 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1181 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1181 /// </returns>
1182 /// </summary> 1182 public static int WaitAny(
1183 /// <param name="workItemResults">Array of work item result objects</param> 1183 IWaitableResult [] waitableResults,
1184 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1184 TimeSpan timeout,
1185 /// <param name="exitContext"> 1185 bool exitContext,
1186 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1186 WaitHandle cancelWaitHandle)
1187 /// </param> 1187 {
1188 /// <returns> 1188 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
1189 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1189 }
1190 /// </returns> 1190
1191 public static int WaitAny( 1191 /// <summary>
1192 IWorkItemResult [] workItemResults, 1192 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1193 TimeSpan timeout, 1193 /// </summary>
1194 bool exitContext) 1194 /// <param name="waitableResults">Array of work item result objects</param>
1195 { 1195 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1196 return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext); 1196 /// <param name="exitContext">
1197 } 1197 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1198 1198 /// </param>
1199 /// <summary> 1199 /// <returns>
1200 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1200 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1201 /// </summary> 1201 /// </returns>
1202 /// <param name="workItemResults">Array of work item result objects</param> 1202 public static int WaitAny(
1203 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1203 IWaitableResult [] waitableResults,
1204 /// <param name="exitContext"> 1204 int millisecondsTimeout,
1205 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1205 bool exitContext)
1206 /// </param> 1206 {
1207 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1207 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null);
1208 /// <returns> 1208 }
1209 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1209
1210 /// </returns> 1210 /// <summary>
1211 public static int WaitAny( 1211 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1212 IWorkItemResult [] workItemResults, 1212 /// </summary>
1213 TimeSpan timeout, 1213 /// <param name="waitableResults">Array of work item result objects</param>
1214 bool exitContext, 1214 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1215 WaitHandle cancelWaitHandle) 1215 /// <param name="exitContext">
1216 { 1216 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1217 return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 1217 /// </param>
1218 } 1218 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1219 1219 /// <returns>
1220 /// <summary> 1220 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1221 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1221 /// </returns>
1222 /// </summary> 1222 public static int WaitAny(
1223 /// <param name="workItemResults">Array of work item result objects</param> 1223 IWaitableResult [] waitableResults,
1224 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1224 int millisecondsTimeout,
1225 /// <param name="exitContext"> 1225 bool exitContext,
1226 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1226 WaitHandle cancelWaitHandle)
1227 /// </param> 1227 {
1228 /// <returns> 1228 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1229 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1229 }
1230 /// </returns> 1230
1231 public static int WaitAny( 1231 /// <summary>
1232 IWorkItemResult [] workItemResults, 1232 /// Creates a new WorkItemsGroup.
1233 int millisecondsTimeout, 1233 /// </summary>
1234 bool exitContext) 1234 /// <param name="concurrency">The number of work items that can be run concurrently</param>
1235 { 1235 /// <returns>A reference to the WorkItemsGroup</returns>
1236 return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, null); 1236 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency)
1237 } 1237 {
1238 1238 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo);
1239 /// <summary> 1239 return workItemsGroup;
1240 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1240 }
1241 /// </summary> 1241
1242 /// <param name="workItemResults">Array of work item result objects</param> 1242 /// <summary>
1243 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1243 /// Creates a new WorkItemsGroup.
1244 /// <param name="exitContext"> 1244 /// </summary>
1245 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1245 /// <param name="concurrency">The number of work items that can be run concurrently</param>
1246 /// </param> 1246 /// <param name="wigStartInfo">A WorkItemsGroup configuration that overrides the default behavior</param>
1247 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1247 /// <returns>A reference to the WorkItemsGroup</returns>
1248 /// <returns> 1248 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo)
1249 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1249 {
1250 /// </returns> 1250 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo);
1251 public static int WaitAny( 1251 return workItemsGroup;
1252 IWorkItemResult [] workItemResults, 1252 }
1253 int millisecondsTimeout, 1253
1254 bool exitContext, 1254 #region Fire Thread's Events
1255 WaitHandle cancelWaitHandle) 1255
1256 { 1256 private void FireOnThreadInitialization()
1257 return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle); 1257 {
1258 } 1258 if (null != _onThreadInitialization)
1259 1259 {
1260 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) 1260 foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList())
1261 { 1261 {
1262 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); 1262 try
1263 return workItemsGroup; 1263 {
1264 } 1264 tih();
1265 1265 }
1266 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) 1266 catch (Exception e)
1267 { 1267 {
1268 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); 1268 e.GetHashCode();
1269 return workItemsGroup; 1269 Debug.Assert(false);
1270 } 1270 throw;
1271 1271 }
1272 public event WorkItemsGroupIdleHandler OnIdle 1272 }
1273 { 1273 }
1274 add 1274 }
1275 { 1275
1276 throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); 1276 private void FireOnThreadTermination()
1277 //_onIdle += value; 1277 {
1278 } 1278 if (null != _onThreadTermination)
1279 remove 1279 {
1280 { 1280 foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList())
1281 throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); 1281 {
1282 //_onIdle -= value; 1282 try
1283 } 1283 {
1284 } 1284 tth();
1285 1285 }
1286 public void Cancel() 1286 catch (Exception e)
1287 { 1287 {
1288 ICollection workItemsGroups = _workItemsGroups.Values; 1288 e.GetHashCode();
1289 foreach(WorkItemsGroup workItemsGroup in workItemsGroups) 1289 Debug.Assert(false);
1290 { 1290 throw;
1291 workItemsGroup.Cancel(); 1291 }
1292 } 1292 }
1293 } 1293 }
1294 1294 }
1295 public void Start() 1295
1296 { 1296 #endregion
1297 lock (this) 1297
1298 { 1298 /// <summary>
1299 if (!this._stpStartInfo.StartSuspended) 1299 /// This event is fired when a thread is created.
1300 { 1300 /// Use it to initialize a thread before the work items use it.
1301 return; 1301 /// </summary>
1302 } 1302 public event ThreadInitializationHandler OnThreadInitialization
1303 _stpStartInfo.StartSuspended = false; 1303 {
1304 } 1304 add { _onThreadInitialization += value; }
1305 1305 remove { _onThreadInitialization -= value; }
1306 ICollection workItemsGroups = _workItemsGroups.Values; 1306 }
1307 foreach(WorkItemsGroup workItemsGroup in workItemsGroups) 1307
1308 { 1308 /// <summary>
1309 workItemsGroup.OnSTPIsStarting(); 1309 /// This event is fired when a thread is terminating.
1310 } 1310 /// Use it for cleanup.
1311 1311 /// </summary>
1312 StartOptimalNumberOfThreads(); 1312 public event ThreadTerminationHandler OnThreadTermination
1313 } 1313 {
1314 1314 add { _onThreadTermination += value; }
1315 #endregion 1315 remove { _onThreadTermination -= value; }
1316 1316 }
1317 #region Properties 1317
1318 1318
1319 /// <summary> 1319 internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig)
1320 /// Get/Set the name of the SmartThreadPool instance 1320 {
1321 /// </summary> 1321 foreach (ThreadEntry threadEntry in _workerThreads.Values)
1322 public string Name 1322 {
1323 { 1323 WorkItem workItem = threadEntry.CurrentWorkItem;
1324 get 1324 if (null != workItem &&
1325 { 1325 workItem.WasQueuedBy(wig) &&
1326 return _name; 1326 !workItem.IsCanceled)
1327 } 1327 {
1328 1328 threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true);
1329 set 1329 }
1330 { 1330 }
1331 _name = value; 1331 }
1332 } 1332
1333 } 1333
1334 1334
1335 /// <summary> 1335 #endregion
1336 /// Get the lower limit of threads in the pool. 1336
1337 /// </summary> 1337 #region Properties
1338 public int MinThreads 1338
1339 { 1339 /// <summary>
1340 get 1340 /// Get/Set the lower limit of threads in the pool.
1341 { 1341 /// </summary>
1342 ValidateNotDisposed(); 1342 public int MinThreads
1343 return _stpStartInfo.MinWorkerThreads; 1343 {
1344 } 1344 get
1345 } 1345 {
1346 1346 ValidateNotDisposed();
1347 /// <summary> 1347 return _stpStartInfo.MinWorkerThreads;
1348 /// Get the upper limit of threads in the pool. 1348 }
1349 /// </summary> 1349 set
1350 public int MaxThreads 1350 {
1351 { 1351 Debug.Assert(value >= 0);
1352 get 1352 Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads);
1353 { 1353 if (_stpStartInfo.MaxWorkerThreads < value)
1354 ValidateNotDisposed(); 1354 {
1355 return _stpStartInfo.MaxWorkerThreads; 1355 _stpStartInfo.MaxWorkerThreads = value;
1356 } 1356 }
1357 } 1357 _stpStartInfo.MinWorkerThreads = value;
1358 /// <summary> 1358 StartOptimalNumberOfThreads();
1359 /// Get the number of threads in the thread pool. 1359 }
1360 /// Should be between the lower and the upper limits. 1360 }
1361 /// </summary> 1361
1362 public int ActiveThreads 1362 /// <summary>
1363 { 1363 /// Get/Set the upper limit of threads in the pool.
1364 get 1364 /// </summary>
1365 { 1365 public int MaxThreads
1366 ValidateNotDisposed(); 1366 {
1367 return _workerThreads.Count; 1367 get
1368 } 1368 {
1369 } 1369 ValidateNotDisposed();
1370 1370 return _stpStartInfo.MaxWorkerThreads;
1371 /// <summary> 1371 }
1372 /// Get the number of busy (not idle) threads in the thread pool. 1372
1373 /// </summary> 1373 set
1374 public int InUseThreads 1374 {
1375 { 1375 Debug.Assert(value > 0);
1376 get 1376 Debug.Assert(value >= _stpStartInfo.MinWorkerThreads);
1377 { 1377 if (_stpStartInfo.MinWorkerThreads > value)
1378 ValidateNotDisposed(); 1378 {
1379 return _inUseWorkerThreads; 1379 _stpStartInfo.MinWorkerThreads = value;
1380 } 1380 }
1381 } 1381 _stpStartInfo.MaxWorkerThreads = value;
1382 1382 StartOptimalNumberOfThreads();
1383 /// <summary> 1383 }
1384 /// Get the number of work items in the queue. 1384 }
1385 /// </summary> 1385 /// <summary>
1386 public int WaitingCallbacks 1386 /// Get the number of threads in the thread pool.
1387 { 1387 /// Should be between the lower and the upper limits.
1388 get 1388 /// </summary>
1389 { 1389 public int ActiveThreads
1390 ValidateNotDisposed(); 1390 {
1391 return _workItemsQueue.Count; 1391 get
1392 } 1392 {
1393 } 1393 ValidateNotDisposed();
1394 1394 return _workerThreads.Count;
1395 1395 }
1396 public event EventHandler Idle 1396 }
1397 { 1397
1398 add 1398 /// <summary>
1399 { 1399 /// Get the number of busy (not idle) threads in the thread pool.
1400 _stpIdle += value; 1400 /// </summary>
1401 } 1401 public int InUseThreads
1402 1402 {
1403 remove 1403 get
1404 { 1404 {
1405 _stpIdle -= value; 1405 ValidateNotDisposed();
1406 } 1406 return _inUseWorkerThreads;
1407 } 1407 }
1408 1408 }
1409 #endregion 1409
1410 1410 /// <summary>
1411 #region IDisposable Members 1411 /// Returns true if the current running work item has been cancelled.
1412 1412 /// Must be used within the work item's callback method.
1413// ~SmartThreadPool() 1413 /// The work item should sample this value in order to know if it
1414// { 1414 /// needs to quit before its completion.
1415// Dispose(); 1415 /// </summary>
1416// } 1416 public static bool IsWorkItemCanceled
1417 1417 {
1418 public void Dispose() 1418 get
1419 { 1419 {
1420 if (!_isDisposed) 1420 return CurrentThreadEntry.CurrentWorkItem.IsCanceled;
1421 { 1421 }
1422 if (!_shutdown) 1422 }
1423 { 1423
1424 Shutdown(); 1424 /// <summary>
1425 } 1425 /// Checks if the work item has been cancelled, and if yes then abort the thread.
1426 1426 /// Can be used with Cancel and timeout
1427 if (null != _shuttingDownEvent) 1427 /// </summary>
1428 { 1428 public static void AbortOnWorkItemCancel()
1429 _shuttingDownEvent.Close(); 1429 {
1430 _shuttingDownEvent = null; 1430 if (IsWorkItemCanceled)
1431 } 1431 {
1432 _workerThreads.Clear(); 1432 Thread.CurrentThread.Abort();
1433 _isDisposed = true; 1433 }
1434 GC.SuppressFinalize(this); 1434 }
1435 } 1435
1436 } 1436 /// <summary>
1437 1437 /// Thread Pool start information (readonly)
1438 private void ValidateNotDisposed() 1438 /// </summary>
1439 { 1439 public STPStartInfo STPStartInfo
1440 if(_isDisposed) 1440 {
1441 { 1441 get
1442 throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); 1442 {
1443 } 1443 return _stpStartInfo.AsReadOnly();
1444 } 1444 }
1445 #endregion 1445 }
1446 } 1446
1447 #endregion 1447 public bool IsShuttingdown
1448} 1448 {
1449 get { return _shutdown; }
1450 }
1451
1452 /// <summary>
1453 /// Return the local calculated performance counters
1454 /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true.
1455 /// </summary>
1456 public ISTPPerformanceCountersReader PerformanceCountersReader
1457 {
1458 get { return (ISTPPerformanceCountersReader)_localPCs; }
1459 }
1460
1461 #endregion
1462
1463 #region IDisposable Members
1464
1465 public void Dispose()
1466 {
1467 if (!_isDisposed)
1468 {
1469 if (!_shutdown)
1470 {
1471 Shutdown();
1472 }
1473
1474 if (null != _shuttingDownEvent)
1475 {
1476 _shuttingDownEvent.Close();
1477 _shuttingDownEvent = null;
1478 }
1479 _workerThreads.Clear();
1480
1481 if (null != _isIdleWaitHandle)
1482 {
1483 _isIdleWaitHandle.Close();
1484 _isIdleWaitHandle = null;
1485 }
1486
1487 _isDisposed = true;
1488 }
1489 }
1490
1491 private void ValidateNotDisposed()
1492 {
1493 if(_isDisposed)
1494 {
1495 throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
1496 }
1497 }
1498 #endregion
1499
1500 #region WorkItemsGroupBase Overrides
1501
1502 /// <summary>
1503 /// Get/Set the maximum number of work items that execute cocurrency on the thread pool
1504 /// </summary>
1505 public override int Concurrency
1506 {
1507 get { return MaxThreads; }
1508 set { MaxThreads = value; }
1509 }
1510
1511 /// <summary>
1512 /// Get the number of work items in the queue.
1513 /// </summary>
1514 public override int WaitingCallbacks
1515 {
1516 get
1517 {
1518 ValidateNotDisposed();
1519 return _workItemsQueue.Count;
1520 }
1521 }
1522
1523 /// <summary>
1524 /// Get an array with all the state objects of the currently running items.
1525 /// The array represents a snap shot and impact performance.
1526 /// </summary>
1527 public override object[] GetStates()
1528 {
1529 object[] states = _workItemsQueue.GetStates();
1530 return states;
1531 }
1532
1533 /// <summary>
1534 /// WorkItemsGroup start information (readonly)
1535 /// </summary>
1536 public override WIGStartInfo WIGStartInfo
1537 {
1538 get { return _stpStartInfo.AsReadOnly(); }
1539 }
1540
1541 /// <summary>
1542 /// Start the thread pool if it was started suspended.
1543 /// If it is already running, this method is ignored.
1544 /// </summary>
1545 public override void Start()
1546 {
1547 if (!_isSuspended)
1548 {
1549 return;
1550 }
1551 _isSuspended = false;
1552
1553 ICollection workItemsGroups = _workItemsGroups.Values;
1554 foreach (WorkItemsGroup workItemsGroup in workItemsGroups)
1555 {
1556 workItemsGroup.OnSTPIsStarting();
1557 }
1558
1559 StartOptimalNumberOfThreads();
1560 }
1561
1562 /// <summary>
1563 /// Cancel all work items using thread abortion
1564 /// </summary>
1565 /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
1566 public override void Cancel(bool abortExecution)
1567 {
1568 _canceledSmartThreadPool.IsCanceled = true;
1569 _canceledSmartThreadPool = new CanceledWorkItemsGroup();
1570
1571 ICollection workItemsGroups = _workItemsGroups.Values;
1572 foreach (WorkItemsGroup workItemsGroup in workItemsGroups)
1573 {
1574 workItemsGroup.Cancel(abortExecution);
1575 }
1576
1577 if (abortExecution)
1578 {
1579 foreach (ThreadEntry threadEntry in _workerThreads.Values)
1580 {
1581 WorkItem workItem = threadEntry.CurrentWorkItem;
1582 if (null != workItem &&
1583 threadEntry.AssociatedSmartThreadPool == this &&
1584 !workItem.IsCanceled)
1585 {
1586 threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true);
1587 }
1588 }
1589 }
1590 }
1591
1592 /// <summary>
1593 /// Wait for the thread pool to be idle
1594 /// </summary>
1595 public override bool WaitForIdle(int millisecondsTimeout)
1596 {
1597 ValidateWaitForIdle();
1598 return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
1599 }
1600
1601 /// <summary>
1602 /// This event is fired when all work items are completed.
1603 /// (When IsIdle changes to true)
1604 /// This event only work on WorkItemsGroup. On SmartThreadPool
1605 /// it throws the NotImplementedException.
1606 /// </summary>
1607 public override event WorkItemsGroupIdleHandler OnIdle
1608 {
1609 add
1610 {
1611 throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature.");
1612 //_onIdle += value;
1613 }
1614 remove
1615 {
1616 throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature.");
1617 //_onIdle -= value;
1618 }
1619 }
1620
1621 internal override void PreQueueWorkItem()
1622 {
1623 ValidateNotDisposed();
1624 }
1625
1626 #endregion
1627
1628 #region Join, Choice, Pipe, etc.
1629
1630 /// <summary>
1631 /// Executes all actions in parallel.
1632 /// Returns when they all finish.
1633 /// </summary>
1634 /// <param name="actions">Actions to execute</param>
1635 public void Join(IEnumerable<Action> actions)
1636 {
1637 WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true };
1638 IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
1639 foreach (Action action in actions)
1640 {
1641 workItemsGroup.QueueWorkItem(action);
1642 }
1643 workItemsGroup.Start();
1644 workItemsGroup.WaitForIdle();
1645 }
1646
1647 /// <summary>
1648 /// Executes all actions in parallel.
1649 /// Returns when they all finish.
1650 /// </summary>
1651 /// <param name="actions">Actions to execute</param>
1652 public void Join(params Action[] actions)
1653 {
1654 Join((IEnumerable<Action>)actions);
1655 }
1656
1657 private class ChoiceIndex
1658 {
1659 public int _index = -1;
1660 }
1661
1662 /// <summary>
1663 /// Executes all actions in parallel
1664 /// Returns when the first one completes
1665 /// </summary>
1666 /// <param name="actions">Actions to execute</param>
1667 public int Choice(IEnumerable<Action> actions)
1668 {
1669 WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true };
1670 IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
1671
1672 ManualResetEvent anActionCompleted = new ManualResetEvent(false);
1673
1674 ChoiceIndex choiceIndex = new ChoiceIndex();
1675
1676 int i = 0;
1677 foreach (Action action in actions)
1678 {
1679 Action act = action;
1680 int value = i;
1681 workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); });
1682 ++i;
1683 }
1684 workItemsGroup.Start();
1685 anActionCompleted.WaitOne();
1686
1687 return choiceIndex._index;
1688 }
1689
1690 /// <summary>
1691 /// Executes all actions in parallel
1692 /// Returns when the first one completes
1693 /// </summary>
1694 /// <param name="actions">Actions to execute</param>
1695 public int Choice(params Action[] actions)
1696 {
1697 return Choice((IEnumerable<Action>)actions);
1698 }
1699
1700 /// <summary>
1701 /// Executes actions in sequence asynchronously.
1702 /// Returns immediately.
1703 /// </summary>
1704 /// <param name="pipeState">A state context that passes </param>
1705 /// <param name="actions">Actions to execute in the order they should run</param>
1706 public void Pipe<T>(T pipeState, IEnumerable<Action<T>> actions)
1707 {
1708 WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true };
1709 IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo);
1710 foreach (Action<T> action in actions)
1711 {
1712 Action<T> act = action;
1713 workItemsGroup.QueueWorkItem(() => act(pipeState));
1714 }
1715 workItemsGroup.Start();
1716 workItemsGroup.WaitForIdle();
1717 }
1718
1719 /// <summary>
1720 /// Executes actions in sequence asynchronously.
1721 /// Returns immediately.
1722 /// </summary>
1723 /// <param name="pipeState"></param>
1724 /// <param name="actions">Actions to execute in the order they should run</param>
1725 public void Pipe<T>(T pipeState, params Action<T>[] actions)
1726 {
1727 Pipe(pipeState, (IEnumerable<Action<T>>)actions);
1728 }
1729 #endregion
1730 }
1731 #endregion
1732}
diff --git a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs
new file mode 100644
index 0000000..3532cca
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs
@@ -0,0 +1,89 @@
1using System.Collections.Generic;
2
3namespace Amib.Threading.Internal
4{
5 internal class SynchronizedDictionary<TKey, TValue>
6 {
7 private readonly Dictionary<TKey, TValue> _dictionary;
8 private readonly object _lock;
9
10 public SynchronizedDictionary()
11 {
12 _lock = new object();
13 _dictionary = new Dictionary<TKey, TValue>();
14 }
15
16 public int Count
17 {
18 get { return _dictionary.Count; }
19 }
20
21 public bool Contains(TKey key)
22 {
23 lock (_lock)
24 {
25 return _dictionary.ContainsKey(key);
26 }
27 }
28
29 public void Remove(TKey key)
30 {
31 lock (_lock)
32 {
33 _dictionary.Remove(key);
34 }
35 }
36
37 public object SyncRoot
38 {
39 get { return _lock; }
40 }
41
42 public TValue this[TKey key]
43 {
44 get
45 {
46 lock (_lock)
47 {
48 return _dictionary[key];
49 }
50 }
51 set
52 {
53 lock (_lock)
54 {
55 _dictionary[key] = value;
56 }
57 }
58 }
59
60 public Dictionary<TKey, TValue>.KeyCollection Keys
61 {
62 get
63 {
64 lock (_lock)
65 {
66 return _dictionary.Keys;
67 }
68 }
69 }
70
71 public Dictionary<TKey, TValue>.ValueCollection Values
72 {
73 get
74 {
75 lock (_lock)
76 {
77 return _dictionary.Values;
78 }
79 }
80 }
81 public void Clear()
82 {
83 lock (_lock)
84 {
85 _dictionary.Clear();
86 }
87 }
88 }
89}
diff --git a/ThirdParty/SmartThreadPool/WIGStartInfo.cs b/ThirdParty/SmartThreadPool/WIGStartInfo.cs
index 150317f..e5ff150 100644
--- a/ThirdParty/SmartThreadPool/WIGStartInfo.cs
+++ b/ThirdParty/SmartThreadPool/WIGStartInfo.cs
@@ -1,99 +1,171 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2
3 3namespace Amib.Threading
4namespace Amib.Threading 4{
5{ 5 /// <summary>
6 /// <summary> 6 /// Summary description for WIGStartInfo.
7 /// Summary description for WIGStartInfo. 7 /// </summary>
8 /// </summary> 8 public class WIGStartInfo
9 public class WIGStartInfo 9 {
10 { 10 private bool _useCallerCallContext;
11 /// <summary> 11 private bool _useCallerHttpContext;
12 /// Use the caller's security context 12 private bool _disposeOfStateObjects;
13 /// </summary> 13 private CallToPostExecute _callToPostExecute;
14 private bool _useCallerCallContext; 14 private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
15 15 private bool _startSuspended;
16 /// <summary> 16 private WorkItemPriority _workItemPriority;
17 /// Use the caller's HTTP context 17 private bool _fillStateWithArgs;
18 /// </summary> 18
19 private bool _useCallerHttpContext; 19 protected bool _readOnly;
20 20
21 /// <summary> 21 public WIGStartInfo()
22 /// Dispose of the state object of a work item 22 {
23 /// </summary> 23 _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
24 private bool _disposeOfStateObjects; 24 _workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
25 25 _startSuspended = SmartThreadPool.DefaultStartSuspended;
26 /// <summary> 26 _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
27 /// The option to run the post execute 27 _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
28 /// </summary> 28 _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
29 private CallToPostExecute _callToPostExecute; 29 _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
30 30 _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
31 /// <summary> 31 }
32 /// A post execute callback to call when none is provided in 32
33 /// the QueueWorkItem method. 33 public WIGStartInfo(WIGStartInfo wigStartInfo)
34 /// </summary> 34 {
35 private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; 35 _useCallerCallContext = wigStartInfo.UseCallerCallContext;
36 36 _useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
37 /// <summary> 37 _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
38 /// Indicate the WorkItemsGroup to suspend the handling of the work items 38 _callToPostExecute = wigStartInfo.CallToPostExecute;
39 /// until the Start() method is called. 39 _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
40 /// </summary> 40 _workItemPriority = wigStartInfo.WorkItemPriority;
41 private bool _startSuspended; 41 _startSuspended = wigStartInfo.StartSuspended;
42 42 _fillStateWithArgs = wigStartInfo.FillStateWithArgs;
43 public WIGStartInfo() 43 }
44 { 44
45 _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; 45 protected void ThrowIfReadOnly()
46 _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; 46 {
47 _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; 47 if (_readOnly)
48 _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; 48 {
49 _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; 49 throw new NotSupportedException("This is a readonly instance and set is not supported");
50 _startSuspended = SmartThreadPool.DefaultStartSuspended; 50 }
51 } 51 }
52 52
53 public WIGStartInfo(WIGStartInfo wigStartInfo) 53 /// <summary>
54 { 54 /// Get/Set if to use the caller's security context
55 _useCallerCallContext = wigStartInfo._useCallerCallContext; 55 /// </summary>
56 _useCallerHttpContext = wigStartInfo._useCallerHttpContext; 56 public virtual bool UseCallerCallContext
57 _disposeOfStateObjects = wigStartInfo._disposeOfStateObjects; 57 {
58 _callToPostExecute = wigStartInfo._callToPostExecute; 58 get { return _useCallerCallContext; }
59 _postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback; 59 set
60 _startSuspended = wigStartInfo._startSuspended; 60 {
61 } 61 ThrowIfReadOnly();
62 62 _useCallerCallContext = value;
63 public bool UseCallerCallContext 63 }
64 { 64 }
65 get { return _useCallerCallContext; } 65
66 set { _useCallerCallContext = value; } 66
67 } 67 /// <summary>
68 68 /// Get/Set if to use the caller's HTTP context
69 public bool UseCallerHttpContext 69 /// </summary>
70 { 70 public virtual bool UseCallerHttpContext
71 get { return _useCallerHttpContext; } 71 {
72 set { _useCallerHttpContext = value; } 72 get { return _useCallerHttpContext; }
73 } 73 set
74 74 {
75 public bool DisposeOfStateObjects 75 ThrowIfReadOnly();
76 { 76 _useCallerHttpContext = value;
77 get { return _disposeOfStateObjects; } 77 }
78 set { _disposeOfStateObjects = value; } 78 }
79 } 79
80 80
81 public CallToPostExecute CallToPostExecute 81 /// <summary>
82 { 82 /// Get/Set if to dispose of the state object of a work item
83 get { return _callToPostExecute; } 83 /// </summary>
84 set { _callToPostExecute = value; } 84 public virtual bool DisposeOfStateObjects
85 } 85 {
86 86 get { return _disposeOfStateObjects; }
87 public PostExecuteWorkItemCallback PostExecuteWorkItemCallback 87 set
88 { 88 {
89 get { return _postExecuteWorkItemCallback; } 89 ThrowIfReadOnly();
90 set { _postExecuteWorkItemCallback = value; } 90 _disposeOfStateObjects = value;
91 } 91 }
92 92 }
93 public bool StartSuspended 93
94 { 94
95 get { return _startSuspended; } 95 /// <summary>
96 set { _startSuspended = value; } 96 /// Get/Set the run the post execute options
97 } 97 /// </summary>
98 } 98 public virtual CallToPostExecute CallToPostExecute
99} 99 {
100 get { return _callToPostExecute; }
101 set
102 {
103 ThrowIfReadOnly();
104 _callToPostExecute = value;
105 }
106 }
107
108
109 /// <summary>
110 /// Get/Set the default post execute callback
111 /// </summary>
112 public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
113 {
114 get { return _postExecuteWorkItemCallback; }
115 set
116 {
117 ThrowIfReadOnly();
118 _postExecuteWorkItemCallback = value;
119 }
120 }
121
122
123 /// <summary>
124 /// Get/Set if the work items execution should be suspended until the Start()
125 /// method is called.
126 /// </summary>
127 public virtual bool StartSuspended
128 {
129 get { return _startSuspended; }
130 set
131 {
132 ThrowIfReadOnly();
133 _startSuspended = value;
134 }
135 }
136
137
138 /// <summary>
139 /// Get/Set the default priority that a work item gets when it is enqueued
140 /// </summary>
141 public virtual WorkItemPriority WorkItemPriority
142 {
143 get { return _workItemPriority; }
144 set { _workItemPriority = value; }
145 }
146
147 /// <summary>
148 /// Get/Set the if QueueWorkItem of Action&lt;...&gt;/Func&lt;...&gt; fill the
149 /// arguments as an object array into the state of the work item.
150 /// The arguments can be access later by IWorkItemResult.State.
151 /// </summary>
152 public virtual bool FillStateWithArgs
153 {
154 get { return _fillStateWithArgs; }
155 set
156 {
157 ThrowIfReadOnly();
158 _fillStateWithArgs = value;
159 }
160 }
161
162 /// <summary>
163 /// Get a readonly version of this WIGStartInfo
164 /// </summary>
165 /// <returns>Returns a readonly reference to this WIGStartInfoRO</returns>
166 public WIGStartInfo AsReadOnly()
167 {
168 return new WIGStartInfo(this) { _readOnly = true };
169 }
170 }
171}
diff --git a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs
new file mode 100644
index 0000000..5745c15
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs
@@ -0,0 +1,190 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading;
5
6namespace Amib.Threading.Internal
7{
8 public partial class WorkItem
9 {
10 #region WorkItemResult class
11
12 private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult
13 {
14 /// <summary>
15 /// A back reference to the work item
16 /// </summary>
17 private readonly WorkItem _workItem;
18
19 public WorkItemResult(WorkItem workItem)
20 {
21 _workItem = workItem;
22 }
23
24 internal WorkItem GetWorkItem()
25 {
26 return _workItem;
27 }
28
29 #region IWorkItemResult Members
30
31 public bool IsCompleted
32 {
33 get
34 {
35 return _workItem.IsCompleted;
36 }
37 }
38
39 public bool IsCanceled
40 {
41 get
42 {
43 return _workItem.IsCanceled;
44 }
45 }
46
47 public object GetResult()
48 {
49 return _workItem.GetResult(Timeout.Infinite, true, null);
50 }
51
52 public object GetResult(int millisecondsTimeout, bool exitContext)
53 {
54 return _workItem.GetResult(millisecondsTimeout, exitContext, null);
55 }
56
57 public object GetResult(TimeSpan timeout, bool exitContext)
58 {
59 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
60 }
61
62 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
63 {
64 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
65 }
66
67 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
68 {
69 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
70 }
71
72 public object GetResult(out Exception e)
73 {
74 return _workItem.GetResult(Timeout.Infinite, true, null, out e);
75 }
76
77 public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
78 {
79 return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
80 }
81
82 public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
83 {
84 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
85 }
86
87 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
88 {
89 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
90 }
91
92 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
93 {
94 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
95 }
96
97 public bool Cancel()
98 {
99 return Cancel(false);
100 }
101
102 public bool Cancel(bool abortExecution)
103 {
104 return _workItem.Cancel(abortExecution);
105 }
106
107 public object State
108 {
109 get
110 {
111 return _workItem._state;
112 }
113 }
114
115 public WorkItemPriority WorkItemPriority
116 {
117 get
118 {
119 return _workItem._workItemInfo.WorkItemPriority;
120 }
121 }
122
123 /// <summary>
124 /// Return the result, same as GetResult()
125 /// </summary>
126 public object Result
127 {
128 get { return GetResult(); }
129 }
130
131 /// <summary>
132 /// Returns the exception if occured otherwise returns null.
133 /// This value is valid only after the work item completed,
134 /// before that it is always null.
135 /// </summary>
136 public object Exception
137 {
138 get { return _workItem._exception; }
139 }
140
141 #endregion
142
143 #region IInternalWorkItemResult Members
144
145 public event WorkItemStateCallback OnWorkItemStarted
146 {
147 add
148 {
149 _workItem.OnWorkItemStarted += value;
150 }
151 remove
152 {
153 _workItem.OnWorkItemStarted -= value;
154 }
155 }
156
157
158 public event WorkItemStateCallback OnWorkItemCompleted
159 {
160 add
161 {
162 _workItem.OnWorkItemCompleted += value;
163 }
164 remove
165 {
166 _workItem.OnWorkItemCompleted -= value;
167 }
168 }
169
170 #endregion
171
172 #region IInternalWorkItemResult Members
173
174 public IWorkItemResult GetWorkItemResult()
175 {
176 return this;
177 }
178
179 public IWorkItemResult<TResult> GetWorkItemResultT<TResult>()
180 {
181 return new WorkItemResultTWrapper<TResult>(this);
182 }
183
184 #endregion
185 }
186
187 #endregion
188
189 }
190}
diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs
index d0c0524..f229d1f 100644
--- a/ThirdParty/SmartThreadPool/WorkItem.cs
+++ b/ThirdParty/SmartThreadPool/WorkItem.cs
@@ -1,58 +1,13 @@
1// Ami Bar
2// amibar@gmail.com
3
4using System; 1using System;
5using System.Threading; 2using System.Threading;
6using System.Diagnostics; 3using System.Diagnostics;
7 4
8namespace Amib.Threading.Internal 5namespace Amib.Threading.Internal
9{ 6{
10 #region WorkItem Delegate
11
12 /// <summary>
13 /// An internal delegate to call when the WorkItem starts or completes
14 /// </summary>
15 internal delegate void WorkItemStateCallback(WorkItem workItem);
16
17 #endregion
18
19 #region IInternalWorkItemResult interface
20
21 public class CanceledWorkItemsGroup
22 {
23 public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
24
25 private bool _isCanceled = false;
26 public bool IsCanceled
27 {
28 get { return _isCanceled; }
29 set { _isCanceled = value; }
30 }
31 }
32
33 internal interface IInternalWorkItemResult
34 {
35 event WorkItemStateCallback OnWorkItemStarted;
36 event WorkItemStateCallback OnWorkItemCompleted;
37 }
38
39 #endregion
40
41 #region IWorkItem interface
42
43 public interface IWorkItem
44 {
45
46 }
47
48 #endregion
49
50 #region WorkItem class
51
52 /// <summary> 7 /// <summary>
53 /// Holds a callback delegate and the state for that delegate. 8 /// Holds a callback delegate and the state for that delegate.
54 /// </summary> 9 /// </summary>
55 public class WorkItem : IHasWorkItemPriority, IWorkItem 10 public partial class WorkItem : IHasWorkItemPriority
56 { 11 {
57 #region WorkItemState enum 12 #region WorkItemState enum
58 13
@@ -61,33 +16,57 @@ namespace Amib.Threading.Internal
61 /// </summary> 16 /// </summary>
62 private enum WorkItemState 17 private enum WorkItemState
63 { 18 {
64 InQueue, 19 InQueue = 0, // Nexts: InProgress, Canceled
65 InProgress, 20 InProgress = 1, // Nexts: Completed, Canceled
66 Completed, 21 Completed = 2, // Stays Completed
67 Canceled, 22 Canceled = 3, // Stays Canceled
68 } 23 }
69 24
70 #endregion 25 private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
26 {
27 bool valid = false;
28
29 switch (currentState)
30 {
31 case WorkItemState.InQueue:
32 valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
33 break;
34 case WorkItemState.InProgress:
35 valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
36 break;
37 case WorkItemState.Completed:
38 case WorkItemState.Canceled:
39 // Cannot be changed
40 break;
41 default:
42 // Unknown state
43 Debug.Assert(false);
44 break;
45 }
71 46
72 #region Member Variables 47 return valid;
48 }
73 49
74 public Thread currentThread; 50 #endregion
51
52 #region Fields
75 53
76 /// <summary> 54 /// <summary>
77 /// Callback delegate for the callback. 55 /// Callback delegate for the callback.
78 /// </summary> 56 /// </summary>
79 private WorkItemCallback _callback; 57 private readonly WorkItemCallback _callback;
80 58
81 /// <summary> 59 /// <summary>
82 /// State with which to call the callback delegate. 60 /// State with which to call the callback delegate.
83 /// </summary> 61 /// </summary>
84 private object _state; 62 private object _state;
85 63
64#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
86 /// <summary> 65 /// <summary>
87 /// Stores the caller's context 66 /// Stores the caller's context
88 /// </summary> 67 /// </summary>
89 private CallerThreadContext _callerContext; 68 private readonly CallerThreadContext _callerContext;
90 69#endif
91 /// <summary> 70 /// <summary>
92 /// Holds the result of the mehtod 71 /// Holds the result of the mehtod
93 /// </summary> 72 /// </summary>
@@ -117,12 +96,12 @@ namespace Amib.Threading.Internal
117 /// <summary> 96 /// <summary>
118 /// Represents the result state of the work item 97 /// Represents the result state of the work item
119 /// </summary> 98 /// </summary>
120 private WorkItemResult _workItemResult; 99 private readonly WorkItemResult _workItemResult;
121 100
122 /// <summary> 101 /// <summary>
123 /// Work item info 102 /// Work item info
124 /// </summary> 103 /// </summary>
125 private WorkItemInfo _workItemInfo; 104 private readonly WorkItemInfo _workItemInfo;
126 105
127 /// <summary> 106 /// <summary>
128 /// Called when the WorkItem starts 107 /// Called when the WorkItem starts
@@ -141,30 +120,41 @@ namespace Amib.Threading.Internal
141 private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; 120 private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
142 121
143 /// <summary> 122 /// <summary>
123 /// A reference to an object that indicates whatever the
124 /// SmartThreadPool has been canceled
125 /// </summary>
126 private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
127
128 /// <summary>
144 /// The work item group this work item belong to. 129 /// The work item group this work item belong to.
145 ///
146 /// </summary> 130 /// </summary>
147 private IWorkItemsGroup _workItemsGroup; 131 private readonly IWorkItemsGroup _workItemsGroup;
148 132
149 #region Performance Counter fields 133 /// <summary>
134 /// The thread that executes this workitem.
135 /// This field is available for the period when the work item is executed, before and after it is null.
136 /// </summary>
137 private Thread _executingThread;
150 138
151 /// <summary> 139 /// <summary>
152 /// The time when the work items is queued. 140 /// The absulote time when the work item will be timeout
153 /// Used with the performance counter.
154 /// </summary> 141 /// </summary>
155 private DateTime _queuedTime; 142 private long _expirationTime;
143
144 #region Performance Counter fields
145
146
147
156 148
157 /// <summary> 149 /// <summary>
158 /// The time when the work items starts its execution. 150 /// Stores how long the work item waited on the stp queue
159 /// Used with the performance counter.
160 /// </summary> 151 /// </summary>
161 private DateTime _beginProcessTime; 152 private Stopwatch _waitingOnQueueStopwatch;
162 153
163 /// <summary> 154 /// <summary>
164 /// The time when the work items ends its execution. 155 /// Stores how much time it took the work item to execute after it went out of the queue
165 /// Used with the performance counter.
166 /// </summary> 156 /// </summary>
167 private DateTime _endProcessTime; 157 private Stopwatch _processingStopwatch;
168 158
169 #endregion 159 #endregion
170 160
@@ -174,17 +164,25 @@ namespace Amib.Threading.Internal
174 164
175 public TimeSpan WaitingTime 165 public TimeSpan WaitingTime
176 { 166 {
177 get 167 get
178 { 168 {
179 return (_beginProcessTime - _queuedTime); 169 return _waitingOnQueueStopwatch.Elapsed;
180 } 170 }
181 } 171 }
182 172
183 public TimeSpan ProcessTime 173 public TimeSpan ProcessTime
184 { 174 {
185 get 175 get
176 {
177 return _processingStopwatch.Elapsed;
178 }
179 }
180
181 internal WorkItemInfo WorkItemInfo
182 {
183 get
186 { 184 {
187 return (_endProcessTime - _beginProcessTime); 185 return _workItemInfo;
188 } 186 }
189 } 187 }
190 188
@@ -195,6 +193,8 @@ namespace Amib.Threading.Internal
195 /// <summary> 193 /// <summary>
196 /// Initialize the callback holding object. 194 /// Initialize the callback holding object.
197 /// </summary> 195 /// </summary>
196 /// <param name="workItemsGroup">The workItemGroup of the workitem</param>
197 /// <param name="workItemInfo">The WorkItemInfo of te workitem</param>
198 /// <param name="callback">Callback delegate for the callback.</param> 198 /// <param name="callback">Callback delegate for the callback.</param>
199 /// <param name="state">State with which to call the callback delegate.</param> 199 /// <param name="state">State with which to call the callback delegate.</param>
200 /// 200 ///
@@ -203,16 +203,18 @@ namespace Amib.Threading.Internal
203 public WorkItem( 203 public WorkItem(
204 IWorkItemsGroup workItemsGroup, 204 IWorkItemsGroup workItemsGroup,
205 WorkItemInfo workItemInfo, 205 WorkItemInfo workItemInfo,
206 WorkItemCallback callback, 206 WorkItemCallback callback,
207 object state) 207 object state)
208 { 208 {
209 _workItemsGroup = workItemsGroup; 209 _workItemsGroup = workItemsGroup;
210 _workItemInfo = workItemInfo; 210 _workItemInfo = workItemInfo;
211 211
212#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
212 if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext) 213 if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
213 { 214 {
214 _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext); 215 _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
215 } 216 }
217#endif
216 218
217 _callback = callback; 219 _callback = callback;
218 _state = state; 220 _state = state;
@@ -222,9 +224,18 @@ namespace Amib.Threading.Internal
222 224
223 internal void Initialize() 225 internal void Initialize()
224 { 226 {
227 // The _workItemState is changed directly instead of using the SetWorkItemState
228 // method since we don't want to go throught IsValidStateTransition.
225 _workItemState = WorkItemState.InQueue; 229 _workItemState = WorkItemState.InQueue;
230
226 _workItemCompleted = null; 231 _workItemCompleted = null;
227 _workItemCompletedRefCount = 0; 232 _workItemCompletedRefCount = 0;
233 _waitingOnQueueStopwatch = new Stopwatch();
234 _processingStopwatch = new Stopwatch();
235 _expirationTime =
236 _workItemInfo.Timeout > 0 ?
237 DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
238 long.MaxValue;
228 } 239 }
229 240
230 internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup) 241 internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
@@ -237,17 +248,16 @@ namespace Amib.Threading.Internal
237 248
238 #region Methods 249 #region Methods
239 250
240 public CanceledWorkItemsGroup CanceledWorkItemsGroup 251 internal CanceledWorkItemsGroup CanceledWorkItemsGroup
241 { 252 {
242 get 253 get { return _canceledWorkItemsGroup; }
243 { 254 set { _canceledWorkItemsGroup = value; }
244 return _canceledWorkItemsGroup; 255 }
245 }
246 256
247 set 257 internal CanceledWorkItemsGroup CanceledSmartThreadPool
248 { 258 {
249 _canceledWorkItemsGroup = value; 259 get { return _canceledSmartThreadPool; }
250 } 260 set { _canceledSmartThreadPool = value; }
251 } 261 }
252 262
253 /// <summary> 263 /// <summary>
@@ -259,9 +269,10 @@ namespace Amib.Threading.Internal
259 /// </returns> 269 /// </returns>
260 public bool StartingWorkItem() 270 public bool StartingWorkItem()
261 { 271 {
262 _beginProcessTime = DateTime.Now; 272 _waitingOnQueueStopwatch.Stop();
273 _processingStopwatch.Start();
263 274
264 lock(this) 275 lock (this)
265 { 276 {
266 if (IsCanceled) 277 if (IsCanceled)
267 { 278 {
@@ -277,6 +288,9 @@ namespace Amib.Threading.Internal
277 288
278 Debug.Assert(WorkItemState.InQueue == GetWorkItemState()); 289 Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
279 290
291 // No need for a lock yet, only after the state has changed to InProgress
292 _executingThread = Thread.CurrentThread;
293
280 SetWorkItemState(WorkItemState.InProgress); 294 SetWorkItemState(WorkItemState.InProgress);
281 } 295 }
282 296
@@ -291,7 +305,7 @@ namespace Amib.Threading.Internal
291 CallToPostExecute currentCallToPostExecute = 0; 305 CallToPostExecute currentCallToPostExecute = 0;
292 306
293 // Execute the work item if we are in the correct state 307 // Execute the work item if we are in the correct state
294 switch(GetWorkItemState()) 308 switch (GetWorkItemState())
295 { 309 {
296 case WorkItemState.InProgress: 310 case WorkItemState.InProgress:
297 currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled; 311 currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled;
@@ -311,7 +325,7 @@ namespace Amib.Threading.Internal
311 PostExecute(); 325 PostExecute();
312 } 326 }
313 327
314 _endProcessTime = DateTime.Now; 328 _processingStopwatch.Stop();
315 } 329 }
316 330
317 internal void FireWorkItemCompleted() 331 internal void FireWorkItemCompleted()
@@ -323,8 +337,21 @@ namespace Amib.Threading.Internal
323 _workItemCompletedEvent(this); 337 _workItemCompletedEvent(this);
324 } 338 }
325 } 339 }
326 catch // Ignore exceptions 340 catch // Suppress exceptions
327 {} 341 { }
342 }
343
344 internal void FireWorkItemStarted()
345 {
346 try
347 {
348 if (null != _workItemStartedEvent)
349 {
350 _workItemStartedEvent(this);
351 }
352 }
353 catch // Suppress exceptions
354 { }
328 } 355 }
329 356
330 /// <summary> 357 /// <summary>
@@ -332,32 +359,70 @@ namespace Amib.Threading.Internal
332 /// </summary> 359 /// </summary>
333 private void ExecuteWorkItem() 360 private void ExecuteWorkItem()
334 { 361 {
362
363#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
335 CallerThreadContext ctc = null; 364 CallerThreadContext ctc = null;
336 if (null != _callerContext) 365 if (null != _callerContext)
337 { 366 {
338 ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext); 367 ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
339 CallerThreadContext.Apply(_callerContext); 368 CallerThreadContext.Apply(_callerContext);
340 } 369 }
370#endif
341 371
342 Exception exception = null; 372 Exception exception = null;
343 object result = null; 373 object result = null;
344 374
345 try 375 try
346 { 376 {
347 result = _callback(_state); 377 try
378 {
379 result = _callback(_state);
380 }
381 catch (Exception e)
382 {
383 // Save the exception so we can rethrow it later
384 exception = e;
385 }
386
387 // Remove the value of the execution thread, so it will be impossible to cancel the work item,
388 // since it is already completed.
389 // Cancelling a work item that already completed may cause the abortion of the next work item!!!
390 Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
391
392 if (null == executionThread)
393 {
394 // Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
395 Thread.Sleep(60 * 1000);
396
397 // If after 1 minute this thread was not aborted then let it continue working.
398 }
348 } 399 }
349 catch (Exception e) 400 // We must treat the ThreadAbortException or else it will be stored in the exception variable
401 catch (ThreadAbortException tae)
350 { 402 {
351 // Save the exception so we can rethrow it later 403 tae.GetHashCode();
352 exception = e; 404 // Check if the work item was cancelled
405 // If we got a ThreadAbortException and the STP is not shutting down, it means the
406 // work items was cancelled.
407 if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown)
408 {
409#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
410 Thread.ResetAbort();
411#endif
412 }
353 } 413 }
354 414
415#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
355 if (null != _callerContext) 416 if (null != _callerContext)
356 { 417 {
357 CallerThreadContext.Apply(ctc); 418 CallerThreadContext.Apply(ctc);
358 } 419 }
420#endif
359 421
360 SetResult(result, exception); 422 if (!SmartThreadPool.IsWorkItemCanceled)
423 {
424 SetResult(result, exception);
425 }
361 } 426 }
362 427
363 /// <summary> 428 /// <summary>
@@ -369,9 +434,9 @@ namespace Amib.Threading.Internal
369 { 434 {
370 try 435 try
371 { 436 {
372 _workItemInfo.PostExecuteWorkItemCallback(this._workItemResult); 437 _workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
373 } 438 }
374 catch (Exception e) 439 catch (Exception e)
375 { 440 {
376 Debug.Assert(null != e); 441 Debug.Assert(null != e);
377 } 442 }
@@ -382,6 +447,8 @@ namespace Amib.Threading.Internal
382 /// Set the result of the work item to return 447 /// Set the result of the work item to return
383 /// </summary> 448 /// </summary>
384 /// <param name="result">The result of the work item</param> 449 /// <param name="result">The result of the work item</param>
450 /// <param name="exception">The exception that was throw while the workitem executed, null
451 /// if there was no exception.</param>
385 internal void SetResult(object result, Exception exception) 452 internal void SetResult(object result, Exception exception)
386 { 453 {
387 _result = result; 454 _result = result;
@@ -401,48 +468,48 @@ namespace Amib.Threading.Internal
401 /// <summary> 468 /// <summary>
402 /// Wait for all work items to complete 469 /// Wait for all work items to complete
403 /// </summary> 470 /// </summary>
404 /// <param name="workItemResults">Array of work item result objects</param> 471 /// <param name="waitableResults">Array of work item result objects</param>
405 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 472 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
406 /// <param name="exitContext"> 473 /// <param name="exitContext">
407 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 474 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
408 /// </param> 475 /// </param>
409 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 476 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
410 /// <returns> 477 /// <returns>
411 /// true when every work item in workItemResults has completed; otherwise false. 478 /// true when every work item in waitableResults has completed; otherwise false.
412 /// </returns> 479 /// </returns>
413 internal static bool WaitAll( 480 internal static bool WaitAll(
414 IWorkItemResult [] workItemResults, 481 IWaitableResult[] waitableResults,
415 int millisecondsTimeout, 482 int millisecondsTimeout,
416 bool exitContext, 483 bool exitContext,
417 WaitHandle cancelWaitHandle) 484 WaitHandle cancelWaitHandle)
418 { 485 {
419 if (0 == workItemResults.Length) 486 if (0 == waitableResults.Length)
420 { 487 {
421 return true; 488 return true;
422 } 489 }
423 490
424 bool success; 491 bool success;
425 WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];; 492 WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
426 GetWaitHandles(workItemResults, waitHandles); 493 GetWaitHandles(waitableResults, waitHandles);
427 494
428 if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) 495 if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
429 { 496 {
430 success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); 497 success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
431 } 498 }
432 else 499 else
433 { 500 {
434 success = true; 501 success = true;
435 int millisecondsLeft = millisecondsTimeout; 502 int millisecondsLeft = millisecondsTimeout;
436 DateTime start = DateTime.Now; 503 Stopwatch stopwatch = Stopwatch.StartNew();
437 504
438 WaitHandle [] whs; 505 WaitHandle[] whs;
439 if (null != cancelWaitHandle) 506 if (null != cancelWaitHandle)
440 { 507 {
441 whs = new WaitHandle [] { null, cancelWaitHandle }; 508 whs = new WaitHandle[] { null, cancelWaitHandle };
442 } 509 }
443 else 510 else
444 { 511 {
445 whs = new WaitHandle [] { null }; 512 whs = new WaitHandle[] { null };
446 } 513 }
447 514
448 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); 515 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
@@ -450,7 +517,7 @@ namespace Amib.Threading.Internal
450 // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle 517 // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
451 // won't affect it. 518 // won't affect it.
452 // Each iteration we update the time left for the timeout. 519 // Each iteration we update the time left for the timeout.
453 for(int i = 0; i < workItemResults.Length; ++i) 520 for (int i = 0; i < waitableResults.Length; ++i)
454 { 521 {
455 // WaitAny don't work with negative numbers 522 // WaitAny don't work with negative numbers
456 if (!waitInfinitely && (millisecondsLeft < 0)) 523 if (!waitInfinitely && (millisecondsLeft < 0))
@@ -460,23 +527,22 @@ namespace Amib.Threading.Internal
460 } 527 }
461 528
462 whs[0] = waitHandles[i]; 529 whs[0] = waitHandles[i];
463 int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext); 530 int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
464 if((result > 0) || (WaitHandle.WaitTimeout == result)) 531 if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result))
465 { 532 {
466 success = false; 533 success = false;
467 break; 534 break;
468 } 535 }
469 536
470 if(!waitInfinitely) 537 if (!waitInfinitely)
471 { 538 {
472 // Update the time left to wait 539 // Update the time left to wait
473 TimeSpan ts = DateTime.Now - start; 540 millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
474 millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
475 } 541 }
476 } 542 }
477 } 543 }
478 // Release the wait handles 544 // Release the wait handles
479 ReleaseWaitHandles(workItemResults); 545 ReleaseWaitHandles(waitableResults);
480 546
481 return success; 547 return success;
482 } 548 }
@@ -484,7 +550,7 @@ namespace Amib.Threading.Internal
484 /// <summary> 550 /// <summary>
485 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 551 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
486 /// </summary> 552 /// </summary>
487 /// <param name="workItemResults">Array of work item result objects</param> 553 /// <param name="waitableResults">Array of work item result objects</param>
488 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 554 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
489 /// <param name="exitContext"> 555 /// <param name="exitContext">
490 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 556 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
@@ -493,38 +559,38 @@ namespace Amib.Threading.Internal
493 /// <returns> 559 /// <returns>
494 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 560 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
495 /// </returns> 561 /// </returns>
496 internal static int WaitAny( 562 internal static int WaitAny(
497 IWorkItemResult [] workItemResults, 563 IWaitableResult[] waitableResults,
498 int millisecondsTimeout, 564 int millisecondsTimeout,
499 bool exitContext, 565 bool exitContext,
500 WaitHandle cancelWaitHandle) 566 WaitHandle cancelWaitHandle)
501 { 567 {
502 WaitHandle [] waitHandles = null; 568 WaitHandle[] waitHandles;
503 569
504 if (null != cancelWaitHandle) 570 if (null != cancelWaitHandle)
505 { 571 {
506 waitHandles = new WaitHandle[workItemResults.Length+1]; 572 waitHandles = new WaitHandle[waitableResults.Length + 1];
507 GetWaitHandles(workItemResults, waitHandles); 573 GetWaitHandles(waitableResults, waitHandles);
508 waitHandles[workItemResults.Length] = cancelWaitHandle; 574 waitHandles[waitableResults.Length] = cancelWaitHandle;
509 } 575 }
510 else 576 else
511 { 577 {
512 waitHandles = new WaitHandle[workItemResults.Length]; 578 waitHandles = new WaitHandle[waitableResults.Length];
513 GetWaitHandles(workItemResults, waitHandles); 579 GetWaitHandles(waitableResults, waitHandles);
514 } 580 }
515 581
516 int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); 582 int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
517 583
518 // Treat cancel as timeout 584 // Treat cancel as timeout
519 if (null != cancelWaitHandle) 585 if (null != cancelWaitHandle)
520 { 586 {
521 if (result == workItemResults.Length) 587 if (result == waitableResults.Length)
522 { 588 {
523 result = WaitHandle.WaitTimeout; 589 result = STPEventWaitHandle.WaitTimeout;
524 } 590 }
525 } 591 }
526 592
527 ReleaseWaitHandles(workItemResults); 593 ReleaseWaitHandles(waitableResults);
528 594
529 return result; 595 return result;
530 } 596 }
@@ -532,16 +598,16 @@ namespace Amib.Threading.Internal
532 /// <summary> 598 /// <summary>
533 /// Fill an array of wait handles with the work items wait handles. 599 /// Fill an array of wait handles with the work items wait handles.
534 /// </summary> 600 /// </summary>
535 /// <param name="workItemResults">An array of work item results</param> 601 /// <param name="waitableResults">An array of work item results</param>
536 /// <param name="waitHandles">An array of wait handles to fill</param> 602 /// <param name="waitHandles">An array of wait handles to fill</param>
537 private static void GetWaitHandles( 603 private static void GetWaitHandles(
538 IWorkItemResult [] workItemResults, 604 IWaitableResult[] waitableResults,
539 WaitHandle [] waitHandles) 605 WaitHandle[] waitHandles)
540 { 606 {
541 for(int i = 0; i < workItemResults.Length; ++i) 607 for (int i = 0; i < waitableResults.Length; ++i)
542 { 608 {
543 WorkItemResult wir = workItemResults[i] as WorkItemResult; 609 WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
544 Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects"); 610 Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
545 611
546 waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); 612 waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
547 } 613 }
@@ -550,40 +616,64 @@ namespace Amib.Threading.Internal
550 /// <summary> 616 /// <summary>
551 /// Release the work items' wait handles 617 /// Release the work items' wait handles
552 /// </summary> 618 /// </summary>
553 /// <param name="workItemResults">An array of work item results</param> 619 /// <param name="waitableResults">An array of work item results</param>
554 private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults) 620 private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
555 { 621 {
556 for(int i = 0; i < workItemResults.Length; ++i) 622 for (int i = 0; i < waitableResults.Length; ++i)
557 { 623 {
558 WorkItemResult wir = workItemResults[i] as WorkItemResult; 624 WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
559 625
560 wir.GetWorkItem().ReleaseWaitHandle(); 626 wir.GetWorkItem().ReleaseWaitHandle();
561 } 627 }
562 } 628 }
563 629
564
565 #endregion 630 #endregion
566 631
567 #region Private Members 632 #region Private Members
568 633
569 private WorkItemState GetWorkItemState() 634 private WorkItemState GetWorkItemState()
570 { 635 {
571 if (_canceledWorkItemsGroup.IsCanceled) 636 lock (this)
572 { 637 {
573 return WorkItemState.Canceled; 638 if (WorkItemState.Completed == _workItemState)
574 } 639 {
575 return _workItemState; 640 return _workItemState;
641 }
642
643 long nowTicks = DateTime.UtcNow.Ticks;
576 644
645 if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
646 {
647 _workItemState = WorkItemState.Canceled;
648 }
649
650 if (WorkItemState.InProgress == _workItemState)
651 {
652 return _workItemState;
653 }
654
655 if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
656 {
657 return WorkItemState.Canceled;
658 }
659
660 return _workItemState;
661 }
577 } 662 }
663
664
578 /// <summary> 665 /// <summary>
579 /// Sets the work item's state 666 /// Sets the work item's state
580 /// </summary> 667 /// </summary>
581 /// <param name="workItemState">The state to set the work item to</param> 668 /// <param name="workItemState">The state to set the work item to</param>
582 private void SetWorkItemState(WorkItemState workItemState) 669 private void SetWorkItemState(WorkItemState workItemState)
583 { 670 {
584 lock(this) 671 lock (this)
585 { 672 {
586 _workItemState = workItemState; 673 if (IsValidStatesTransition(_workItemState, workItemState))
674 {
675 _workItemState = workItemState;
676 }
587 } 677 }
588 } 678 }
589 679
@@ -594,7 +684,7 @@ namespace Amib.Threading.Internal
594 private void SignalComplete(bool canceled) 684 private void SignalComplete(bool canceled)
595 { 685 {
596 SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed); 686 SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed);
597 lock(this) 687 lock (this)
598 { 688 {
599 // If someone is waiting then signal. 689 // If someone is waiting then signal.
600 if (null != _workItemCompleted) 690 if (null != _workItemCompleted)
@@ -606,40 +696,83 @@ namespace Amib.Threading.Internal
606 696
607 internal void WorkItemIsQueued() 697 internal void WorkItemIsQueued()
608 { 698 {
609 _queuedTime = DateTime.Now; 699 _waitingOnQueueStopwatch.Start();
610 } 700 }
611 701
612 #endregion 702 #endregion
613 703
614 #region Members exposed by WorkItemResult 704 #region Members exposed by WorkItemResult
615 705
616 /// <summary> 706 /// <summary>
617 /// Cancel the work item if it didn't start running yet. 707 /// Cancel the work item if it didn't start running yet.
618 /// </summary> 708 /// </summary>
619 /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> 709 /// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
620 private bool Cancel() 710 private bool Cancel(bool abortExecution)
621 { 711 {
622 lock(this) 712#if (_WINDOWS_CE)
713 if(abortExecution)
714 {
715 throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
716 }
717#endif
718 bool success = false;
719 bool signalComplete = false;
720
721 lock (this)
623 { 722 {
624 switch(GetWorkItemState()) 723 switch (GetWorkItemState())
625 { 724 {
626 case WorkItemState.Canceled: 725 case WorkItemState.Canceled:
627 //Debug.WriteLine("Work item already canceled"); 726 //Debug.WriteLine("Work item already canceled");
628 return true; 727 if (abortExecution)
728 {
729 Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
730 if (null != executionThread)
731 {
732 executionThread.Abort(); // "Cancel"
733 // No need to signalComplete, because we already cancelled this work item
734 // so it already signaled its completion.
735 //signalComplete = true;
736 }
737 }
738 success = true;
739 break;
629 case WorkItemState.Completed: 740 case WorkItemState.Completed:
630 case WorkItemState.InProgress:
631 //Debug.WriteLine("Work item cannot be canceled"); 741 //Debug.WriteLine("Work item cannot be canceled");
632 return false; 742 break;
743 case WorkItemState.InProgress:
744 if (abortExecution)
745 {
746 Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
747 if (null != executionThread)
748 {
749 executionThread.Abort(); // "Cancel"
750 success = true;
751 signalComplete = true;
752 }
753 }
754 else
755 {
756 success = false;
757 signalComplete = false;
758 }
759 break;
633 case WorkItemState.InQueue: 760 case WorkItemState.InQueue:
634 // Signal to the wait for completion that the work 761 // Signal to the wait for completion that the work
635 // item has been completed (canceled). There is no 762 // item has been completed (canceled). There is no
636 // reason to wait for it to get out of the queue 763 // reason to wait for it to get out of the queue
637 SignalComplete(true); 764 signalComplete = true;
638 //Debug.WriteLine("Work item canceled"); 765 //Debug.WriteLine("Work item canceled");
639 return true; 766 success = true;
767 break;
768 }
769
770 if (signalComplete)
771 {
772 SignalComplete(true);
640 } 773 }
641 } 774 }
642 return false; 775 return success;
643 } 776 }
644 777
645 /// <summary> 778 /// <summary>
@@ -653,7 +786,7 @@ namespace Amib.Threading.Internal
653 bool exitContext, 786 bool exitContext,
654 WaitHandle cancelWaitHandle) 787 WaitHandle cancelWaitHandle)
655 { 788 {
656 Exception e = null; 789 Exception e;
657 object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); 790 object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
658 if (null != e) 791 if (null != e)
659 { 792 {
@@ -694,7 +827,7 @@ namespace Amib.Threading.Internal
694 { 827 {
695 WaitHandle wh = GetWaitHandle(); 828 WaitHandle wh = GetWaitHandle();
696 829
697 bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext); 830 bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);
698 831
699 ReleaseWaitHandle(); 832 ReleaseWaitHandle();
700 833
@@ -706,10 +839,10 @@ namespace Amib.Threading.Internal
706 else 839 else
707 { 840 {
708 WaitHandle wh = GetWaitHandle(); 841 WaitHandle wh = GetWaitHandle();
709 int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); 842 int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
710 ReleaseWaitHandle(); 843 ReleaseWaitHandle();
711 844
712 switch(result) 845 switch (result)
713 { 846 {
714 case 0: 847 case 0:
715 // The work item signaled 848 // The work item signaled
@@ -717,7 +850,7 @@ namespace Amib.Threading.Internal
717 // work item (not the get result) 850 // work item (not the get result)
718 break; 851 break;
719 case 1: 852 case 1:
720 case WaitHandle.WaitTimeout: 853 case STPEventWaitHandle.WaitTimeout:
721 throw new WorkItemTimeoutException("Work item timeout"); 854 throw new WorkItemTimeoutException("Work item timeout");
722 default: 855 default:
723 Debug.Assert(false); 856 Debug.Assert(false);
@@ -745,11 +878,11 @@ namespace Amib.Threading.Internal
745 /// </summary> 878 /// </summary>
746 private WaitHandle GetWaitHandle() 879 private WaitHandle GetWaitHandle()
747 { 880 {
748 lock(this) 881 lock (this)
749 { 882 {
750 if (null == _workItemCompleted) 883 if (null == _workItemCompleted)
751 { 884 {
752 _workItemCompleted = new ManualResetEvent(IsCompleted); 885 _workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
753 } 886 }
754 ++_workItemCompletedRefCount; 887 ++_workItemCompletedRefCount;
755 } 888 }
@@ -758,7 +891,7 @@ namespace Amib.Threading.Internal
758 891
759 private void ReleaseWaitHandle() 892 private void ReleaseWaitHandle()
760 { 893 {
761 lock(this) 894 lock (this)
762 { 895 {
763 if (null != _workItemCompleted) 896 if (null != _workItemCompleted)
764 { 897 {
@@ -779,10 +912,10 @@ namespace Amib.Threading.Internal
779 { 912 {
780 get 913 get
781 { 914 {
782 lock(this) 915 lock (this)
783 { 916 {
784 WorkItemState workItemState = GetWorkItemState(); 917 WorkItemState workItemState = GetWorkItemState();
785 return ((workItemState == WorkItemState.Completed) || 918 return ((workItemState == WorkItemState.Completed) ||
786 (workItemState == WorkItemState.Canceled)); 919 (workItemState == WorkItemState.Canceled));
787 } 920 }
788 } 921 }
@@ -795,7 +928,7 @@ namespace Amib.Threading.Internal
795 { 928 {
796 get 929 get
797 { 930 {
798 lock(this) 931 lock (this)
799 { 932 {
800 return (GetWorkItemState() == WorkItemState.Canceled); 933 return (GetWorkItemState() == WorkItemState.Canceled);
801 } 934 }
@@ -843,172 +976,6 @@ namespace Amib.Threading.Internal
843 } 976 }
844 } 977 }
845 978
846
847 #region WorkItemResult class
848
849 private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult
850 {
851 /// <summary>
852 /// A back reference to the work item
853 /// </summary>
854 private WorkItem _workItem;
855
856 public WorkItemResult(WorkItem workItem)
857 {
858 _workItem = workItem;
859 }
860
861 internal WorkItem GetWorkItem()
862 {
863 return _workItem;
864 }
865
866 #region IWorkItemResult Members
867
868 public bool IsCompleted
869 {
870 get
871 {
872 return _workItem.IsCompleted;
873 }
874 }
875
876 public void Abort()
877 {
878 _workItem.Abort();
879 }
880
881 public bool IsCanceled
882 {
883 get
884 {
885 return _workItem.IsCanceled;
886 }
887 }
888
889 public object GetResult()
890 {
891 return _workItem.GetResult(Timeout.Infinite, true, null);
892 }
893
894 public object GetResult(int millisecondsTimeout, bool exitContext)
895 {
896 return _workItem.GetResult(millisecondsTimeout, exitContext, null);
897 }
898
899 public object GetResult(TimeSpan timeout, bool exitContext)
900 {
901 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
902 }
903
904 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
905 {
906 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
907 }
908
909 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
910 {
911 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
912 }
913
914 public object GetResult(out Exception e)
915 {
916 return _workItem.GetResult(Timeout.Infinite, true, null, out e);
917 }
918
919 public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
920 {
921 return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
922 }
923
924 public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
925 {
926 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
927 }
928
929 public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
930 {
931 return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
932 }
933
934 public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
935 {
936 return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
937 }
938
939 public bool Cancel()
940 {
941 return _workItem.Cancel();
942 }
943
944 public object State
945 {
946 get
947 {
948 return _workItem._state;
949 }
950 }
951
952 public WorkItemPriority WorkItemPriority
953 {
954 get
955 {
956 return _workItem._workItemInfo.WorkItemPriority;
957 }
958 }
959
960 /// <summary>
961 /// Return the result, same as GetResult()
962 /// </summary>
963 public object Result
964 {
965 get { return GetResult(); }
966 }
967
968 /// <summary>
969 /// Returns the exception if occured otherwise returns null.
970 /// This value is valid only after the work item completed,
971 /// before that it is always null.
972 /// </summary>
973 public object Exception
974 {
975 get { return _workItem._exception; }
976 }
977
978 #endregion
979
980 #region IInternalWorkItemResult Members
981
982 public event WorkItemStateCallback OnWorkItemStarted
983 {
984 add
985 {
986 _workItem.OnWorkItemStarted += value;
987 }
988 remove
989 {
990 _workItem.OnWorkItemStarted -= value;
991 }
992 }
993
994
995 public event WorkItemStateCallback OnWorkItemCompleted
996 {
997 add
998 {
999 _workItem.OnWorkItemCompleted += value;
1000 }
1001 remove
1002 {
1003 _workItem.OnWorkItemCompleted -= value;
1004 }
1005 }
1006
1007 #endregion
1008 }
1009
1010 #endregion
1011
1012 public void DisposeOfState() 979 public void DisposeOfState()
1013 { 980 {
1014 if (_workItemInfo.DisposeOfStateObjects) 981 if (_workItemInfo.DisposeOfStateObjects)
@@ -1021,15 +988,5 @@ namespace Amib.Threading.Internal
1021 } 988 }
1022 } 989 }
1023 } 990 }
1024
1025 public void Abort()
1026 {
1027 lock (this)
1028 {
1029 if(currentThread != null)
1030 currentThread.Abort();
1031 }
1032 }
1033 } 991 }
1034 #endregion
1035} 992}
diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs
index dfcb54f..2d6601e 100644
--- a/ThirdParty/SmartThreadPool/WorkItemFactory.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs
@@ -1,333 +1,343 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2
3 3namespace Amib.Threading.Internal
4using System; 4{
5 5 #region WorkItemFactory class
6namespace Amib.Threading.Internal 6
7{ 7 public class WorkItemFactory
8 #region WorkItemFactory class 8 {
9 9 /// <summary>
10 public class WorkItemFactory 10 /// Create a new work item
11 { 11 /// </summary>
12 /// <summary> 12 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
13 /// Create a new work item 13 /// <param name="wigStartInfo">Work item group start information</param>
14 /// </summary> 14 /// <param name="callback">A callback to execute</param>
15 /// <param name="wigStartInfo">Work item group start information</param> 15 /// <returns>Returns a work item</returns>
16 /// <param name="callback">A callback to execute</param> 16 public static WorkItem CreateWorkItem(
17 /// <returns>Returns a work item</returns> 17 IWorkItemsGroup workItemsGroup,
18 public static WorkItem CreateWorkItem( 18 WIGStartInfo wigStartInfo,
19 IWorkItemsGroup workItemsGroup, 19 WorkItemCallback callback)
20 WIGStartInfo wigStartInfo, 20 {
21 WorkItemCallback callback) 21 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
22 { 22 }
23 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); 23
24 } 24 /// <summary>
25 25 /// Create a new work item
26 /// <summary> 26 /// </summary>
27 /// Create a new work item 27 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
28 /// </summary> 28 /// <param name="wigStartInfo">Work item group start information</param>
29 /// <param name="wigStartInfo">Work item group start information</param> 29 /// <param name="callback">A callback to execute</param>
30 /// <param name="callback">A callback to execute</param> 30 /// <param name="workItemPriority">The priority of the work item</param>
31 /// <param name="workItemPriority">The priority of the work item</param> 31 /// <returns>Returns a work item</returns>
32 /// <returns>Returns a work item</returns> 32 public static WorkItem CreateWorkItem(
33 public static WorkItem CreateWorkItem( 33 IWorkItemsGroup workItemsGroup,
34 IWorkItemsGroup workItemsGroup, 34 WIGStartInfo wigStartInfo,
35 WIGStartInfo wigStartInfo, 35 WorkItemCallback callback,
36 WorkItemCallback callback, 36 WorkItemPriority workItemPriority)
37 WorkItemPriority workItemPriority) 37 {
38 { 38 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
39 return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); 39 }
40 } 40
41 41 /// <summary>
42 /// <summary> 42 /// Create a new work item
43 /// Create a new work item 43 /// </summary>
44 /// </summary> 44 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
45 /// <param name="wigStartInfo">Work item group start information</param> 45 /// <param name="wigStartInfo">Work item group start information</param>
46 /// <param name="workItemInfo">Work item info</param> 46 /// <param name="workItemInfo">Work item info</param>
47 /// <param name="callback">A callback to execute</param> 47 /// <param name="callback">A callback to execute</param>
48 /// <returns>Returns a work item</returns> 48 /// <returns>Returns a work item</returns>
49 public static WorkItem CreateWorkItem( 49 public static WorkItem CreateWorkItem(
50 IWorkItemsGroup workItemsGroup, 50 IWorkItemsGroup workItemsGroup,
51 WIGStartInfo wigStartInfo, 51 WIGStartInfo wigStartInfo,
52 WorkItemInfo workItemInfo, 52 WorkItemInfo workItemInfo,
53 WorkItemCallback callback) 53 WorkItemCallback callback)
54 { 54 {
55 return CreateWorkItem( 55 return CreateWorkItem(
56 workItemsGroup, 56 workItemsGroup,
57 wigStartInfo, 57 wigStartInfo,
58 workItemInfo, 58 workItemInfo,
59 callback, 59 callback,
60 null); 60 null);
61 } 61 }
62 62
63 /// <summary> 63 /// <summary>
64 /// Create a new work item 64 /// Create a new work item
65 /// </summary> 65 /// </summary>
66 /// <param name="wigStartInfo">Work item group start information</param> 66 /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
67 /// <param name="callback">A callback to execute</param> 67 /// <param name="wigStartInfo">Work item group start information</param>
68 /// <param name="state"> 68 /// <param name="callback">A callback to execute</param>
69 /// The context object of the work item. Used for passing arguments to the work item. 69 /// <param name="state">
70 /// </param> 70 /// The context object of the work item. Used for passing arguments to the work item.
71 /// <returns>Returns a work item</returns> 71 /// </param>
72 public static WorkItem CreateWorkItem( 72 /// <returns>Returns a work item</returns>
73 IWorkItemsGroup workItemsGroup, 73 public static WorkItem CreateWorkItem(
74 WIGStartInfo wigStartInfo, 74 IWorkItemsGroup workItemsGroup,
75 WorkItemCallback callback, 75 WIGStartInfo wigStartInfo,
76 object state) 76 WorkItemCallback callback,
77 { 77 object state)
78 ValidateCallback(callback); 78 {
79 79 ValidateCallback(callback);
80 WorkItemInfo workItemInfo = new WorkItemInfo(); 80
81 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 81 WorkItemInfo workItemInfo = new WorkItemInfo();
82 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 82 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
83 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; 83 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
84 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 84 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
85 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 85 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
86 86 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
87 WorkItem workItem = new WorkItem( 87 workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
88 workItemsGroup, 88
89 workItemInfo, 89 WorkItem workItem = new WorkItem(
90 callback, 90 workItemsGroup,
91 state); 91 workItemInfo,
92 return workItem; 92 callback,
93 } 93 state);
94 94 return workItem;
95 /// <summary> 95 }
96 /// Create a new work item 96
97 /// </summary> 97 /// <summary>
98 /// <param name="wigStartInfo">Work item group start information</param> 98 /// Create a new work item
99 /// <param name="callback">A callback to execute</param> 99 /// </summary>
100 /// <param name="state"> 100 /// <param name="workItemsGroup">The work items group</param>
101 /// The context object of the work item. Used for passing arguments to the work item. 101 /// <param name="wigStartInfo">Work item group start information</param>
102 /// </param> 102 /// <param name="callback">A callback to execute</param>
103 /// <param name="workItemPriority">The work item priority</param> 103 /// <param name="state">
104 /// <returns>Returns a work item</returns> 104 /// The context object of the work item. Used for passing arguments to the work item.
105 public static WorkItem CreateWorkItem( 105 /// </param>
106 IWorkItemsGroup workItemsGroup, 106 /// <param name="workItemPriority">The work item priority</param>
107 WIGStartInfo wigStartInfo, 107 /// <returns>Returns a work item</returns>
108 WorkItemCallback callback, 108 public static WorkItem CreateWorkItem(
109 object state, 109 IWorkItemsGroup workItemsGroup,
110 WorkItemPriority workItemPriority) 110 WIGStartInfo wigStartInfo,
111 { 111 WorkItemCallback callback,
112 ValidateCallback(callback); 112 object state,
113 113 WorkItemPriority workItemPriority)
114 WorkItemInfo workItemInfo = new WorkItemInfo(); 114 {
115 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 115 ValidateCallback(callback);
116 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 116
117 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; 117 WorkItemInfo workItemInfo = new WorkItemInfo();
118 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 118 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
119 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 119 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
120 workItemInfo.WorkItemPriority = workItemPriority; 120 workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
121 121 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
122 WorkItem workItem = new WorkItem( 122 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
123 workItemsGroup, 123 workItemInfo.WorkItemPriority = workItemPriority;
124 workItemInfo, 124
125 callback, 125 WorkItem workItem = new WorkItem(
126 state); 126 workItemsGroup,
127 127 workItemInfo,
128 return workItem; 128 callback,
129 } 129 state);
130 130
131 /// <summary> 131 return workItem;
132 /// Create a new work item 132 }
133 /// </summary> 133
134 /// <param name="wigStartInfo">Work item group start information</param> 134 /// <summary>
135 /// <param name="workItemInfo">Work item information</param> 135 /// Create a new work item
136 /// <param name="callback">A callback to execute</param> 136 /// </summary>
137 /// <param name="state"> 137 /// <param name="workItemsGroup">The work items group</param>
138 /// The context object of the work item. Used for passing arguments to the work item. 138 /// <param name="wigStartInfo">Work item group start information</param>
139 /// </param> 139 /// <param name="workItemInfo">Work item information</param>
140 /// <returns>Returns a work item</returns> 140 /// <param name="callback">A callback to execute</param>
141 public static WorkItem CreateWorkItem( 141 /// <param name="state">
142 IWorkItemsGroup workItemsGroup, 142 /// The context object of the work item. Used for passing arguments to the work item.
143 WIGStartInfo wigStartInfo, 143 /// </param>
144 WorkItemInfo workItemInfo, 144 /// <returns>Returns a work item</returns>
145 WorkItemCallback callback, 145 public static WorkItem CreateWorkItem(
146 object state) 146 IWorkItemsGroup workItemsGroup,
147 { 147 WIGStartInfo wigStartInfo,
148 ValidateCallback(callback); 148 WorkItemInfo workItemInfo,
149 ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); 149 WorkItemCallback callback,
150 150 object state)
151 WorkItem workItem = new WorkItem( 151 {
152 workItemsGroup, 152 ValidateCallback(callback);
153 new WorkItemInfo(workItemInfo), 153 ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
154 callback, 154
155 state); 155 WorkItem workItem = new WorkItem(
156 156 workItemsGroup,
157 return workItem; 157 new WorkItemInfo(workItemInfo),
158 } 158 callback,
159 159 state);
160 /// <summary> 160
161 /// Create a new work item 161 return workItem;
162 /// </summary> 162 }
163 /// <param name="wigStartInfo">Work item group start information</param> 163
164 /// <param name="callback">A callback to execute</param> 164 /// <summary>
165 /// <param name="state"> 165 /// Create a new work item
166 /// The context object of the work item. Used for passing arguments to the work item. 166 /// </summary>
167 /// </param> 167 /// <param name="workItemsGroup">The work items group</param>
168 /// <param name="postExecuteWorkItemCallback"> 168 /// <param name="wigStartInfo">Work item group start information</param>
169 /// A delegate to call after the callback completion 169 /// <param name="callback">A callback to execute</param>
170 /// </param> 170 /// <param name="state">
171 /// <returns>Returns a work item</returns> 171 /// The context object of the work item. Used for passing arguments to the work item.
172 public static WorkItem CreateWorkItem( 172 /// </param>
173 IWorkItemsGroup workItemsGroup, 173 /// <param name="postExecuteWorkItemCallback">
174 WIGStartInfo wigStartInfo, 174 /// A delegate to call after the callback completion
175 WorkItemCallback callback, 175 /// </param>
176 object state, 176 /// <returns>Returns a work item</returns>
177 PostExecuteWorkItemCallback postExecuteWorkItemCallback) 177 public static WorkItem CreateWorkItem(
178 { 178 IWorkItemsGroup workItemsGroup,
179 ValidateCallback(callback); 179 WIGStartInfo wigStartInfo,
180 ValidateCallback(postExecuteWorkItemCallback); 180 WorkItemCallback callback,
181 181 object state,
182 WorkItemInfo workItemInfo = new WorkItemInfo(); 182 PostExecuteWorkItemCallback postExecuteWorkItemCallback)
183 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 183 {
184 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 184 ValidateCallback(callback);
185 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 185 ValidateCallback(postExecuteWorkItemCallback);
186 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 186
187 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 187 WorkItemInfo workItemInfo = new WorkItemInfo();
188 188 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
189 WorkItem workItem = new WorkItem( 189 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
190 workItemsGroup, 190 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
191 workItemInfo, 191 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
192 callback, 192 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
193 state); 193 workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
194 194
195 return workItem; 195 WorkItem workItem = new WorkItem(
196 } 196 workItemsGroup,
197 197 workItemInfo,
198 /// <summary> 198 callback,
199 /// Create a new work item 199 state);
200 /// </summary> 200
201 /// <param name="wigStartInfo">Work item group start information</param> 201 return workItem;
202 /// <param name="callback">A callback to execute</param> 202 }
203 /// <param name="state"> 203
204 /// The context object of the work item. Used for passing arguments to the work item. 204 /// <summary>
205 /// </param> 205 /// Create a new work item
206 /// <param name="postExecuteWorkItemCallback"> 206 /// </summary>
207 /// A delegate to call after the callback completion 207 /// <param name="workItemsGroup">The work items group</param>
208 /// </param> 208 /// <param name="wigStartInfo">Work item group start information</param>
209 /// <param name="workItemPriority">The work item priority</param> 209 /// <param name="callback">A callback to execute</param>
210 /// <returns>Returns a work item</returns> 210 /// <param name="state">
211 public static WorkItem CreateWorkItem( 211 /// The context object of the work item. Used for passing arguments to the work item.
212 IWorkItemsGroup workItemsGroup, 212 /// </param>
213 WIGStartInfo wigStartInfo, 213 /// <param name="postExecuteWorkItemCallback">
214 WorkItemCallback callback, 214 /// A delegate to call after the callback completion
215 object state, 215 /// </param>
216 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 216 /// <param name="workItemPriority">The work item priority</param>
217 WorkItemPriority workItemPriority) 217 /// <returns>Returns a work item</returns>
218 { 218 public static WorkItem CreateWorkItem(
219 ValidateCallback(callback); 219 IWorkItemsGroup workItemsGroup,
220 ValidateCallback(postExecuteWorkItemCallback); 220 WIGStartInfo wigStartInfo,
221 221 WorkItemCallback callback,
222 WorkItemInfo workItemInfo = new WorkItemInfo(); 222 object state,
223 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 223 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
224 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 224 WorkItemPriority workItemPriority)
225 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 225 {
226 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; 226 ValidateCallback(callback);
227 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 227 ValidateCallback(postExecuteWorkItemCallback);
228 workItemInfo.WorkItemPriority = workItemPriority; 228
229 229 WorkItemInfo workItemInfo = new WorkItemInfo();
230 WorkItem workItem = new WorkItem( 230 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
231 workItemsGroup, 231 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
232 workItemInfo, 232 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
233 callback, 233 workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
234 state); 234 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
235 235 workItemInfo.WorkItemPriority = workItemPriority;
236 return workItem; 236
237 } 237 WorkItem workItem = new WorkItem(
238 238 workItemsGroup,
239 /// <summary> 239 workItemInfo,
240 /// Create a new work item 240 callback,
241 /// </summary> 241 state);
242 /// <param name="wigStartInfo">Work item group start information</param> 242
243 /// <param name="callback">A callback to execute</param> 243 return workItem;
244 /// <param name="state"> 244 }
245 /// The context object of the work item. Used for passing arguments to the work item. 245
246 /// </param> 246 /// <summary>
247 /// <param name="postExecuteWorkItemCallback"> 247 /// Create a new work item
248 /// A delegate to call after the callback completion 248 /// </summary>
249 /// </param> 249 /// <param name="workItemsGroup">The work items group</param>
250 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 250 /// <param name="wigStartInfo">Work item group start information</param>
251 /// <returns>Returns a work item</returns> 251 /// <param name="callback">A callback to execute</param>
252 public static WorkItem CreateWorkItem( 252 /// <param name="state">
253 IWorkItemsGroup workItemsGroup, 253 /// The context object of the work item. Used for passing arguments to the work item.
254 WIGStartInfo wigStartInfo, 254 /// </param>
255 WorkItemCallback callback, 255 /// <param name="postExecuteWorkItemCallback">
256 object state, 256 /// A delegate to call after the callback completion
257 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 257 /// </param>
258 CallToPostExecute callToPostExecute) 258 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
259 { 259 /// <returns>Returns a work item</returns>
260 ValidateCallback(callback); 260 public static WorkItem CreateWorkItem(
261 ValidateCallback(postExecuteWorkItemCallback); 261 IWorkItemsGroup workItemsGroup,
262 262 WIGStartInfo wigStartInfo,
263 WorkItemInfo workItemInfo = new WorkItemInfo(); 263 WorkItemCallback callback,
264 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 264 object state,
265 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 265 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
266 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 266 CallToPostExecute callToPostExecute)
267 workItemInfo.CallToPostExecute = callToPostExecute; 267 {
268 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 268 ValidateCallback(callback);
269 269 ValidateCallback(postExecuteWorkItemCallback);
270 WorkItem workItem = new WorkItem( 270
271 workItemsGroup, 271 WorkItemInfo workItemInfo = new WorkItemInfo();
272 workItemInfo, 272 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
273 callback, 273 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
274 state); 274 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
275 275 workItemInfo.CallToPostExecute = callToPostExecute;
276 return workItem; 276 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
277 } 277 workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
278 278
279 /// <summary> 279 WorkItem workItem = new WorkItem(
280 /// Create a new work item 280 workItemsGroup,
281 /// </summary> 281 workItemInfo,
282 /// <param name="wigStartInfo">Work item group start information</param> 282 callback,
283 /// <param name="callback">A callback to execute</param> 283 state);
284 /// <param name="state"> 284
285 /// The context object of the work item. Used for passing arguments to the work item. 285 return workItem;
286 /// </param> 286 }
287 /// <param name="postExecuteWorkItemCallback"> 287
288 /// A delegate to call after the callback completion 288 /// <summary>
289 /// </param> 289 /// Create a new work item
290 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 290 /// </summary>
291 /// <param name="workItemPriority">The work item priority</param> 291 /// <param name="workItemsGroup">The work items group</param>
292 /// <returns>Returns a work item</returns> 292 /// <param name="wigStartInfo">Work item group start information</param>
293 public static WorkItem CreateWorkItem( 293 /// <param name="callback">A callback to execute</param>
294 IWorkItemsGroup workItemsGroup, 294 /// <param name="state">
295 WIGStartInfo wigStartInfo, 295 /// The context object of the work item. Used for passing arguments to the work item.
296 WorkItemCallback callback, 296 /// </param>
297 object state, 297 /// <param name="postExecuteWorkItemCallback">
298 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 298 /// A delegate to call after the callback completion
299 CallToPostExecute callToPostExecute, 299 /// </param>
300 WorkItemPriority workItemPriority) 300 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
301 { 301 /// <param name="workItemPriority">The work item priority</param>
302 302 /// <returns>Returns a work item</returns>
303 ValidateCallback(callback); 303 public static WorkItem CreateWorkItem(
304 ValidateCallback(postExecuteWorkItemCallback); 304 IWorkItemsGroup workItemsGroup,
305 305 WIGStartInfo wigStartInfo,
306 WorkItemInfo workItemInfo = new WorkItemInfo(); 306 WorkItemCallback callback,
307 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; 307 object state,
308 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; 308 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
309 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; 309 CallToPostExecute callToPostExecute,
310 workItemInfo.CallToPostExecute = callToPostExecute; 310 WorkItemPriority workItemPriority)
311 workItemInfo.WorkItemPriority = workItemPriority; 311 {
312 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; 312
313 313 ValidateCallback(callback);
314 WorkItem workItem = new WorkItem( 314 ValidateCallback(postExecuteWorkItemCallback);
315 workItemsGroup, 315
316 workItemInfo, 316 WorkItemInfo workItemInfo = new WorkItemInfo();
317 callback, 317 workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
318 state); 318 workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
319 319 workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
320 return workItem; 320 workItemInfo.CallToPostExecute = callToPostExecute;
321 } 321 workItemInfo.WorkItemPriority = workItemPriority;
322 322 workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
323 private static void ValidateCallback(Delegate callback) 323
324 { 324 WorkItem workItem = new WorkItem(
325 if(callback.GetInvocationList().Length > 1) 325 workItemsGroup,
326 { 326 workItemInfo,
327 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); 327 callback,
328 } 328 state);
329 } 329
330 } 330 return workItem;
331 331 }
332 #endregion 332
333} 333 private static void ValidateCallback(Delegate callback)
334 {
335 if (callback != null && callback.GetInvocationList().Length > 1)
336 {
337 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
338 }
339 }
340 }
341
342 #endregion
343}
diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs
index c259339..5fbceb8 100644
--- a/ThirdParty/SmartThreadPool/WorkItemInfo.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs
@@ -1,102 +1,69 @@
1// Ami Bar 1namespace Amib.Threading
2// amibar@gmail.com 2{
3 3 #region WorkItemInfo class
4namespace Amib.Threading 4
5{ 5 /// <summary>
6 #region WorkItemInfo class 6 /// Summary description for WorkItemInfo.
7 7 /// </summary>
8 /// <summary> 8 public class WorkItemInfo
9 /// Summary description for WorkItemInfo. 9 {
10 /// </summary> 10 public WorkItemInfo()
11 public class WorkItemInfo 11 {
12 { 12 UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
13 /// <summary> 13 UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
14 /// Use the caller's security context 14 DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
15 /// </summary> 15 CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
16 private bool _useCallerCallContext; 16 PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
17 17 WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
18 /// <summary> 18 }
19 /// Use the caller's security context 19
20 /// </summary> 20 public WorkItemInfo(WorkItemInfo workItemInfo)
21 private bool _useCallerHttpContext; 21 {
22 22 UseCallerCallContext = workItemInfo.UseCallerCallContext;
23 /// <summary> 23 UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
24 /// Dispose of the state object of a work item 24 DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
25 /// </summary> 25 CallToPostExecute = workItemInfo.CallToPostExecute;
26 private bool _disposeOfStateObjects; 26 PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
27 27 WorkItemPriority = workItemInfo.WorkItemPriority;
28 /// <summary> 28 Timeout = workItemInfo.Timeout;
29 /// The option to run the post execute 29 }
30 /// </summary> 30
31 private CallToPostExecute _callToPostExecute; 31 /// <summary>
32 32 /// Get/Set if to use the caller's security context
33 /// <summary> 33 /// </summary>
34 /// A post execute callback to call when none is provided in 34 public bool UseCallerCallContext { get; set; }
35 /// the QueueWorkItem method. 35
36 /// </summary> 36 /// <summary>
37 private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; 37 /// Get/Set if to use the caller's HTTP context
38 38 /// </summary>
39 /// <summary> 39 public bool UseCallerHttpContext { get; set; }
40 /// The priority of the work item 40
41 /// </summary> 41 /// <summary>
42 private WorkItemPriority _workItemPriority; 42 /// Get/Set if to dispose of the state object of a work item
43 43 /// </summary>
44 public WorkItemInfo() 44 public bool DisposeOfStateObjects { get; set; }
45 { 45
46 _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; 46 /// <summary>
47 _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; 47 /// Get/Set the run the post execute options
48 _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; 48 /// </summary>
49 _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; 49 public CallToPostExecute CallToPostExecute { get; set; }
50 _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; 50
51 _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; 51 /// <summary>
52 } 52 /// Get/Set the post execute callback
53 53 /// </summary>
54 public WorkItemInfo(WorkItemInfo workItemInfo) 54 public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
55 { 55
56 _useCallerCallContext = workItemInfo._useCallerCallContext; 56 /// <summary>
57 _useCallerHttpContext = workItemInfo._useCallerHttpContext; 57 /// Get/Set the work item's priority
58 _disposeOfStateObjects = workItemInfo._disposeOfStateObjects; 58 /// </summary>
59 _callToPostExecute = workItemInfo._callToPostExecute; 59 public WorkItemPriority WorkItemPriority { get; set; }
60 _postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback; 60
61 _workItemPriority = workItemInfo._workItemPriority; 61 /// <summary>
62 } 62 /// Get/Set the work item's timout in milliseconds.
63 63 /// This is a passive timout. When the timout expires the work item won't be actively aborted!
64 public bool UseCallerCallContext 64 /// </summary>
65 { 65 public long Timeout { get; set; }
66 get { return _useCallerCallContext; } 66 }
67 set { _useCallerCallContext = value; } 67
68 } 68 #endregion
69 69}
70 public bool UseCallerHttpContext
71 {
72 get { return _useCallerHttpContext; }
73 set { _useCallerHttpContext = value; }
74 }
75
76 public bool DisposeOfStateObjects
77 {
78 get { return _disposeOfStateObjects; }
79 set { _disposeOfStateObjects = value; }
80 }
81
82 public CallToPostExecute CallToPostExecute
83 {
84 get { return _callToPostExecute; }
85 set { _callToPostExecute = value; }
86 }
87
88 public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
89 {
90 get { return _postExecuteWorkItemCallback; }
91 set { _postExecuteWorkItemCallback = value; }
92 }
93
94 public WorkItemPriority WorkItemPriority
95 {
96 get { return _workItemPriority; }
97 set { _workItemPriority = value; }
98 }
99 }
100
101 #endregion
102}
diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
new file mode 100644
index 0000000..a0bf8b8
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
@@ -0,0 +1,128 @@
1using System;
2using System.Threading;
3
4namespace Amib.Threading.Internal
5{
6 #region WorkItemResultTWrapper class
7
8 internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult
9 {
10 private readonly IWorkItemResult _workItemResult;
11
12 public WorkItemResultTWrapper(IWorkItemResult workItemResult)
13 {
14 _workItemResult = workItemResult;
15 }
16
17 #region IWorkItemResult<TResult> Members
18
19 public TResult GetResult()
20 {
21 return (TResult)_workItemResult.GetResult();
22 }
23
24 public TResult GetResult(int millisecondsTimeout, bool exitContext)
25 {
26 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext);
27 }
28
29 public TResult GetResult(TimeSpan timeout, bool exitContext)
30 {
31 return (TResult)_workItemResult.GetResult(timeout, exitContext);
32 }
33
34 public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
35 {
36 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
37 }
38
39 public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
40 {
41 return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle);
42 }
43
44 public TResult GetResult(out Exception e)
45 {
46 return (TResult)_workItemResult.GetResult(out e);
47 }
48
49 public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
50 {
51 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e);
52 }
53
54 public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e)
55 {
56 return (TResult)_workItemResult.GetResult(timeout, exitContext, out e);
57 }
58
59 public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
60 {
61 return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
62 }
63
64 public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
65 {
66 return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e);
67 }
68
69 public bool IsCompleted
70 {
71 get { return _workItemResult.IsCompleted; }
72 }
73
74 public bool IsCanceled
75 {
76 get { return _workItemResult.IsCanceled; }
77 }
78
79 public object State
80 {
81 get { return _workItemResult.State; }
82 }
83
84 public bool Cancel()
85 {
86 return _workItemResult.Cancel();
87 }
88
89 public bool Cancel(bool abortExecution)
90 {
91 return _workItemResult.Cancel(abortExecution);
92 }
93
94 public WorkItemPriority WorkItemPriority
95 {
96 get { return _workItemResult.WorkItemPriority; }
97 }
98
99 public TResult Result
100 {
101 get { return (TResult)_workItemResult.Result; }
102 }
103
104 public object Exception
105 {
106 get { return (TResult)_workItemResult.Exception; }
107 }
108
109 #region IInternalWorkItemResult Members
110
111 public IWorkItemResult GetWorkItemResult()
112 {
113 return _workItemResult.GetWorkItemResult();
114 }
115
116 public IWorkItemResult<TRes> GetWorkItemResultT<TRes>()
117 {
118 return (IWorkItemResult<TRes>)this;
119 }
120
121 #endregion
122
123 #endregion
124 }
125
126 #endregion
127
128}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
index 01ac8dd..67dcbdd 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
@@ -1,512 +1,361 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2using System.Threading;
3 3using System.Runtime.CompilerServices;
4using System; 4using System.Diagnostics;
5using System.Threading; 5
6using System.Runtime.CompilerServices; 6namespace Amib.Threading.Internal
7using System.Diagnostics; 7{
8 8
9namespace Amib.Threading.Internal 9 #region WorkItemsGroup class
10{ 10
11 #region WorkItemsGroup class 11 /// <summary>
12 12 /// Summary description for WorkItemsGroup.
13 /// <summary> 13 /// </summary>
14 /// Summary description for WorkItemsGroup. 14 public class WorkItemsGroup : WorkItemsGroupBase
15 /// </summary> 15 {
16 public class WorkItemsGroup : IWorkItemsGroup 16 #region Private members
17 { 17
18 #region Private members 18 private readonly object _lock = new object();
19 19
20 private object _lock = new object(); 20 /// <summary>
21 /// <summary> 21 /// A reference to the SmartThreadPool instance that created this
22 /// Contains the name of this instance of SmartThreadPool. 22 /// WorkItemsGroup.
23 /// Can be changed by the user. 23 /// </summary>
24 /// </summary> 24 private readonly SmartThreadPool _stp;
25 private string _name = "WorkItemsGroup"; 25
26 26 /// <summary>
27 /// <summary> 27 /// The OnIdle event
28 /// A reference to the SmartThreadPool instance that created this 28 /// </summary>
29 /// WorkItemsGroup. 29 private event WorkItemsGroupIdleHandler _onIdle;
30 /// </summary> 30
31 private SmartThreadPool _stp; 31 /// <summary>
32 32 /// A flag to indicate if the Work Items Group is now suspended.
33 /// <summary> 33 /// </summary>
34 /// The OnIdle event 34 private bool _isSuspended;
35 /// </summary> 35
36 private event WorkItemsGroupIdleHandler _onIdle; 36 /// <summary>
37 37 /// Defines how many work items of this WorkItemsGroup can run at once.
38 /// <summary> 38 /// </summary>
39 /// Defines how many work items of this WorkItemsGroup can run at once. 39 private int _concurrency;
40 /// </summary> 40
41 private int _concurrency; 41 /// <summary>
42 42 /// Priority queue to hold work items before they are passed
43 /// <summary> 43 /// to the SmartThreadPool.
44 /// Priority queue to hold work items before they are passed 44 /// </summary>
45 /// to the SmartThreadPool. 45 private readonly PriorityQueue _workItemsQueue;
46 /// </summary> 46
47 private PriorityQueue _workItemsQueue; 47 /// <summary>
48 48 /// Indicate how many work items are waiting in the SmartThreadPool
49 /// <summary> 49 /// queue.
50 /// Indicate how many work items are waiting in the SmartThreadPool 50 /// This value is used to apply the concurrency.
51 /// queue. 51 /// </summary>
52 /// This value is used to apply the concurrency. 52 private int _workItemsInStpQueue;
53 /// </summary> 53
54 private int _workItemsInStpQueue; 54 /// <summary>
55 55 /// Indicate how many work items are currently running in the SmartThreadPool.
56 /// <summary> 56 /// This value is used with the Cancel, to calculate if we can send new
57 /// Indicate how many work items are currently running in the SmartThreadPool. 57 /// work items to the STP.
58 /// This value is used with the Cancel, to calculate if we can send new 58 /// </summary>
59 /// work items to the STP. 59 private int _workItemsExecutingInStp = 0;
60 /// </summary> 60
61 private int _workItemsExecutingInStp = 0; 61 /// <summary>
62 62 /// WorkItemsGroup start information
63 /// <summary> 63 /// </summary>
64 /// WorkItemsGroup start information 64 private readonly WIGStartInfo _workItemsGroupStartInfo;
65 /// </summary> 65
66 private WIGStartInfo _workItemsGroupStartInfo; 66 /// <summary>
67 67 /// Signaled when all of the WorkItemsGroup's work item completed.
68 /// <summary> 68 /// </summary>
69 /// Signaled when all of the WorkItemsGroup's work item completed. 69 //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
70 /// </summary> 70 private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
71 private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); 71
72 72 /// <summary>
73 /// <summary> 73 /// A common object for all the work items that this work items group
74 /// A common object for all the work items that this work items group 74 /// generate so we can mark them to cancel in O(1)
75 /// generate so we can mark them to cancel in O(1) 75 /// </summary>
76 /// </summary> 76 private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
77 private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); 77
78 78 #endregion
79 #endregion 79
80 80 #region Construction
81 #region Construction 81
82 82 public WorkItemsGroup(
83 public WorkItemsGroup( 83 SmartThreadPool stp,
84 SmartThreadPool stp, 84 int concurrency,
85 int concurrency, 85 WIGStartInfo wigStartInfo)
86 WIGStartInfo wigStartInfo) 86 {
87 { 87 if (concurrency <= 0)
88 if (concurrency <= 0) 88 {
89 { 89 throw new ArgumentOutOfRangeException(
90 throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero"); 90 "concurrency",
91 } 91#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
92 _stp = stp; 92 concurrency,
93 _concurrency = concurrency; 93#endif
94 _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo); 94 "concurrency must be greater than zero");
95 _workItemsQueue = new PriorityQueue(); 95 }
96 96 _stp = stp;
97 // The _workItemsInStpQueue gets the number of currently executing work items, 97 _concurrency = concurrency;
98 // because once a work item is executing, it cannot be cancelled. 98 _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
99 _workItemsInStpQueue = _workItemsExecutingInStp; 99 _workItemsQueue = new PriorityQueue();
100 } 100 Name = "WorkItemsGroup";
101 101
102 #endregion 102 // The _workItemsInStpQueue gets the number of currently executing work items,
103 103 // because once a work item is executing, it cannot be cancelled.
104 #region IWorkItemsGroup implementation 104 _workItemsInStpQueue = _workItemsExecutingInStp;
105 105
106 /// <summary> 106 _isSuspended = _workItemsGroupStartInfo.StartSuspended;
107 /// Get/Set the name of the SmartThreadPool instance 107 }
108 /// </summary> 108
109 public string Name 109 #endregion
110 { 110
111 get 111 #region WorkItemsGroupBase Overrides
112 { 112
113 return _name; 113 public override int Concurrency
114 } 114 {
115 115 get { return _concurrency; }
116 set 116 set
117 { 117 {
118 _name = value; 118 Debug.Assert(value > 0);
119 } 119
120 } 120 int diff = value - _concurrency;
121 121 _concurrency = value;
122 /// <summary> 122 if (diff > 0)
123 /// Queue a work item 123 {
124 /// </summary> 124 EnqueueToSTPNextNWorkItem(diff);
125 /// <param name="callback">A callback to execute</param> 125 }
126 /// <returns>Returns a work item result</returns> 126 }
127 public IWorkItemResult QueueWorkItem(WorkItemCallback callback) 127 }
128 { 128
129 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback); 129 public override int WaitingCallbacks
130 EnqueueToSTPNextWorkItem(workItem); 130 {
131 return workItem.GetWorkItemResult(); 131 get { return _workItemsQueue.Count; }
132 } 132 }
133 133
134 /// <summary> 134 public override object[] GetStates()
135 /// Queue a work item 135 {
136 /// </summary> 136 lock (_lock)
137 /// <param name="callback">A callback to execute</param> 137 {
138 /// <param name="workItemPriority">The priority of the work item</param> 138 object[] states = new object[_workItemsQueue.Count];
139 /// <returns>Returns a work item result</returns> 139 int i = 0;
140 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) 140 foreach (WorkItem workItem in _workItemsQueue)
141 { 141 {
142 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority); 142 states[i] = workItem.GetWorkItemResult().State;
143 EnqueueToSTPNextWorkItem(workItem); 143 ++i;
144 return workItem.GetWorkItemResult(); 144 }
145 } 145 return states;
146 146 }
147 /// <summary> 147 }
148 /// Queue a work item 148
149 /// </summary> 149 /// <summary>
150 /// <param name="workItemInfo">Work item info</param> 150 /// WorkItemsGroup start information
151 /// <param name="callback">A callback to execute</param> 151 /// </summary>
152 /// <returns>Returns a work item result</returns> 152 public override WIGStartInfo WIGStartInfo
153 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) 153 {
154 { 154 get { return _workItemsGroupStartInfo; }
155 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback); 155 }
156 EnqueueToSTPNextWorkItem(workItem); 156
157 return workItem.GetWorkItemResult(); 157 /// <summary>
158 } 158 /// Start the Work Items Group if it was started suspended
159 159 /// </summary>
160 /// <summary> 160 public override void Start()
161 /// Queue a work item 161 {
162 /// </summary> 162 // If the Work Items Group already started then quit
163 /// <param name="callback">A callback to execute</param> 163 if (!_isSuspended)
164 /// <param name="state"> 164 {
165 /// The context object of the work item. Used for passing arguments to the work item. 165 return;
166 /// </param> 166 }
167 /// <returns>Returns a work item result</returns> 167 _isSuspended = false;
168 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) 168
169 { 169 EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
170 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state); 170 }
171 EnqueueToSTPNextWorkItem(workItem); 171
172 return workItem.GetWorkItemResult(); 172 public override void Cancel(bool abortExecution)
173 } 173 {
174 174 lock (_lock)
175 /// <summary> 175 {
176 /// Queue a work item 176 _canceledWorkItemsGroup.IsCanceled = true;
177 /// </summary> 177 _workItemsQueue.Clear();
178 /// <param name="callback">A callback to execute</param> 178 _workItemsInStpQueue = 0;
179 /// <param name="state"> 179 _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
180 /// The context object of the work item. Used for passing arguments to the work item. 180 }
181 /// </param> 181
182 /// <param name="workItemPriority">The work item priority</param> 182 if (abortExecution)
183 /// <returns>Returns a work item result</returns> 183 {
184 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) 184 _stp.CancelAbortWorkItemsGroup(this);
185 { 185 }
186 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority); 186 }
187 EnqueueToSTPNextWorkItem(workItem); 187
188 return workItem.GetWorkItemResult(); 188 /// <summary>
189 } 189 /// Wait for the thread pool to be idle
190 190 /// </summary>
191 /// <summary> 191 public override bool WaitForIdle(int millisecondsTimeout)
192 /// Queue a work item 192 {
193 /// </summary> 193 SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
194 /// <param name="workItemInfo">Work item information</param> 194 return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
195 /// <param name="callback">A callback to execute</param> 195 }
196 /// <param name="state"> 196
197 /// The context object of the work item. Used for passing arguments to the work item. 197 public override event WorkItemsGroupIdleHandler OnIdle
198 /// </param> 198 {
199 /// <returns>Returns a work item result</returns> 199 add { _onIdle += value; }
200 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) 200 remove { _onIdle -= value; }
201 { 201 }
202 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state); 202
203 EnqueueToSTPNextWorkItem(workItem); 203 #endregion
204 return workItem.GetWorkItemResult(); 204
205 } 205 #region Private methods
206 206
207 /// <summary> 207 private void RegisterToWorkItemCompletion(IWorkItemResult wir)
208 /// Queue a work item 208 {
209 /// </summary> 209 IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
210 /// <param name="callback">A callback to execute</param> 210 iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
211 /// <param name="state"> 211 iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
212 /// The context object of the work item. Used for passing arguments to the work item. 212 }
213 /// </param> 213
214 /// <param name="postExecuteWorkItemCallback"> 214 public void OnSTPIsStarting()
215 /// A delegate to call after the callback completion 215 {
216 /// </param> 216 if (_isSuspended)
217 /// <returns>Returns a work item result</returns> 217 {
218 public IWorkItemResult QueueWorkItem( 218 return;
219 WorkItemCallback callback, 219 }
220 object state, 220
221 PostExecuteWorkItemCallback postExecuteWorkItemCallback) 221 EnqueueToSTPNextNWorkItem(_concurrency);
222 { 222 }
223 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback); 223
224 EnqueueToSTPNextWorkItem(workItem); 224 public void EnqueueToSTPNextNWorkItem(int count)
225 return workItem.GetWorkItemResult(); 225 {
226 } 226 for (int i = 0; i < count; ++i)
227 227 {
228 /// <summary> 228 EnqueueToSTPNextWorkItem(null, false);
229 /// Queue a work item 229 }
230 /// </summary> 230 }
231 /// <param name="callback">A callback to execute</param> 231
232 /// <param name="state"> 232 private object FireOnIdle(object state)
233 /// The context object of the work item. Used for passing arguments to the work item. 233 {
234 /// </param> 234 FireOnIdleImpl(_onIdle);
235 /// <param name="postExecuteWorkItemCallback"> 235 return null;
236 /// A delegate to call after the callback completion 236 }
237 /// </param> 237
238 /// <param name="workItemPriority">The work item priority</param> 238 [MethodImpl(MethodImplOptions.NoInlining)]
239 /// <returns>Returns a work item result</returns> 239 private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
240 public IWorkItemResult QueueWorkItem( 240 {
241 WorkItemCallback callback, 241 if(null == onIdle)
242 object state, 242 {
243 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 243 return;
244 WorkItemPriority workItemPriority) 244 }
245 { 245
246 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); 246 Delegate[] delegates = onIdle.GetInvocationList();
247 EnqueueToSTPNextWorkItem(workItem); 247 foreach(WorkItemsGroupIdleHandler eh in delegates)
248 return workItem.GetWorkItemResult(); 248 {
249 } 249 try
250 250 {
251 /// <summary> 251 eh(this);
252 /// Queue a work item 252 }
253 /// </summary> 253 catch { } // Suppress exceptions
254 /// <param name="callback">A callback to execute</param> 254 }
255 /// <param name="state"> 255 }
256 /// The context object of the work item. Used for passing arguments to the work item. 256
257 /// </param> 257 private void OnWorkItemStartedCallback(WorkItem workItem)
258 /// <param name="postExecuteWorkItemCallback"> 258 {
259 /// A delegate to call after the callback completion 259 lock(_lock)
260 /// </param> 260 {
261 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 261 ++_workItemsExecutingInStp;
262 /// <returns>Returns a work item result</returns> 262 }
263 public IWorkItemResult QueueWorkItem( 263 }
264 WorkItemCallback callback, 264
265 object state, 265 private void OnWorkItemCompletedCallback(WorkItem workItem)
266 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 266 {
267 CallToPostExecute callToPostExecute) 267 EnqueueToSTPNextWorkItem(null, true);
268 { 268 }
269 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); 269
270 EnqueueToSTPNextWorkItem(workItem); 270 internal override void Enqueue(WorkItem workItem)
271 return workItem.GetWorkItemResult(); 271 {
272 } 272 EnqueueToSTPNextWorkItem(workItem);
273 273 }
274 /// <summary> 274
275 /// Queue a work item 275 private void EnqueueToSTPNextWorkItem(WorkItem workItem)
276 /// </summary> 276 {
277 /// <param name="callback">A callback to execute</param> 277 EnqueueToSTPNextWorkItem(workItem, false);
278 /// <param name="state"> 278 }
279 /// The context object of the work item. Used for passing arguments to the work item. 279
280 /// </param> 280 private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
281 /// <param name="postExecuteWorkItemCallback"> 281 {
282 /// A delegate to call after the callback completion 282 lock(_lock)
283 /// </param> 283 {
284 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> 284 // Got here from OnWorkItemCompletedCallback()
285 /// <param name="workItemPriority">The work item priority</param> 285 if (decrementWorkItemsInStpQueue)
286 /// <returns>Returns a work item result</returns> 286 {
287 public IWorkItemResult QueueWorkItem( 287 --_workItemsInStpQueue;
288 WorkItemCallback callback, 288
289 object state, 289 if(_workItemsInStpQueue < 0)
290 PostExecuteWorkItemCallback postExecuteWorkItemCallback, 290 {
291 CallToPostExecute callToPostExecute, 291 _workItemsInStpQueue = 0;
292 WorkItemPriority workItemPriority) 292 }
293 { 293
294 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); 294 --_workItemsExecutingInStp;
295 EnqueueToSTPNextWorkItem(workItem); 295
296 return workItem.GetWorkItemResult(); 296 if(_workItemsExecutingInStp < 0)
297 } 297 {
298 298 _workItemsExecutingInStp = 0;
299 /// <summary> 299 }
300 /// Wait for the thread pool to be idle 300 }
301 /// </summary> 301
302 public void WaitForIdle() 302 // If the work item is not null then enqueue it
303 { 303 if (null != workItem)
304 WaitForIdle(Timeout.Infinite); 304 {
305 } 305 workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
306 306
307 /// <summary> 307 RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
308 /// Wait for the thread pool to be idle 308 _workItemsQueue.Enqueue(workItem);
309 /// </summary> 309 //_stp.IncrementWorkItemsCount();
310 public bool WaitForIdle(TimeSpan timeout) 310
311 { 311 if ((1 == _workItemsQueue.Count) &&
312 return WaitForIdle((int)timeout.TotalMilliseconds); 312 (0 == _workItemsInStpQueue))
313 } 313 {
314 314 _stp.RegisterWorkItemsGroup(this);
315 /// <summary> 315 IsIdle = false;
316 /// Wait for the thread pool to be idle 316 _isIdleWaitHandle.Reset();
317 /// </summary> 317 }
318 public bool WaitForIdle(int millisecondsTimeout) 318 }
319 { 319
320 _stp.ValidateWorkItemsGroupWaitForIdle(this); 320 // If the work items queue of the group is empty than quit
321 return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false); 321 if (0 == _workItemsQueue.Count)
322 } 322 {
323 323 if (0 == _workItemsInStpQueue)
324 public int WaitingCallbacks 324 {
325 { 325 _stp.UnregisterWorkItemsGroup(this);
326 get 326 IsIdle = true;
327 { 327 _isIdleWaitHandle.Set();
328 return _workItemsQueue.Count; 328 if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
329 } 329 {
330 } 330 _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
331 331 }
332 public event WorkItemsGroupIdleHandler OnIdle 332 }
333 { 333 return;
334 add 334 }
335 { 335
336 _onIdle += value; 336 if (!_isSuspended)
337 } 337 {
338 remove 338 if (_workItemsInStpQueue < _concurrency)
339 { 339 {
340 _onIdle -= value; 340 WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
341 } 341 try
342 } 342 {
343 343 _stp.Enqueue(nextWorkItem);
344 public void Cancel() 344 }
345 { 345 catch (ObjectDisposedException e)
346 lock(_lock) 346 {
347 { 347 e.GetHashCode();
348 _canceledWorkItemsGroup.IsCanceled = true; 348 // The STP has been shutdown
349 _workItemsQueue.Clear(); 349 }
350 _workItemsInStpQueue = 0; 350
351 _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); 351 ++_workItemsInStpQueue;
352 } 352 }
353 } 353 }
354 354 }
355 public void Start() 355 }
356 { 356
357 lock (this) 357 #endregion
358 { 358 }
359 if (!_workItemsGroupStartInfo.StartSuspended) 359
360 { 360 #endregion
361 return; 361}
362 }
363 _workItemsGroupStartInfo.StartSuspended = false;
364 }
365
366 for(int i = 0; i < _concurrency; ++i)
367 {
368 EnqueueToSTPNextWorkItem(null, false);
369 }
370 }
371
372 #endregion
373
374 #region Private methods
375
376 private void RegisterToWorkItemCompletion(IWorkItemResult wir)
377 {
378 IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
379 iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
380 iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
381 }
382
383 public void OnSTPIsStarting()
384 {
385 lock (this)
386 {
387 if (_workItemsGroupStartInfo.StartSuspended)
388 {
389 return;
390 }
391 }
392
393 for(int i = 0; i < _concurrency; ++i)
394 {
395 EnqueueToSTPNextWorkItem(null, false);
396 }
397 }
398
399 private object FireOnIdle(object state)
400 {
401 FireOnIdleImpl(_onIdle);
402 return null;
403 }
404
405 [MethodImpl(MethodImplOptions.NoInlining)]
406 private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
407 {
408 if(null == onIdle)
409 {
410 return;
411 }
412
413 Delegate[] delegates = onIdle.GetInvocationList();
414 foreach(WorkItemsGroupIdleHandler eh in delegates)
415 {
416 try
417 {
418 eh(this);
419 }
420 // Ignore exceptions
421 catch{}
422 }
423 }
424
425 private void OnWorkItemStartedCallback(WorkItem workItem)
426 {
427 lock(_lock)
428 {
429 ++_workItemsExecutingInStp;
430 }
431 }
432
433 private void OnWorkItemCompletedCallback(WorkItem workItem)
434 {
435 EnqueueToSTPNextWorkItem(null, true);
436 }
437
438 private void EnqueueToSTPNextWorkItem(WorkItem workItem)
439 {
440 EnqueueToSTPNextWorkItem(workItem, false);
441 }
442
443 private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
444 {
445 lock(_lock)
446 {
447 // Got here from OnWorkItemCompletedCallback()
448 if (decrementWorkItemsInStpQueue)
449 {
450 --_workItemsInStpQueue;
451
452 if(_workItemsInStpQueue < 0)
453 {
454 _workItemsInStpQueue = 0;
455 }
456
457 --_workItemsExecutingInStp;
458
459 if(_workItemsExecutingInStp < 0)
460 {
461 _workItemsExecutingInStp = 0;
462 }
463 }
464
465 // If the work item is not null then enqueue it
466 if (null != workItem)
467 {
468 workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
469
470 RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
471 _workItemsQueue.Enqueue(workItem);
472 //_stp.IncrementWorkItemsCount();
473
474 if ((1 == _workItemsQueue.Count) &&
475 (0 == _workItemsInStpQueue))
476 {
477 _stp.RegisterWorkItemsGroup(this);
478 Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
479 _isIdleWaitHandle.Reset();
480 }
481 }
482
483 // If the work items queue of the group is empty than quit
484 if (0 == _workItemsQueue.Count)
485 {
486 if (0 == _workItemsInStpQueue)
487 {
488 _stp.UnregisterWorkItemsGroup(this);
489 Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
490 _isIdleWaitHandle.Set();
491 _stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
492 }
493 return;
494 }
495
496 if (!_workItemsGroupStartInfo.StartSuspended)
497 {
498 if (_workItemsInStpQueue < _concurrency)
499 {
500 WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
501 _stp.Enqueue(nextWorkItem, true);
502 ++_workItemsInStpQueue;
503 }
504 }
505 }
506 }
507
508 #endregion
509 }
510
511 #endregion
512}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
new file mode 100644
index 0000000..429de12
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
@@ -0,0 +1,471 @@
1using System;
2using System.Threading;
3
4namespace Amib.Threading.Internal
5{
6 public abstract class WorkItemsGroupBase : IWorkItemsGroup
7 {
8 #region Private Fields
9
10 /// <summary>
11 /// Contains the name of this instance of SmartThreadPool.
12 /// Can be changed by the user.
13 /// </summary>
14 private string _name = "WorkItemsGroupBase";
15
16 public WorkItemsGroupBase()
17 {
18 IsIdle = true;
19 }
20
21 #endregion
22
23 #region IWorkItemsGroup Members
24
25 #region Public Methods
26
27 /// <summary>
28 /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
29 /// </summary>
30 public string Name
31 {
32 get { return _name; }
33 set { _name = value; }
34 }
35
36 #endregion
37
38 #region Abstract Methods
39
40 public abstract int Concurrency { get; set; }
41 public abstract int WaitingCallbacks { get; }
42 public abstract object[] GetStates();
43 public abstract WIGStartInfo WIGStartInfo { get; }
44 public abstract void Start();
45 public abstract void Cancel(bool abortExecution);
46 public abstract bool WaitForIdle(int millisecondsTimeout);
47 public abstract event WorkItemsGroupIdleHandler OnIdle;
48
49 internal abstract void Enqueue(WorkItem workItem);
50 internal virtual void PreQueueWorkItem() { }
51
52 #endregion
53
54 #region Common Base Methods
55
56 /// <summary>
57 /// Cancel all the work items.
58 /// Same as Cancel(false)
59 /// </summary>
60 public virtual void Cancel()
61 {
62 Cancel(false);
63 }
64
65 /// <summary>
66 /// Wait for the SmartThreadPool/WorkItemsGroup to be idle
67 /// </summary>
68 public void WaitForIdle()
69 {
70 WaitForIdle(Timeout.Infinite);
71 }
72
73 /// <summary>
74 /// Wait for the SmartThreadPool/WorkItemsGroup to be idle
75 /// </summary>
76 public bool WaitForIdle(TimeSpan timeout)
77 {
78 return WaitForIdle((int)timeout.TotalMilliseconds);
79 }
80
81 /// <summary>
82 /// IsIdle is true when there are no work items running or queued.
83 /// </summary>
84 public bool IsIdle { get; protected set; }
85
86 #endregion
87
88 #region QueueWorkItem
89
90 /// <summary>
91 /// Queue a work item
92 /// </summary>
93 /// <param name="callback">A callback to execute</param>
94 /// <returns>Returns a work item result</returns>
95 public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
96 {
97 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback);
98 Enqueue(workItem);
99 return workItem.GetWorkItemResult();
100 }
101
102 /// <summary>
103 /// Queue a work item
104 /// </summary>
105 /// <param name="callback">A callback to execute</param>
106 /// <param name="workItemPriority">The priority of the work item</param>
107 /// <returns>Returns a work item result</returns>
108 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
109 {
110 PreQueueWorkItem();
111 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
112 Enqueue(workItem);
113 return workItem.GetWorkItemResult();
114 }
115
116 /// <summary>
117 /// Queue a work item
118 /// </summary>
119 /// <param name="workItemInfo">Work item info</param>
120 /// <param name="callback">A callback to execute</param>
121 /// <returns>Returns a work item result</returns>
122 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
123 {
124 PreQueueWorkItem();
125 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
126 Enqueue(workItem);
127 return workItem.GetWorkItemResult();
128 }
129
130 /// <summary>
131 /// Queue a work item
132 /// </summary>
133 /// <param name="callback">A callback to execute</param>
134 /// <param name="state">
135 /// The context object of the work item. Used for passing arguments to the work item.
136 /// </param>
137 /// <returns>Returns a work item result</returns>
138 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
139 {
140 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state);
141 Enqueue(workItem);
142 return workItem.GetWorkItemResult();
143 }
144
145 /// <summary>
146 /// Queue a work item
147 /// </summary>
148 /// <param name="callback">A callback to execute</param>
149 /// <param name="state">
150 /// The context object of the work item. Used for passing arguments to the work item.
151 /// </param>
152 /// <param name="workItemPriority">The work item priority</param>
153 /// <returns>Returns a work item result</returns>
154 public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
155 {
156 PreQueueWorkItem();
157 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
158 Enqueue(workItem);
159 return workItem.GetWorkItemResult();
160 }
161
162 /// <summary>
163 /// Queue a work item
164 /// </summary>
165 /// <param name="workItemInfo">Work item information</param>
166 /// <param name="callback">A callback to execute</param>
167 /// <param name="state">
168 /// The context object of the work item. Used for passing arguments to the work item.
169 /// </param>
170 /// <returns>Returns a work item result</returns>
171 public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
172 {
173 PreQueueWorkItem();
174 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
175 Enqueue(workItem);
176 return workItem.GetWorkItemResult();
177 }
178
179 /// <summary>
180 /// Queue a work item
181 /// </summary>
182 /// <param name="callback">A callback to execute</param>
183 /// <param name="state">
184 /// The context object of the work item. Used for passing arguments to the work item.
185 /// </param>
186 /// <param name="postExecuteWorkItemCallback">
187 /// A delegate to call after the callback completion
188 /// </param>
189 /// <returns>Returns a work item result</returns>
190 public IWorkItemResult QueueWorkItem(
191 WorkItemCallback callback,
192 object state,
193 PostExecuteWorkItemCallback postExecuteWorkItemCallback)
194 {
195 PreQueueWorkItem();
196 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
197 Enqueue(workItem);
198 return workItem.GetWorkItemResult();
199 }
200
201 /// <summary>
202 /// Queue a work item
203 /// </summary>
204 /// <param name="callback">A callback to execute</param>
205 /// <param name="state">
206 /// The context object of the work item. Used for passing arguments to the work item.
207 /// </param>
208 /// <param name="postExecuteWorkItemCallback">
209 /// A delegate to call after the callback completion
210 /// </param>
211 /// <param name="workItemPriority">The work item priority</param>
212 /// <returns>Returns a work item result</returns>
213 public IWorkItemResult QueueWorkItem(
214 WorkItemCallback callback,
215 object state,
216 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
217 WorkItemPriority workItemPriority)
218 {
219 PreQueueWorkItem();
220 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
221 Enqueue(workItem);
222 return workItem.GetWorkItemResult();
223 }
224
225 /// <summary>
226 /// Queue a work item
227 /// </summary>
228 /// <param name="callback">A callback to execute</param>
229 /// <param name="state">
230 /// The context object of the work item. Used for passing arguments to the work item.
231 /// </param>
232 /// <param name="postExecuteWorkItemCallback">
233 /// A delegate to call after the callback completion
234 /// </param>
235 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
236 /// <returns>Returns a work item result</returns>
237 public IWorkItemResult QueueWorkItem(
238 WorkItemCallback callback,
239 object state,
240 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
241 CallToPostExecute callToPostExecute)
242 {
243 PreQueueWorkItem();
244 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
245 Enqueue(workItem);
246 return workItem.GetWorkItemResult();
247 }
248
249 /// <summary>
250 /// Queue a work item
251 /// </summary>
252 /// <param name="callback">A callback to execute</param>
253 /// <param name="state">
254 /// The context object of the work item. Used for passing arguments to the work item.
255 /// </param>
256 /// <param name="postExecuteWorkItemCallback">
257 /// A delegate to call after the callback completion
258 /// </param>
259 /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
260 /// <param name="workItemPriority">The work item priority</param>
261 /// <returns>Returns a work item result</returns>
262 public IWorkItemResult QueueWorkItem(
263 WorkItemCallback callback,
264 object state,
265 PostExecuteWorkItemCallback postExecuteWorkItemCallback,
266 CallToPostExecute callToPostExecute,
267 WorkItemPriority workItemPriority)
268 {
269 PreQueueWorkItem();
270 WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
271 Enqueue(workItem);
272 return workItem.GetWorkItemResult();
273 }
274
275 #endregion
276
277 #region QueueWorkItem(Action<...>)
278
279 public IWorkItemResult QueueWorkItem(Action action)
280 {
281 return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority);
282 }
283
284 public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority)
285 {
286 PreQueueWorkItem ();
287 WorkItem workItem = WorkItemFactory.CreateWorkItem (
288 this,
289 WIGStartInfo,
290 delegate
291 {
292 action.Invoke ();
293 return null;
294 }, priority);
295 Enqueue (workItem);
296 return workItem.GetWorkItemResult ();
297 }
298
299 public IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg)
300 {
301 return QueueWorkItem<T> (action, arg, SmartThreadPool.DefaultWorkItemPriority);
302 }
303
304 public IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority)
305 {
306 PreQueueWorkItem ();
307 WorkItem workItem = WorkItemFactory.CreateWorkItem (
308 this,
309 WIGStartInfo,
310 state =>
311 {
312 action.Invoke (arg);
313 return null;
314 },
315 WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority);
316 Enqueue (workItem);
317 return workItem.GetWorkItemResult ();
318 }
319
320 public IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
321 {
322 return QueueWorkItem<T1, T2> (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority);
323 }
324
325 public IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority)
326 {
327 PreQueueWorkItem ();
328 WorkItem workItem = WorkItemFactory.CreateWorkItem (
329 this,
330 WIGStartInfo,
331 state =>
332 {
333 action.Invoke (arg1, arg2);
334 return null;
335 },
336 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority);
337 Enqueue (workItem);
338 return workItem.GetWorkItemResult ();
339 }
340
341 public IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
342 {
343 return QueueWorkItem<T1, T2, T3> (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority);
344 ;
345 }
346
347 public IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority)
348 {
349 PreQueueWorkItem ();
350 WorkItem workItem = WorkItemFactory.CreateWorkItem (
351 this,
352 WIGStartInfo,
353 state =>
354 {
355 action.Invoke (arg1, arg2, arg3);
356 return null;
357 },
358 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority);
359 Enqueue (workItem);
360 return workItem.GetWorkItemResult ();
361 }
362
363 public IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(
364 Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
365 {
366 return QueueWorkItem<T1, T2, T3, T4> (action, arg1, arg2, arg3, arg4,
367 SmartThreadPool.DefaultWorkItemPriority);
368 }
369
370 public IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (
371 Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority)
372 {
373 PreQueueWorkItem ();
374 WorkItem workItem = WorkItemFactory.CreateWorkItem (
375 this,
376 WIGStartInfo,
377 state =>
378 {
379 action.Invoke (arg1, arg2, arg3, arg4);
380 return null;
381 },
382 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority);
383 Enqueue (workItem);
384 return workItem.GetWorkItemResult ();
385 }
386
387 #endregion
388
389 #region QueueWorkItem(Func<...>)
390
391 public IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func)
392 {
393 PreQueueWorkItem();
394 WorkItem workItem = WorkItemFactory.CreateWorkItem(
395 this,
396 WIGStartInfo,
397 state =>
398 {
399 return func.Invoke();
400 });
401 Enqueue(workItem);
402 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
403 }
404
405 public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg)
406 {
407 PreQueueWorkItem();
408 WorkItem workItem = WorkItemFactory.CreateWorkItem(
409 this,
410 WIGStartInfo,
411 state =>
412 {
413 return func.Invoke(arg);
414 },
415 WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null);
416 Enqueue(workItem);
417 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
418 }
419
420 public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
421 {
422 PreQueueWorkItem();
423 WorkItem workItem = WorkItemFactory.CreateWorkItem(
424 this,
425 WIGStartInfo,
426 state =>
427 {
428 return func.Invoke(arg1, arg2);
429 },
430 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null);
431 Enqueue(workItem);
432 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
433 }
434
435 public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(
436 Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3)
437 {
438 PreQueueWorkItem();
439 WorkItem workItem = WorkItemFactory.CreateWorkItem(
440 this,
441 WIGStartInfo,
442 state =>
443 {
444 return func.Invoke(arg1, arg2, arg3);
445 },
446 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null);
447 Enqueue(workItem);
448 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
449 }
450
451 public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(
452 Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
453 {
454 PreQueueWorkItem();
455 WorkItem workItem = WorkItemFactory.CreateWorkItem(
456 this,
457 WIGStartInfo,
458 state =>
459 {
460 return func.Invoke(arg1, arg2, arg3, arg4);
461 },
462 WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null);
463 Enqueue(workItem);
464 return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
465 }
466
467 #endregion
468
469 #endregion
470 }
471} \ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
index af5af07..156a131 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
@@ -1,600 +1,645 @@
1// Ami Bar 1using System;
2// amibar@gmail.com 2using System.Collections.Generic;
3 3using System.Threading;
4using System; 4
5using System.Threading; 5namespace Amib.Threading.Internal
6 6{
7namespace Amib.Threading.Internal 7 #region WorkItemsQueue class
8{ 8
9 #region WorkItemsQueue class 9 /// <summary>
10 10 /// WorkItemsQueue class.
11 /// <summary> 11 /// </summary>
12 /// WorkItemsQueue class. 12 public class WorkItemsQueue : IDisposable
13 /// </summary> 13 {
14 public class WorkItemsQueue : IDisposable 14 #region Member variables
15 { 15
16 #region Member variables 16 /// <summary>
17 17 /// Waiters queue (implemented as stack).
18 /// <summary> 18 /// </summary>
19 /// Waiters queue (implemented as stack). 19 private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
20 /// </summary> 20
21 private WaiterEntry _headWaiterEntry = new WaiterEntry(); 21 /// <summary>
22 22 /// Waiters count
23 /// <summary> 23 /// </summary>
24 /// Waiters count 24 private int _waitersCount = 0;
25 /// </summary> 25
26 private int _waitersCount = 0; 26 /// <summary>
27 27 /// Work items queue
28 /// <summary> 28 /// </summary>
29 /// Work items queue 29 private readonly PriorityQueue _workItems = new PriorityQueue();
30 /// </summary> 30
31 private PriorityQueue _workItems = new PriorityQueue(); 31 /// <summary>
32 32 /// Indicate that work items are allowed to be queued
33 /// <summary> 33 /// </summary>
34 /// Indicate that work items are allowed to be queued 34 private bool _isWorkItemsQueueActive = true;
35 /// </summary> 35
36 private bool _isWorkItemsQueueActive = true; 36
37 37#if (WINDOWS_PHONE)
38 /// <summary> 38 private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>();
39 /// Each thread in the thread pool keeps its own waiter entry. 39#elif (_WINDOWS_CE)
40 /// </summary> 40 private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
41 [ThreadStatic] 41#else
42 private static WaiterEntry _waiterEntry; 42
43 43 [ThreadStatic]
44 /// <summary> 44 private static WaiterEntry _waiterEntry;
45 /// A flag that indicates if the WorkItemsQueue has been disposed. 45#endif
46 /// </summary> 46
47 private bool _isDisposed = false; 47
48 48 /// <summary>
49 #endregion 49 /// Each thread in the thread pool keeps its own waiter entry.
50 50 /// </summary>
51 #region Public properties 51 private static WaiterEntry CurrentWaiterEntry
52 52 {
53 /// <summary> 53#if (WINDOWS_PHONE)
54 /// Returns the current number of work items in the queue 54 get
55 /// </summary> 55 {
56 public int Count 56 lock (_waiterEntries)
57 { 57 {
58 get 58 WaiterEntry waiterEntry;
59 { 59 if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
60 lock(this) 60 {
61 { 61 return waiterEntry;
62 ValidateNotDisposed(); 62 }
63 return _workItems.Count; 63 }
64 } 64 return null;
65 } 65 }
66 } 66 set
67 67 {
68 /// <summary> 68 lock (_waiterEntries)
69 /// Returns the current number of waiters 69 {
70 /// </summary> 70 _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
71 public int WaitersCount 71 }
72 { 72 }
73 get 73#elif (_WINDOWS_CE)
74 { 74 get
75 lock(this) 75 {
76 { 76 return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
77 ValidateNotDisposed(); 77 }
78 return _waitersCount; 78 set
79 } 79 {
80 } 80 Thread.SetData(_waiterEntrySlot, value);
81 } 81 }
82 82#else
83 83 get
84 #endregion 84 {
85 85 return _waiterEntry;
86 #region Public methods 86 }
87 87 set
88 /// <summary> 88 {
89 /// Enqueue a work item to the queue. 89 _waiterEntry = value;
90 /// </summary> 90 }
91 public bool EnqueueWorkItem(WorkItem workItem) 91#endif
92 { 92 }
93 // A work item cannot be null, since null is used in the 93
94 // WaitForWorkItem() method to indicate timeout or cancel 94 /// <summary>
95 if (null == workItem) 95 /// A flag that indicates if the WorkItemsQueue has been disposed.
96 { 96 /// </summary>
97 throw new ArgumentNullException("workItem" , "workItem cannot be null"); 97 private bool _isDisposed = false;
98 } 98
99 99 #endregion
100 bool enqueue = true; 100
101 101 #region Public properties
102 // First check if there is a waiter waiting for work item. During 102
103 // the check, timed out waiters are ignored. If there is no 103 /// <summary>
104 // waiter then the work item is queued. 104 /// Returns the current number of work items in the queue
105 lock(this) 105 /// </summary>
106 { 106 public int Count
107 ValidateNotDisposed(); 107 {
108 108 get
109 if (!_isWorkItemsQueueActive) 109 {
110 { 110 return _workItems.Count;
111 return false; 111 }
112 } 112 }
113 113
114 while(_waitersCount > 0) 114 /// <summary>
115 { 115 /// Returns the current number of waiters
116 // Dequeue a waiter. 116 /// </summary>
117 WaiterEntry waiterEntry = PopWaiter(); 117 public int WaitersCount
118 118 {
119 // Signal the waiter. On success break the loop 119 get
120 if (waiterEntry.Signal(workItem)) 120 {
121 { 121 return _waitersCount;
122 enqueue = false; 122 }
123 break; 123 }
124 } 124
125 } 125
126 126 #endregion
127 if (enqueue) 127
128 { 128 #region Public methods
129 // Enqueue the work item 129
130 _workItems.Enqueue(workItem); 130 /// <summary>
131 } 131 /// Enqueue a work item to the queue.
132 } 132 /// </summary>
133 return true; 133 public bool EnqueueWorkItem(WorkItem workItem)
134 } 134 {
135 135 // A work item cannot be null, since null is used in the
136 136 // WaitForWorkItem() method to indicate timeout or cancel
137 /// <summary> 137 if (null == workItem)
138 /// Waits for a work item or exits on timeout or cancel 138 {
139 /// </summary> 139 throw new ArgumentNullException("workItem" , "workItem cannot be null");
140 /// <param name="millisecondsTimeout">Timeout in milliseconds</param> 140 }
141 /// <param name="cancelEvent">Cancel wait handle</param> 141
142 /// <returns>Returns true if the resource was granted</returns> 142 bool enqueue = true;
143 public WorkItem DequeueWorkItem( 143
144 int millisecondsTimeout, 144 // First check if there is a waiter waiting for work item. During
145 WaitHandle cancelEvent) 145 // the check, timed out waiters are ignored. If there is no
146 { 146 // waiter then the work item is queued.
147 /// This method cause the caller to wait for a work item. 147 lock(this)
148 /// If there is at least one waiting work item then the 148 {
149 /// method returns immidiately with true. 149 ValidateNotDisposed();
150 /// 150
151 /// If there are no waiting work items then the caller 151 if (!_isWorkItemsQueueActive)
152 /// is queued between other waiters for a work item to arrive. 152 {
153 /// 153 return false;
154 /// If a work item didn't come within millisecondsTimeout or 154 }
155 /// the user canceled the wait by signaling the cancelEvent 155
156 /// then the method returns false to indicate that the caller 156 while(_waitersCount > 0)
157 /// didn't get a work item. 157 {
158 158 // Dequeue a waiter.
159 WaiterEntry waiterEntry = null; 159 WaiterEntry waiterEntry = PopWaiter();
160 WorkItem workItem = null; 160
161 161 // Signal the waiter. On success break the loop
162 lock(this) 162 if (waiterEntry.Signal(workItem))
163 { 163 {
164 ValidateNotDisposed(); 164 enqueue = false;
165 165 break;
166 // If there are waiting work items then take one and return. 166 }
167 if (_workItems.Count > 0) 167 }
168 { 168
169 workItem = _workItems.Dequeue() as WorkItem; 169 if (enqueue)
170 return workItem; 170 {
171 } 171 // Enqueue the work item
172 // No waiting work items ... 172 _workItems.Enqueue(workItem);
173 else 173 }
174 { 174 }
175 // Get the wait entry for the waiters queue 175 return true;
176 waiterEntry = GetThreadWaiterEntry(); 176 }
177 177
178 // Put the waiter with the other waiters 178
179 PushWaiter(waiterEntry); 179 /// <summary>
180 } 180 /// Waits for a work item or exits on timeout or cancel
181 } 181 /// </summary>
182 182 /// <param name="millisecondsTimeout">Timeout in milliseconds</param>
183 // Prepare array of wait handle for the WaitHandle.WaitAny() 183 /// <param name="cancelEvent">Cancel wait handle</param>
184 WaitHandle [] waitHandles = new WaitHandle [] { 184 /// <returns>Returns true if the resource was granted</returns>
185 waiterEntry.WaitHandle, 185 public WorkItem DequeueWorkItem(
186 cancelEvent }; 186 int millisecondsTimeout,
187 187 WaitHandle cancelEvent)
188 // Wait for an available resource, cancel event, or timeout. 188 {
189 189 // This method cause the caller to wait for a work item.
190 // During the wait we are supposes to exit the synchronization 190 // If there is at least one waiting work item then the
191 // domain. (Placing true as the third argument of the WaitAny()) 191 // method returns immidiately with it.
192 // It just doesn't work, I don't know why, so I have lock(this) 192 //
193 // statments insted of one. 193 // If there are no waiting work items then the caller
194 194 // is queued between other waiters for a work item to arrive.
195 int index = WaitHandle.WaitAny( 195 //
196 waitHandles, 196 // If a work item didn't come within millisecondsTimeout or
197 millisecondsTimeout, 197 // the user canceled the wait by signaling the cancelEvent
198 true); 198 // then the method returns null to indicate that the caller
199 199 // didn't get a work item.
200 lock(this) 200
201 { 201 WaiterEntry waiterEntry;
202 // success is true if it got a work item. 202 WorkItem workItem = null;
203 bool success = (0 == index); 203 lock (this)
204 204 {
205 // The timeout variable is used only for readability. 205 ValidateNotDisposed();
206 // (We treat cancel as timeout) 206
207 bool timeout = !success; 207 // If there are waiting work items then take one and return.
208 208 if (_workItems.Count > 0)
209 // On timeout update the waiterEntry that it is timed out 209 {
210 if (timeout) 210 workItem = _workItems.Dequeue() as WorkItem;
211 { 211 return workItem;
212 // The Timeout() fails if the waiter has already been signaled 212 }
213 timeout = waiterEntry.Timeout(); 213
214 214 // No waiting work items ...
215 // On timeout remove the waiter from the queue. 215
216 // Note that the complexity is O(1). 216 // Get the waiter entry for the waiters queue
217 if(timeout) 217 waiterEntry = GetThreadWaiterEntry();
218 { 218
219 RemoveWaiter(waiterEntry, false); 219 // Put the waiter with the other waiters
220 } 220 PushWaiter(waiterEntry);
221 221 }
222 // Again readability 222
223 success = !timeout; 223 // Prepare array of wait handle for the WaitHandle.WaitAny()
224 } 224 WaitHandle [] waitHandles = new WaitHandle[] {
225 225 waiterEntry.WaitHandle,
226 // On success return the work item 226 cancelEvent };
227 if (success) 227
228 { 228 // Wait for an available resource, cancel event, or timeout.
229 workItem = waiterEntry.WorkItem; 229
230 230 // During the wait we are supposes to exit the synchronization
231 if (null == workItem) 231 // domain. (Placing true as the third argument of the WaitAny())
232 { 232 // It just doesn't work, I don't know why, so I have two lock(this)
233 workItem = _workItems.Dequeue() as WorkItem; 233 // statments instead of one.
234 } 234
235 } 235 int index = STPEventWaitHandle.WaitAny(
236 } 236 waitHandles,
237 // On failure return null. 237 millisecondsTimeout,
238 return workItem; 238 true);
239 } 239
240 240 lock(this)
241 /// <summary> 241 {
242 /// Cleanup the work items queue, hence no more work 242 // success is true if it got a work item.
243 /// items are allowed to be queue 243 bool success = (0 == index);
244 /// </summary> 244
245 protected virtual void Cleanup() 245 // The timeout variable is used only for readability.
246 { 246 // (We treat cancel as timeout)
247 lock(this) 247 bool timeout = !success;
248 { 248
249 // Deactivate only once 249 // On timeout update the waiterEntry that it is timed out
250 if (!_isWorkItemsQueueActive) 250 if (timeout)
251 { 251 {
252 return; 252 // The Timeout() fails if the waiter has already been signaled
253 } 253 timeout = waiterEntry.Timeout();
254 254
255 // Don't queue more work items 255 // On timeout remove the waiter from the queue.
256 _isWorkItemsQueueActive = false; 256 // Note that the complexity is O(1).
257 257 if(timeout)
258 foreach(WorkItem workItem in _workItems) 258 {
259 { 259 RemoveWaiter(waiterEntry, false);
260 workItem.DisposeOfState(); 260 }
261 } 261
262 262 // Again readability
263 // Clear the work items that are already queued 263 success = !timeout;
264 _workItems.Clear(); 264 }
265 265
266 // Note: 266 // On success return the work item
267 // I don't iterate over the queue and dispose of work items's states, 267 if (success)
268 // since if a work item has a state object that is still in use in the 268 {
269 // application then I must not dispose it. 269 workItem = waiterEntry.WorkItem;
270 270
271 // Tell the waiters that they were timed out. 271 if (null == workItem)
272 // It won't signal them to exit, but to ignore their 272 {
273 // next work item. 273 workItem = _workItems.Dequeue() as WorkItem;
274 while(_waitersCount > 0) 274 }
275 { 275 }
276 WaiterEntry waiterEntry = PopWaiter(); 276 }
277 waiterEntry.Timeout(); 277 // On failure return null.
278 } 278 return workItem;
279 } 279 }
280 } 280
281 281 /// <summary>
282 #endregion 282 /// Cleanup the work items queue, hence no more work
283 283 /// items are allowed to be queue
284 #region Private methods 284 /// </summary>
285 285 private void Cleanup()
286 /// <summary> 286 {
287 /// Returns the WaiterEntry of the current thread 287 lock(this)
288 /// </summary> 288 {
289 /// <returns></returns> 289 // Deactivate only once
290 /// In order to avoid creation and destuction of WaiterEntry 290 if (!_isWorkItemsQueueActive)
291 /// objects each thread has its own WaiterEntry object. 291 {
292 private WaiterEntry GetThreadWaiterEntry() 292 return;
293 { 293 }
294 if (null == _waiterEntry) 294
295 { 295 // Don't queue more work items
296 _waiterEntry = new WaiterEntry(); 296 _isWorkItemsQueueActive = false;
297 } 297
298 _waiterEntry.Reset(); 298 foreach(WorkItem workItem in _workItems)
299 return _waiterEntry; 299 {
300 } 300 workItem.DisposeOfState();
301 301 }
302 #region Waiters stack methods 302
303 303 // Clear the work items that are already queued
304 /// <summary> 304 _workItems.Clear();
305 /// Push a new waiter into the waiter's stack 305
306 /// </summary> 306 // Note:
307 /// <param name="newWaiterEntry">A waiter to put in the stack</param> 307 // I don't iterate over the queue and dispose of work items's states,
308 public void PushWaiter(WaiterEntry newWaiterEntry) 308 // since if a work item has a state object that is still in use in the
309 { 309 // application then I must not dispose it.
310 // Remove the waiter if it is already in the stack and 310
311 // update waiter's count as needed 311 // Tell the waiters that they were timed out.
312 RemoveWaiter(newWaiterEntry, false); 312 // It won't signal them to exit, but to ignore their
313 313 // next work item.
314 // If the stack is empty then newWaiterEntry is the new head of the stack 314 while(_waitersCount > 0)
315 if (null == _headWaiterEntry._nextWaiterEntry) 315 {
316 { 316 WaiterEntry waiterEntry = PopWaiter();
317 _headWaiterEntry._nextWaiterEntry = newWaiterEntry; 317 waiterEntry.Timeout();
318 newWaiterEntry._prevWaiterEntry = _headWaiterEntry; 318 }
319 319 }
320 } 320 }
321 // If the stack is not empty then put newWaiterEntry as the new head 321
322 // of the stack. 322 public object[] GetStates()
323 else 323 {
324 { 324 lock (this)
325 // Save the old first waiter entry 325 {
326 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; 326 object[] states = new object[_workItems.Count];
327 327 int i = 0;
328 // Update the links 328 foreach (WorkItem workItem in _workItems)
329 _headWaiterEntry._nextWaiterEntry = newWaiterEntry; 329 {
330 newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; 330 states[i] = workItem.GetWorkItemResult().State;
331 newWaiterEntry._prevWaiterEntry = _headWaiterEntry; 331 ++i;
332 oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; 332 }
333 } 333 return states;
334 334 }
335 // Increment the number of waiters 335 }
336 ++_waitersCount; 336
337 } 337 #endregion
338 338
339 /// <summary> 339 #region Private methods
340 /// Pop a waiter from the waiter's stack 340
341 /// </summary> 341 /// <summary>
342 /// <returns>Returns the first waiter in the stack</returns> 342 /// Returns the WaiterEntry of the current thread
343 private WaiterEntry PopWaiter() 343 /// </summary>
344 { 344 /// <returns></returns>
345 // Store the current stack head 345 /// In order to avoid creation and destuction of WaiterEntry
346 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; 346 /// objects each thread has its own WaiterEntry object.
347 347 private static WaiterEntry GetThreadWaiterEntry()
348 // Store the new stack head 348 {
349 WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; 349 if (null == CurrentWaiterEntry)
350 350 {
351 // Update the old stack head list links and decrement the number 351 CurrentWaiterEntry = new WaiterEntry();
352 // waiters. 352 }
353 RemoveWaiter(oldFirstWaiterEntry, true); 353 CurrentWaiterEntry.Reset();
354 354 return CurrentWaiterEntry;
355 // Update the new stack head 355 }
356 _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; 356
357 if (null != newHeadWaiterEntry) 357 #region Waiters stack methods
358 { 358
359 newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; 359 /// <summary>
360 } 360 /// Push a new waiter into the waiter's stack
361 361 /// </summary>
362 // Return the old stack head 362 /// <param name="newWaiterEntry">A waiter to put in the stack</param>
363 return oldFirstWaiterEntry; 363 public void PushWaiter(WaiterEntry newWaiterEntry)
364 } 364 {
365 365 // Remove the waiter if it is already in the stack and
366 /// <summary> 366 // update waiter's count as needed
367 /// Remove a waiter from the stack 367 RemoveWaiter(newWaiterEntry, false);
368 /// </summary> 368
369 /// <param name="waiterEntry">A waiter entry to remove</param> 369 // If the stack is empty then newWaiterEntry is the new head of the stack
370 /// <param name="popDecrement">If true the waiter count is always decremented</param> 370 if (null == _headWaiterEntry._nextWaiterEntry)
371 private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) 371 {
372 { 372 _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
373 // Store the prev entry in the list 373 newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
374 WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; 374
375 375 }
376 // Store the next entry in the list 376 // If the stack is not empty then put newWaiterEntry as the new head
377 WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; 377 // of the stack.
378 378 else
379 // A flag to indicate if we need to decrement the waiters count. 379 {
380 // If we got here from PopWaiter then we must decrement. 380 // Save the old first waiter entry
381 // If we got here from PushWaiter then we decrement only if 381 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
382 // the waiter was already in the stack. 382
383 bool decrementCounter = popDecrement; 383 // Update the links
384 384 _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
385 // Null the waiter's entry links 385 newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
386 waiterEntry._prevWaiterEntry = null; 386 newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
387 waiterEntry._nextWaiterEntry = null; 387 oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
388 388 }
389 // If the waiter entry had a prev link then update it. 389
390 // It also means that the waiter is already in the list and we 390 // Increment the number of waiters
391 // need to decrement the waiters count. 391 ++_waitersCount;
392 if (null != prevWaiterEntry) 392 }
393 { 393
394 prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; 394 /// <summary>
395 decrementCounter = true; 395 /// Pop a waiter from the waiter's stack
396 } 396 /// </summary>
397 397 /// <returns>Returns the first waiter in the stack</returns>
398 // If the waiter entry had a next link then update it. 398 private WaiterEntry PopWaiter()
399 // It also means that the waiter is already in the list and we 399 {
400 // need to decrement the waiters count. 400 // Store the current stack head
401 if (null != nextWaiterEntry) 401 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
402 { 402
403 nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; 403 // Store the new stack head
404 decrementCounter = true; 404 WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
405 } 405
406 406 // Update the old stack head list links and decrement the number
407 // Decrement the waiters count if needed 407 // waiters.
408 if (decrementCounter) 408 RemoveWaiter(oldFirstWaiterEntry, true);
409 { 409
410 --_waitersCount; 410 // Update the new stack head
411 } 411 _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
412 } 412 if (null != newHeadWaiterEntry)
413 413 {
414 #endregion 414 newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
415 415 }
416 #endregion 416
417 417 // Return the old stack head
418 #region WaiterEntry class 418 return oldFirstWaiterEntry;
419 419 }
420 // A waiter entry in the _waiters queue. 420
421 public class WaiterEntry : IDisposable 421 /// <summary>
422 { 422 /// Remove a waiter from the stack
423 #region Member variables 423 /// </summary>
424 424 /// <param name="waiterEntry">A waiter entry to remove</param>
425 /// <summary> 425 /// <param name="popDecrement">If true the waiter count is always decremented</param>
426 /// Event to signal the waiter that it got the work item. 426 private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
427 /// </summary> 427 {
428 private AutoResetEvent _waitHandle = new AutoResetEvent(false); 428 // Store the prev entry in the list
429 429 WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
430 /// <summary> 430
431 /// Flag to know if this waiter already quited from the queue 431 // Store the next entry in the list
432 /// because of a timeout. 432 WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
433 /// </summary> 433
434 private bool _isTimedout = false; 434 // A flag to indicate if we need to decrement the waiters count.
435 435 // If we got here from PopWaiter then we must decrement.
436 /// <summary> 436 // If we got here from PushWaiter then we decrement only if
437 /// Flag to know if the waiter was signaled and got a work item. 437 // the waiter was already in the stack.
438 /// </summary> 438 bool decrementCounter = popDecrement;
439 private bool _isSignaled = false; 439
440 440 // Null the waiter's entry links
441 /// <summary> 441 waiterEntry._prevWaiterEntry = null;
442 /// A work item that passed directly to the waiter withou going 442 waiterEntry._nextWaiterEntry = null;
443 /// through the queue 443
444 /// </summary> 444 // If the waiter entry had a prev link then update it.
445 private WorkItem _workItem = null; 445 // It also means that the waiter is already in the list and we
446 446 // need to decrement the waiters count.
447 private bool _isDisposed = false; 447 if (null != prevWaiterEntry)
448 448 {
449 // Linked list members 449 prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
450 internal WaiterEntry _nextWaiterEntry = null; 450 decrementCounter = true;
451 internal WaiterEntry _prevWaiterEntry = null; 451 }
452 452
453 #endregion 453 // If the waiter entry had a next link then update it.
454 454 // It also means that the waiter is already in the list and we
455 #region Construction 455 // need to decrement the waiters count.
456 456 if (null != nextWaiterEntry)
457 public WaiterEntry() 457 {
458 { 458 nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
459 Reset(); 459 decrementCounter = true;
460 } 460 }
461 461
462 #endregion 462 // Decrement the waiters count if needed
463 463 if (decrementCounter)
464 #region Public methods 464 {
465 465 --_waitersCount;
466 public WaitHandle WaitHandle 466 }
467 { 467 }
468 get { return _waitHandle; } 468
469 } 469 #endregion
470 470
471 public WorkItem WorkItem 471 #endregion
472 { 472
473 get 473 #region WaiterEntry class
474 { 474
475 lock(this) 475 // A waiter entry in the _waiters queue.
476 { 476 public sealed class WaiterEntry : IDisposable
477 return _workItem; 477 {
478 } 478 #region Member variables
479 } 479
480 } 480 /// <summary>
481 481 /// Event to signal the waiter that it got the work item.
482 /// <summary> 482 /// </summary>
483 /// Signal the waiter that it got a work item. 483 //private AutoResetEvent _waitHandle = new AutoResetEvent(false);
484 /// </summary> 484 private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
485 /// <returns>Return true on success</returns> 485
486 /// The method fails if Timeout() preceded its call 486 /// <summary>
487 public bool Signal(WorkItem workItem) 487 /// Flag to know if this waiter already quited from the queue
488 { 488 /// because of a timeout.
489 lock(this) 489 /// </summary>
490 { 490 private bool _isTimedout = false;
491 if (!_isTimedout) 491
492 { 492 /// <summary>
493 _workItem = workItem; 493 /// Flag to know if the waiter was signaled and got a work item.
494 _isSignaled = true; 494 /// </summary>
495 _waitHandle.Set(); 495 private bool _isSignaled = false;
496 return true; 496
497 } 497 /// <summary>
498 } 498 /// A work item that passed directly to the waiter withou going
499 return false; 499 /// through the queue
500 } 500 /// </summary>
501 501 private WorkItem _workItem = null;
502 /// <summary> 502
503 /// Mark the wait entry that it has been timed out 503 private bool _isDisposed = false;
504 /// </summary> 504
505 /// <returns>Return true on success</returns> 505 // Linked list members
506 /// The method fails if Signal() preceded its call 506 internal WaiterEntry _nextWaiterEntry = null;
507 public bool Timeout() 507 internal WaiterEntry _prevWaiterEntry = null;
508 { 508
509 lock(this) 509 #endregion
510 { 510
511 // Time out can happen only if the waiter wasn't marked as 511 #region Construction
512 // signaled 512
513 if (!_isSignaled) 513 public WaiterEntry()
514 { 514 {
515 // We don't remove the waiter from the queue, the DequeueWorkItem 515 Reset();
516 // method skips _waiters that were timed out. 516 }
517 _isTimedout = true; 517
518 return true; 518 #endregion
519 } 519
520 } 520 #region Public methods
521 return false; 521
522 } 522 public WaitHandle WaitHandle
523 523 {
524 /// <summary> 524 get { return _waitHandle; }
525 /// Reset the wait entry so it can be used again 525 }
526 /// </summary> 526
527 public void Reset() 527 public WorkItem WorkItem
528 { 528 {
529 _workItem = null; 529 get
530 _isTimedout = false; 530 {
531 _isSignaled = false; 531 return _workItem;
532 _waitHandle.Reset(); 532 }
533 } 533 }
534 534
535 /// <summary> 535 /// <summary>
536 /// Free resources 536 /// Signal the waiter that it got a work item.
537 /// </summary> 537 /// </summary>
538 public void Close() 538 /// <returns>Return true on success</returns>
539 { 539 /// The method fails if Timeout() preceded its call
540 if (null != _waitHandle) 540 public bool Signal(WorkItem workItem)
541 { 541 {
542 _waitHandle.Close(); 542 lock(this)
543 _waitHandle = null; 543 {
544 } 544 if (!_isTimedout)
545 } 545 {
546 546 _workItem = workItem;
547 #endregion 547 _isSignaled = true;
548 548 _waitHandle.Set();
549 #region IDisposable Members 549 return true;
550 550 }
551 public void Dispose() 551 }
552 { 552 return false;
553 if (!_isDisposed) 553 }
554 { 554
555 Close(); 555 /// <summary>
556 _isDisposed = true; 556 /// Mark the wait entry that it has been timed out
557 } 557 /// </summary>
558 } 558 /// <returns>Return true on success</returns>
559 559 /// The method fails if Signal() preceded its call
560 ~WaiterEntry() 560 public bool Timeout()
561 { 561 {
562 Dispose(); 562 lock(this)
563 } 563 {
564 564 // Time out can happen only if the waiter wasn't marked as
565 #endregion 565 // signaled
566 } 566 if (!_isSignaled)
567 567 {
568 #endregion 568 // We don't remove the waiter from the queue, the DequeueWorkItem
569 569 // method skips _waiters that were timed out.
570 #region IDisposable Members 570 _isTimedout = true;
571 571 return true;
572 public void Dispose() 572 }
573 { 573 }
574 if (!_isDisposed) 574 return false;
575 { 575 }
576 Cleanup(); 576
577 _isDisposed = true; 577 /// <summary>
578 GC.SuppressFinalize(this); 578 /// Reset the wait entry so it can be used again
579 } 579 /// </summary>
580 } 580 public void Reset()
581 581 {
582 ~WorkItemsQueue() 582 _workItem = null;
583 { 583 _isTimedout = false;
584 Cleanup(); 584 _isSignaled = false;
585 } 585 _waitHandle.Reset();
586 586 }
587 private void ValidateNotDisposed() 587
588 { 588 /// <summary>
589 if(_isDisposed) 589 /// Free resources
590 { 590 /// </summary>
591 throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); 591 public void Close()
592 } 592 {
593 } 593 if (null != _waitHandle)
594 594 {
595 #endregion 595 _waitHandle.Close();
596 } 596 _waitHandle = null;
597 597 }
598 #endregion 598 }
599} 599
600 600 #endregion
601
602 #region IDisposable Members
603
604 public void Dispose()
605 {
606 lock (this)
607 {
608 if (!_isDisposed)
609 {
610 Close();
611 }
612 _isDisposed = true;
613 }
614 }
615
616 #endregion
617 }
618
619 #endregion
620
621 #region IDisposable Members
622
623 public void Dispose()
624 {
625 if (!_isDisposed)
626 {
627 Cleanup();
628 }
629 _isDisposed = true;
630 }
631
632 private void ValidateNotDisposed()
633 {
634 if(_isDisposed)
635 {
636 throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
637 }
638 }
639
640 #endregion
641 }
642
643 #endregion
644}
645