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