diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index bde46731a1..a3602e93f2 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1840,7 +1840,7 @@ namespace OpenSim.Framework
case FireAndForgetMethod.SmartThreadPool:
if (m_ThreadPool == null)
InitThreadPool(15);
- m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
+ m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
break;
case FireAndForgetMethod.Thread:
Thread thread = new Thread(delegate(object o) { realCallback(o); });
@@ -1910,15 +1910,15 @@ namespace OpenSim.Framework
return sb.ToString();
}
- private static object SmartThreadPoolCallback(object o)
- {
- object[] array = (object[])o;
- WaitCallback callback = (WaitCallback)array[0];
- object obj = array[1];
-
- callback(obj);
- return null;
- }
+// private static object SmartThreadPoolCallback(object o)
+// {
+// object[] array = (object[])o;
+// WaitCallback callback = (WaitCallback)array[0];
+// object obj = array[1];
+//
+// callback(obj);
+// return null;
+// }
#endregion FireAndForget Threading Pattern
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 35ae44c315..b9a217b649 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
public interface IScriptWorkItem
{
bool Cancel();
- void Abort();
+ bool Abort();
///
/// Wait for the work item to complete.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 1e6db4372d..f9d3afc126 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -564,9 +564,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public bool Stop(int timeout)
{
-// m_log.DebugFormat(
-// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
-// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
+ if (DebugLevel >= 1)
+ m_log.DebugFormat(
+ "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
+ ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
IScriptWorkItem workItem;
@@ -627,6 +628,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
}
}
+ Console.WriteLine("Here9");
+
lock (EventQueue)
{
workItem = m_CurrentWorkItem;
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 0d9babbca8..5804aa87f2 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -483,7 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
///
/// Basis on which to sort output. Can be null if no sort needs to take place
private void HandleScriptsAction(
- string[] cmdparams, Action action, Func keySelector)
+ string[] cmdparams, Action action, System.Func keySelector)
{
if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
return;
@@ -1517,7 +1517,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
startInfo.MaxWorkerThreads = maxThreads;
startInfo.MinWorkerThreads = minThreads;
startInfo.ThreadPriority = threadPriority;;
- startInfo.StackSize = stackSize;
+ startInfo.MaxStackSize = stackSize;
startInfo.StartSuspended = true;
m_ThreadPool = new SmartThreadPool(startInfo);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
index 8dd7677d7f..9d9dee182d 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
return wr.Cancel();
}
- public void Abort()
+ public bool Abort()
{
- wr.Abort();
+ return wr.Cancel(true);
}
public bool Wait(int t)
{
// We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
// TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
- // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8
+ // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8
// (or very likely other versions of Mono at least up until 3.0.3).
return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
}
diff --git a/ThirdParty/SmartThreadPool/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/AssemblyInfo.cs
deleted file mode 100644
index e2465b032b..0000000000
--- a/ThirdParty/SmartThreadPool/AssemblyInfo.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-//
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-//
-[assembly: AssemblyTitle("")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: ComVisible(false)]
-[assembly: CLSCompliant(true)]
-
-//
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-
-[assembly: AssemblyVersion("0.7.6.*")]
-
-//
-// In order to sign your assembly you must specify a key to use. Refer to the
-// Microsoft .NET Framework documentation for more information on assembly signing.
-//
-// Use the attributes below to control which key is used for signing.
-//
-// Notes:
-// (*) If no key is specified, the assembly is not signed.
-// (*) KeyName refers to a key that has been installed in the Crypto Service
-// Provider (CSP) on your machine. KeyFile refers to a file which contains
-// a key.
-// (*) If the KeyFile and the KeyName values are both specified, the
-// following processing occurs:
-// (1) If the KeyName can be found in the CSP, that key is used.
-// (2) If the KeyName does not exist and the KeyFile does exist, the key
-// in the KeyFile is installed into the CSP and used.
-// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
-// When specifying the KeyFile, the location of the KeyFile should be
-// relative to the project output directory which is
-// %Project Directory%\obj\. For example, if your KeyFile is
-// located in the project directory, you would specify the AssemblyKeyFile
-// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
-// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
-// documentation for more information on this.
-//
-[assembly: AssemblyDelaySign(false)]
-[assembly: AssemblyKeyFile("")]
-[assembly: AssemblyKeyName("")]
diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs
index 6ea53f65d0..2177241a02 100644
--- a/ThirdParty/SmartThreadPool/CallerThreadContext.cs
+++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs
@@ -1,223 +1,138 @@
-using System;
-using System.Diagnostics;
-using System.Threading;
-using System.Reflection;
-using System.Web;
-using System.Runtime.Remoting.Messaging;
-
-
-namespace Amib.Threading
-{
- #region CallerThreadContext class
-
- ///
- /// This class stores the caller call context in order to restore
- /// it when the work item is executed in the thread pool environment.
- ///
- internal class CallerThreadContext
- {
- #region Prepare reflection information
-
- // Cached type information.
- private static MethodInfo getLogicalCallContextMethodInfo =
- typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
-
- private static MethodInfo setLogicalCallContextMethodInfo =
- typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
-
- private static string HttpContextSlotName = GetHttpContextSlotName();
-
- private static string GetHttpContextSlotName()
- {
- FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
-
- if( fi != null )
- return (string)fi.GetValue(null);
- else // Use the default "HttpContext" slot name
- return "HttpContext";
- }
-
- #endregion
-
- #region Private fields
-
- private HttpContext _httpContext = null;
- private LogicalCallContext _callContext = null;
-
- #endregion
-
- ///
- /// Constructor
- ///
- private CallerThreadContext()
- {
- }
-
- public bool CapturedCallContext
- {
- get
- {
- return (null != _callContext);
- }
- }
-
- public bool CapturedHttpContext
- {
- get
- {
- return (null != _httpContext);
- }
- }
-
- ///
- /// Captures the current thread context
- ///
- ///
- public static CallerThreadContext Capture(
- bool captureCallContext,
- bool captureHttpContext)
- {
- Debug.Assert(captureCallContext || captureHttpContext);
-
- CallerThreadContext callerThreadContext = new CallerThreadContext();
-
- // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
- // Capture Call Context
- if(captureCallContext && (getLogicalCallContextMethodInfo != null))
- {
- callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
- if (callerThreadContext._callContext != null)
- {
- callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
- }
- }
-
- // Capture httpContext
- if (captureHttpContext && (null != HttpContext.Current))
- {
- callerThreadContext._httpContext = HttpContext.Current;
- }
-
- return callerThreadContext;
- }
-
- ///
- /// Applies the thread context stored earlier
- ///
- ///
- public static void Apply(CallerThreadContext callerThreadContext)
- {
- if (null == callerThreadContext)
- {
- throw new ArgumentNullException("callerThreadContext");
- }
-
- // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
- // Restore call context
- if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
- {
- setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
- }
-
- // Restore HttpContext
- if (callerThreadContext._httpContext != null)
- {
- CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
- }
- }
- }
-
- #endregion
-
-}
-
-
-/*
-// Ami Bar
-// amibar@gmail.com
-
-using System;
-using System.Threading;
-using System.Globalization;
-using System.Security.Principal;
-using System.Reflection;
-using System.Runtime.Remoting.Contexts;
-
-namespace Amib.Threading.Internal
-{
- #region CallerThreadContext class
-
- ///
- /// This class stores the caller thread context in order to restore
- /// it when the work item is executed in the context of the thread
- /// from the pool.
- /// Note that we can't store the thread's CompressedStack, because
- /// it throws a security exception
- ///
- public class CallerThreadContext
- {
- private CultureInfo _culture = null;
- private CultureInfo _cultureUI = null;
- private IPrincipal _principal;
- private System.Runtime.Remoting.Contexts.Context _context;
-
- private static FieldInfo _fieldInfo = GetFieldInfo();
-
- private static FieldInfo GetFieldInfo()
- {
- Type threadType = typeof(Thread);
- return threadType.GetField(
- "m_Context",
- BindingFlags.Instance | BindingFlags.NonPublic);
- }
-
- ///
- /// Constructor
- ///
- private CallerThreadContext()
- {
- }
-
- ///
- /// Captures the current thread context
- ///
- ///
- public static CallerThreadContext Capture()
- {
- CallerThreadContext callerThreadContext = new CallerThreadContext();
-
- Thread thread = Thread.CurrentThread;
- callerThreadContext._culture = thread.CurrentCulture;
- callerThreadContext._cultureUI = thread.CurrentUICulture;
- callerThreadContext._principal = Thread.CurrentPrincipal;
- callerThreadContext._context = Thread.CurrentContext;
- return callerThreadContext;
- }
-
- ///
- /// Applies the thread context stored earlier
- ///
- ///
- public static void Apply(CallerThreadContext callerThreadContext)
- {
- Thread thread = Thread.CurrentThread;
- thread.CurrentCulture = callerThreadContext._culture;
- thread.CurrentUICulture = callerThreadContext._cultureUI;
- Thread.CurrentPrincipal = callerThreadContext._principal;
-
- // Uncomment the following block to enable the Thread.CurrentThread
-/*
- if (null != _fieldInfo)
- {
- _fieldInfo.SetValue(
- Thread.CurrentThread,
- callerThreadContext._context);
- }
-* /
- }
- }
-
- #endregion
-}
-*/
-
+
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Reflection;
+using System.Web;
+using System.Runtime.Remoting.Messaging;
+
+
+namespace Amib.Threading.Internal
+{
+#region CallerThreadContext class
+
+ ///
+ /// This class stores the caller call context in order to restore
+ /// it when the work item is executed in the thread pool environment.
+ ///
+ internal class CallerThreadContext
+ {
+#region Prepare reflection information
+
+ // Cached type information.
+ private static readonly MethodInfo getLogicalCallContextMethodInfo =
+ typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ private static readonly MethodInfo setLogicalCallContextMethodInfo =
+ typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ private static string HttpContextSlotName = GetHttpContextSlotName();
+
+ private static string GetHttpContextSlotName()
+ {
+ FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
+
+ if (fi != null)
+ {
+ return (string) fi.GetValue(null);
+ }
+
+ return "HttpContext";
+ }
+
+ #endregion
+
+#region Private fields
+
+ private HttpContext _httpContext;
+ private LogicalCallContext _callContext;
+
+ #endregion
+
+ ///
+ /// Constructor
+ ///
+ private CallerThreadContext()
+ {
+ }
+
+ public bool CapturedCallContext
+ {
+ get
+ {
+ return (null != _callContext);
+ }
+ }
+
+ public bool CapturedHttpContext
+ {
+ get
+ {
+ return (null != _httpContext);
+ }
+ }
+
+ ///
+ /// Captures the current thread context
+ ///
+ ///
+ public static CallerThreadContext Capture(
+ bool captureCallContext,
+ bool captureHttpContext)
+ {
+ Debug.Assert(captureCallContext || captureHttpContext);
+
+ CallerThreadContext callerThreadContext = new CallerThreadContext();
+
+ // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
+ // Capture Call Context
+ if(captureCallContext && (getLogicalCallContextMethodInfo != null))
+ {
+ callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
+ if (callerThreadContext._callContext != null)
+ {
+ callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
+ }
+ }
+
+ // Capture httpContext
+ if (captureHttpContext && (null != HttpContext.Current))
+ {
+ callerThreadContext._httpContext = HttpContext.Current;
+ }
+
+ return callerThreadContext;
+ }
+
+ ///
+ /// Applies the thread context stored earlier
+ ///
+ ///
+ public static void Apply(CallerThreadContext callerThreadContext)
+ {
+ if (null == callerThreadContext)
+ {
+ throw new ArgumentNullException("callerThreadContext");
+ }
+
+ // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
+ // Restore call context
+ if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
+ {
+ setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
+ }
+
+ // Restore HttpContext
+ if (callerThreadContext._httpContext != null)
+ {
+ HttpContext.Current = callerThreadContext._httpContext;
+ //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
+ }
+ }
+ }
+
+ #endregion
+}
+#endif
diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
new file mode 100644
index 0000000000..4a2a3e7bc3
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
@@ -0,0 +1,14 @@
+namespace Amib.Threading.Internal
+{
+ internal class CanceledWorkItemsGroup
+ {
+ public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
+
+ public CanceledWorkItemsGroup()
+ {
+ IsCanceled = false;
+ }
+
+ public bool IsCanceled { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs
new file mode 100644
index 0000000000..70a1a29b93
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs
@@ -0,0 +1,104 @@
+#if (_WINDOWS_CE)
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace Amib.Threading.Internal
+{
+ ///
+ /// EventWaitHandle class
+ /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation.
+ /// So I wrote this class to implement these two methods with some of their overloads.
+ /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny.
+ /// Note that this class doesn't even inherit from WaitHandle!
+ ///
+ public class STPEventWaitHandle
+ {
+ #region Public Constants
+
+ public const int WaitTimeout = Timeout.Infinite;
+
+ #endregion
+
+ #region Private External Constants
+
+ private const Int32 WAIT_FAILED = -1;
+ private const Int32 WAIT_TIMEOUT = 0x102;
+ private const UInt32 INFINITE = 0xFFFFFFFF;
+
+ #endregion
+
+ #region WaitAll and WaitAny
+
+ internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
+ {
+ return waitHandle.WaitOne(millisecondsTimeout, exitContext);
+ }
+
+ private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles)
+ {
+ IntPtr[] nativeHandles = new IntPtr[waitHandles.Length];
+ for (int i = 0; i < waitHandles.Length; i++)
+ {
+ nativeHandles[i] = waitHandles[i].Handle;
+ }
+ return nativeHandles;
+ }
+
+ public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
+ {
+ uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
+
+ IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
+
+ int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout);
+
+ if (result == WAIT_TIMEOUT || result == WAIT_FAILED)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
+ {
+ uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
+
+ IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
+
+ int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout);
+
+ if (result >= 0 && result < waitHandles.Length)
+ {
+ return result;
+ }
+
+ return -1;
+ }
+
+ public static int WaitAny(WaitHandle[] waitHandles)
+ {
+ return WaitAny(waitHandles, Timeout.Infinite, false);
+ }
+
+ public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
+ {
+ int millisecondsTimeout = (int)timeout.TotalMilliseconds;
+
+ return WaitAny(waitHandles, millisecondsTimeout, false);
+ }
+
+ #endregion
+
+ #region External methods
+
+ [DllImport("coredll.dll", SetLastError = true)]
+ public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds);
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
new file mode 100644
index 0000000000..2f8c55b098
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
@@ -0,0 +1,82 @@
+using System.Threading;
+
+#if (_WINDOWS_CE)
+using System;
+using System.Runtime.InteropServices;
+#endif
+
+namespace Amib.Threading.Internal
+{
+ ///
+ /// EventWaitHandleFactory class.
+ /// This is a static class that creates AutoResetEvent and ManualResetEvent objects.
+ /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property
+ /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API.
+ /// Consequently this class creates the needed XxxResetEvent and replaces the handle if
+ /// it's a WindowsCE OS.
+ ///
+ public static class EventWaitHandleFactory
+ {
+ ///
+ /// Create a new AutoResetEvent object
+ ///
+ /// Return a new AutoResetEvent object
+ public static AutoResetEvent CreateAutoResetEvent()
+ {
+ AutoResetEvent waitHandle = new AutoResetEvent(false);
+
+#if (_WINDOWS_CE)
+ ReplaceEventHandle(waitHandle, false, false);
+#endif
+
+ return waitHandle;
+ }
+
+ ///
+ /// Create a new ManualResetEvent object
+ ///
+ /// Return a new ManualResetEvent object
+ public static ManualResetEvent CreateManualResetEvent(bool initialState)
+ {
+ ManualResetEvent waitHandle = new ManualResetEvent(initialState);
+
+#if (_WINDOWS_CE)
+ ReplaceEventHandle(waitHandle, true, initialState);
+#endif
+
+ return waitHandle;
+ }
+
+#if (_WINDOWS_CE)
+
+ ///
+ /// Replace the event handle
+ ///
+ /// The WaitHandle object which its handle needs to be replaced.
+ /// Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)
+ /// The initial state of the event
+ private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState)
+ {
+ // Store the old handle
+ IntPtr oldHandle = waitHandle.Handle;
+
+ // Create a new event
+ IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null);
+
+ // Replace the old event with the new event
+ waitHandle.Handle = newHandle;
+
+ // Close the old event
+ CloseHandle (oldHandle);
+ }
+
+ [DllImport("coredll.dll", SetLastError = true)]
+ public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
+
+ //Handle
+ [DllImport("coredll.dll", SetLastError = true)]
+ public static extern bool CloseHandle(IntPtr hObject);
+#endif
+
+ }
+}
diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs
index c454709051..8e66ce9c84 100644
--- a/ThirdParty/SmartThreadPool/Exceptions.cs
+++ b/ThirdParty/SmartThreadPool/Exceptions.cs
@@ -1,81 +1,111 @@
-// Ami Bar
-// amibar@gmail.com
-
-using System;
-using System.Runtime.Serialization;
-
-namespace Amib.Threading
-{
- #region Exceptions
-
- ///
- /// Represents an exception in case IWorkItemResult.GetResult has been canceled
- ///
- [Serializable]
- public sealed class WorkItemCancelException : ApplicationException
- {
- public WorkItemCancelException() : base()
- {
- }
-
- public WorkItemCancelException(string message) : base(message)
- {
- }
-
- public WorkItemCancelException(string message, Exception e) : base(message, e)
- {
- }
-
- public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc)
- {
- }
- }
-
- ///
- /// Represents an exception in case IWorkItemResult.GetResult has been timed out
- ///
- [Serializable]
- public sealed class WorkItemTimeoutException : ApplicationException
- {
- public WorkItemTimeoutException() : base()
- {
- }
-
- public WorkItemTimeoutException(string message) : base(message)
- {
- }
-
- public WorkItemTimeoutException(string message, Exception e) : base(message, e)
- {
- }
-
- public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc)
- {
- }
- }
-
- ///
- /// Represents an exception in case IWorkItemResult.GetResult has been timed out
- ///
- [Serializable]
- public sealed class WorkItemResultException : ApplicationException
- {
- public WorkItemResultException() : base()
- {
- }
-
- public WorkItemResultException(string message) : base(message)
- {
- }
-
- public WorkItemResultException(string message, Exception e) : base(message, e)
- {
- }
-
- public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc)
- {
- }
- }
-
- #endregion
-}
+using System;
+#if !(_WINDOWS_CE)
+using System.Runtime.Serialization;
+#endif
+
+namespace Amib.Threading
+{
+ #region Exceptions
+
+ ///
+ /// Represents an exception in case IWorkItemResult.GetResult has been canceled
+ ///
+ public sealed partial class WorkItemCancelException : Exception
+ {
+ public WorkItemCancelException()
+ {
+ }
+
+ public WorkItemCancelException(string message)
+ : base(message)
+ {
+ }
+
+ public WorkItemCancelException(string message, Exception e)
+ : base(message, e)
+ {
+ }
+ }
+
+ ///
+ /// Represents an exception in case IWorkItemResult.GetResult has been timed out
+ ///
+ public sealed partial class WorkItemTimeoutException : Exception
+ {
+ public WorkItemTimeoutException()
+ {
+ }
+
+ public WorkItemTimeoutException(string message)
+ : base(message)
+ {
+ }
+
+ public WorkItemTimeoutException(string message, Exception e)
+ : base(message, e)
+ {
+ }
+ }
+
+ ///
+ /// Represents an exception in case IWorkItemResult.GetResult has been timed out
+ ///
+ public sealed partial class WorkItemResultException : Exception
+ {
+ public WorkItemResultException()
+ {
+ }
+
+ public WorkItemResultException(string message)
+ : base(message)
+ {
+ }
+
+ public WorkItemResultException(string message, Exception e)
+ : base(message, e)
+ {
+ }
+ }
+
+
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
+ ///
+ /// Represents an exception in case IWorkItemResult.GetResult has been canceled
+ ///
+ [Serializable]
+ public sealed partial class WorkItemCancelException
+ {
+ public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
+ : base(si, sc)
+ {
+ }
+ }
+
+ ///
+ /// Represents an exception in case IWorkItemResult.GetResult has been timed out
+ ///
+ [Serializable]
+ public sealed partial class WorkItemTimeoutException
+ {
+ public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
+ : base(si, sc)
+ {
+ }
+ }
+
+ ///
+ /// Represents an exception in case IWorkItemResult.GetResult has been timed out
+ ///
+ [Serializable]
+ public sealed partial class WorkItemResultException
+ {
+ public WorkItemResultException(SerializationInfo si, StreamingContext sc)
+ : base(si, sc)
+ {
+ }
+ }
+
+#endif
+
+ #endregion
+}
diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs
index f1c1fcf3ba..29c8a3e766 100644
--- a/ThirdParty/SmartThreadPool/Interfaces.cs
+++ b/ThirdParty/SmartThreadPool/Interfaces.cs
@@ -1,271 +1,628 @@
-// Ami Bar
-// amibar@gmail.com
-
-using System;
-using System.Threading;
-
-namespace Amib.Threading
-{
- #region Delegates
-
- ///
- /// A delegate that represents the method to run as the work item
- ///
- /// A state object for the method to run
- public delegate object WorkItemCallback(object state);
-
- ///
- /// A delegate to call after the WorkItemCallback completed
- ///
- /// The work item result object
- public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
-
- ///
- /// A delegate to call when a WorkItemsGroup becomes idle
- ///
- /// A reference to the WorkItemsGroup that became idle
- public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
-
- #endregion
-
- #region WorkItem Priority
-
- public enum WorkItemPriority
- {
- Lowest,
- BelowNormal,
- Normal,
- AboveNormal,
- Highest,
- }
-
- #endregion
-
- #region IHasWorkItemPriority interface
-
- public interface IHasWorkItemPriority
- {
- WorkItemPriority WorkItemPriority { get; }
- }
-
- #endregion
-
- #region IWorkItemsGroup interface
-
- ///
- /// IWorkItemsGroup interface
- ///
- public interface IWorkItemsGroup
- {
- ///
- /// Get/Set the name of the WorkItemsGroup
- ///
- string Name { get; set; }
-
- IWorkItemResult QueueWorkItem(WorkItemCallback callback);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
- IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
-
- IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
- IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
-
- void WaitForIdle();
- bool WaitForIdle(TimeSpan timeout);
- bool WaitForIdle(int millisecondsTimeout);
-
- int WaitingCallbacks { get; }
- event WorkItemsGroupIdleHandler OnIdle;
-
- void Cancel();
- void Start();
- }
-
- #endregion
-
- #region CallToPostExecute enumerator
-
- [Flags]
- public enum CallToPostExecute
- {
- Never = 0x00,
- WhenWorkItemCanceled = 0x01,
- WhenWorkItemNotCanceled = 0x02,
- Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
- }
-
- #endregion
-
- #region IWorkItemResult interface
-
- ///
- /// IWorkItemResult interface
- ///
- public interface IWorkItemResult
- {
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits.
- ///
- /// The result of the work item
- object GetResult();
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout.
- ///
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- object GetResult(
- int millisecondsTimeout,
- bool exitContext);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout.
- ///
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- object GetResult(
- TimeSpan timeout,
- bool exitContext);
-
- void Abort();
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
- ///
- /// Timeout in milliseconds, or -1 for infinite
- ///
- /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
- ///
- /// A cancel wait handle to interrupt the blocking if needed
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- /// On cancel throws WorkItemCancelException
- object GetResult(
- int millisecondsTimeout,
- bool exitContext,
- WaitHandle cancelWaitHandle);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
- ///
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- /// On cancel throws WorkItemCancelException
- object GetResult(
- TimeSpan timeout,
- bool exitContext,
- WaitHandle cancelWaitHandle);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits.
- ///
- /// Filled with the exception if one was thrown
- /// The result of the work item
- object GetResult(out Exception e);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout.
- ///
- /// Filled with the exception if one was thrown
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- object GetResult(
- int millisecondsTimeout,
- bool exitContext,
- out Exception e);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout.
- ///
- /// Filled with the exception if one was thrown
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- object GetResult(
- TimeSpan timeout,
- bool exitContext,
- out Exception e);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
- ///
- /// Timeout in milliseconds, or -1 for infinite
- ///
- /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
- ///
- /// A cancel wait handle to interrupt the blocking if needed
- /// Filled with the exception if one was thrown
- /// The result of the work item
- /// On timeout throws WorkItemTimeoutException
- /// On cancel throws WorkItemCancelException
- object GetResult(
- int millisecondsTimeout,
- bool exitContext,
- WaitHandle cancelWaitHandle,
- out Exception e);
-
- ///
- /// Get the result of the work item.
- /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
- ///
- /// The result of the work item
- /// Filled with the exception if one was thrown
- /// On timeout throws WorkItemTimeoutException
- /// On cancel throws WorkItemCancelException
- object GetResult(
- TimeSpan timeout,
- bool exitContext,
- WaitHandle cancelWaitHandle,
- out Exception e);
-
- ///
- /// Gets an indication whether the asynchronous operation has completed.
- ///
- bool IsCompleted { get; }
-
- ///
- /// Gets an indication whether the asynchronous operation has been canceled.
- ///
- bool IsCanceled { get; }
-
- ///
- /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
- ///
- object State { get; }
-
- ///
- /// Cancel the work item if it didn't start running yet.
- ///
- /// Returns true on success or false if the work item is in progress or already completed
- bool Cancel();
-
- ///
- /// Get the work item's priority
- ///
- WorkItemPriority WorkItemPriority { get; }
-
- ///
- /// Return the result, same as GetResult()
- ///
- object Result { get; }
-
- ///
- /// Returns the exception if occured otherwise returns null.
- ///
- object Exception { get; }
- }
-
- #endregion
-}
+using System;
+using System.Threading;
+
+namespace Amib.Threading
+{
+ #region Delegates
+
+ ///
+ /// A delegate that represents the method to run as the work item
+ ///
+ /// A state object for the method to run
+ public delegate object WorkItemCallback(object state);
+
+ ///
+ /// A delegate to call after the WorkItemCallback completed
+ ///
+ /// The work item result object
+ public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
+
+ ///
+ /// A delegate to call after the WorkItemCallback completed
+ ///
+ /// The work item result object
+ public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
+
+ ///
+ /// A delegate to call when a WorkItemsGroup becomes idle
+ ///
+ /// A reference to the WorkItemsGroup that became idle
+ public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
+
+ ///
+ /// A delegate to call after a thread is created, but before
+ /// it's first use.
+ ///
+ public delegate void ThreadInitializationHandler();
+
+ ///
+ /// A delegate to call when a thread is about to exit, after
+ /// it is no longer belong to the pool.
+ ///
+ public delegate void ThreadTerminationHandler();
+
+ #endregion
+
+ #region WorkItem Priority
+
+ ///
+ /// Defines the availeable priorities of a work item.
+ /// The higher the priority a work item has, the sooner
+ /// it will be executed.
+ ///
+ public enum WorkItemPriority
+ {
+ Lowest,
+ BelowNormal,
+ Normal,
+ AboveNormal,
+ Highest,
+ }
+
+ #endregion
+
+ #region IWorkItemsGroup interface
+
+ ///
+ /// IWorkItemsGroup interface
+ /// Created by SmartThreadPool.CreateWorkItemsGroup()
+ ///
+ public interface IWorkItemsGroup
+ {
+ ///
+ /// Get/Set the name of the WorkItemsGroup
+ ///
+ string Name { get; set; }
+
+ ///
+ /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
+ ///
+ int Concurrency { get; set; }
+
+ ///
+ /// Get the number of work items waiting in the queue.
+ ///
+ int WaitingCallbacks { get; }
+
+ ///
+ /// Get an array with all the state objects of the currently running items.
+ /// The array represents a snap shot and impact performance.
+ ///
+ object[] GetStates();
+
+ ///
+ /// Get the WorkItemsGroup start information
+ ///
+ WIGStartInfo WIGStartInfo { get; }
+
+ ///
+ /// Starts to execute work items
+ ///
+ void Start();
+
+ ///
+ /// Cancel all the work items.
+ /// Same as Cancel(false)
+ ///
+ void Cancel();
+
+ ///
+ /// Cancel all work items using thread abortion
+ ///
+ /// True to stop work items by raising ThreadAbortException
+ void Cancel(bool abortExecution);
+
+ ///
+ /// Wait for all work item to complete.
+ ///
+ void WaitForIdle();
+
+ ///
+ /// Wait for all work item to complete, until timeout expired
+ ///
+ /// How long to wait for the work items to complete
+ /// Returns true if work items completed within the timeout, otherwise false.
+ bool WaitForIdle(TimeSpan timeout);
+
+ ///
+ /// Wait for all work item to complete, until timeout expired
+ ///
+ /// How long to wait for the work items to complete in milliseconds
+ /// Returns true if work items completed within the timeout, otherwise false.
+ bool WaitForIdle(int millisecondsTimeout);
+
+ ///
+ /// IsIdle is true when there are no work items running or queued.
+ ///
+ bool IsIdle { get; }
+
+ ///
+ /// This event is fired when all work items are completed.
+ /// (When IsIdle changes to true)
+ /// This event only work on WorkItemsGroup. On SmartThreadPool
+ /// it throws the NotImplementedException.
+ ///
+ event WorkItemsGroupIdleHandler OnIdle;
+
+ #region QueueWorkItem
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ /// The priority of the work item
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// The work item priority
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// The work item priority
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Indicates on which cases to call to the post execute callback
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Indicates on which cases to call to the post execute callback
+ /// The work item priority
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
+
+ ///
+ /// Queue a work item
+ ///
+ /// Work item info
+ /// A callback to execute
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
+
+ ///
+ /// Queue a work item
+ ///
+ /// Work item information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// Returns a work item result
+ IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
+
+ #endregion
+
+ #region QueueWorkItem(Action<...>)
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem(Action action);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem (Action action, T arg);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult object, but its GetResult() will always return null
+ IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority);
+
+ #endregion
+
+ #region QueueWorkItem(Func<...>)
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult<TResult> object.
+ /// its GetResult() returns a TResult object
+ IWorkItemResult QueueWorkItem(Func func);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult<TResult> object.
+ /// its GetResult() returns a TResult object
+ IWorkItemResult QueueWorkItem(Func func, T arg);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult<TResult> object.
+ /// its GetResult() returns a TResult object
+ IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult<TResult> object.
+ /// its GetResult() returns a TResult object
+ IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3);
+
+ ///
+ /// Queue a work item.
+ ///
+ /// Returns a IWorkItemResult<TResult> object.
+ /// its GetResult() returns a TResult object
+ IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
+
+ #endregion
+ }
+
+ #endregion
+
+ #region CallToPostExecute enumerator
+
+ [Flags]
+ public enum CallToPostExecute
+ {
+ ///
+ /// Never call to the PostExecute call back
+ ///
+ Never = 0x00,
+
+ ///
+ /// Call to the PostExecute only when the work item is cancelled
+ ///
+ WhenWorkItemCanceled = 0x01,
+
+ ///
+ /// Call to the PostExecute only when the work item is not cancelled
+ ///
+ WhenWorkItemNotCanceled = 0x02,
+
+ ///
+ /// Always call to the PostExecute
+ ///
+ Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
+ }
+
+ #endregion
+
+ #region IWorkItemResult interface
+
+ ///
+ /// The common interface of IWorkItemResult and IWorkItemResult<T>
+ ///
+ public interface IWaitableResult
+ {
+ ///
+ /// This method intent is for internal use.
+ ///
+ ///
+ IWorkItemResult GetWorkItemResult();
+
+ ///
+ /// This method intent is for internal use.
+ ///
+ ///
+ IWorkItemResult GetWorkItemResultT();
+ }
+
+ ///
+ /// IWorkItemResult interface.
+ /// Created when a WorkItemCallback work item is queued.
+ ///
+ public interface IWorkItemResult : IWorkItemResult
private enum WorkItemState
{
- InQueue,
- InProgress,
- Completed,
- Canceled,
+ InQueue = 0, // Nexts: InProgress, Canceled
+ InProgress = 1, // Nexts: Completed, Canceled
+ Completed = 2, // Stays Completed
+ Canceled = 3, // Stays Canceled
+ }
+
+ private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
+ {
+ bool valid = false;
+
+ switch (currentState)
+ {
+ case WorkItemState.InQueue:
+ valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
+ break;
+ case WorkItemState.InProgress:
+ valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
+ break;
+ case WorkItemState.Completed:
+ case WorkItemState.Canceled:
+ // Cannot be changed
+ break;
+ default:
+ // Unknown state
+ Debug.Assert(false);
+ break;
+ }
+
+ return valid;
}
#endregion
- #region Member Variables
-
- public Thread currentThread;
+ #region Fields
///
/// Callback delegate for the callback.
///
- private WorkItemCallback _callback;
+ private readonly WorkItemCallback _callback;
///
/// State with which to call the callback delegate.
///
private object _state;
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
///
/// Stores the caller's context
///
- private CallerThreadContext _callerContext;
-
+ private readonly CallerThreadContext _callerContext;
+#endif
///
/// Holds the result of the mehtod
///
@@ -117,12 +96,12 @@ namespace Amib.Threading.Internal
///
/// Represents the result state of the work item
///
- private WorkItemResult _workItemResult;
+ private readonly WorkItemResult _workItemResult;
///
/// Work item info
///
- private WorkItemInfo _workItemInfo;
+ private readonly WorkItemInfo _workItemInfo;
///
/// Called when the WorkItem starts
@@ -141,30 +120,41 @@ namespace Amib.Threading.Internal
private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
///
- /// The work item group this work item belong to.
- ///
+ /// A reference to an object that indicates whatever the
+ /// SmartThreadPool has been canceled
///
- private IWorkItemsGroup _workItemsGroup;
+ private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
+
+ ///
+ /// The work item group this work item belong to.
+ ///
+ private readonly IWorkItemsGroup _workItemsGroup;
+
+ ///
+ /// The thread that executes this workitem.
+ /// This field is available for the period when the work item is executed, before and after it is null.
+ ///
+ private Thread _executingThread;
+
+ ///
+ /// The absulote time when the work item will be timeout
+ ///
+ private long _expirationTime;
#region Performance Counter fields
- ///
- /// The time when the work items is queued.
- /// Used with the performance counter.
- ///
- private DateTime _queuedTime;
+
+
///
- /// The time when the work items starts its execution.
- /// Used with the performance counter.
+ /// Stores how long the work item waited on the stp queue
///
- private DateTime _beginProcessTime;
+ private Stopwatch _waitingOnQueueStopwatch;
///
- /// The time when the work items ends its execution.
- /// Used with the performance counter.
+ /// Stores how much time it took the work item to execute after it went out of the queue
///
- private DateTime _endProcessTime;
+ private Stopwatch _processingStopwatch;
#endregion
@@ -174,17 +164,25 @@ namespace Amib.Threading.Internal
public TimeSpan WaitingTime
{
- get
+ get
{
- return (_beginProcessTime - _queuedTime);
+ return _waitingOnQueueStopwatch.Elapsed;
}
}
public TimeSpan ProcessTime
{
- get
+ get
{
- return (_endProcessTime - _beginProcessTime);
+ return _processingStopwatch.Elapsed;
+ }
+ }
+
+ internal WorkItemInfo WorkItemInfo
+ {
+ get
+ {
+ return _workItemInfo;
}
}
@@ -195,6 +193,8 @@ namespace Amib.Threading.Internal
///
/// Initialize the callback holding object.
///
+ /// The workItemGroup of the workitem
+ /// The WorkItemInfo of te workitem
/// Callback delegate for the callback.
/// State with which to call the callback delegate.
///
@@ -203,16 +203,18 @@ namespace Amib.Threading.Internal
public WorkItem(
IWorkItemsGroup workItemsGroup,
WorkItemInfo workItemInfo,
- WorkItemCallback callback,
+ WorkItemCallback callback,
object state)
{
_workItemsGroup = workItemsGroup;
_workItemInfo = workItemInfo;
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
{
_callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
}
+#endif
_callback = callback;
_state = state;
@@ -222,9 +224,18 @@ namespace Amib.Threading.Internal
internal void Initialize()
{
+ // The _workItemState is changed directly instead of using the SetWorkItemState
+ // method since we don't want to go throught IsValidStateTransition.
_workItemState = WorkItemState.InQueue;
+
_workItemCompleted = null;
_workItemCompletedRefCount = 0;
+ _waitingOnQueueStopwatch = new Stopwatch();
+ _processingStopwatch = new Stopwatch();
+ _expirationTime =
+ _workItemInfo.Timeout > 0 ?
+ DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
+ long.MaxValue;
}
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
@@ -237,17 +248,16 @@ namespace Amib.Threading.Internal
#region Methods
- public CanceledWorkItemsGroup CanceledWorkItemsGroup
+ internal CanceledWorkItemsGroup CanceledWorkItemsGroup
{
- get
- {
- return _canceledWorkItemsGroup;
- }
+ get { return _canceledWorkItemsGroup; }
+ set { _canceledWorkItemsGroup = value; }
+ }
- set
- {
- _canceledWorkItemsGroup = value;
- }
+ internal CanceledWorkItemsGroup CanceledSmartThreadPool
+ {
+ get { return _canceledSmartThreadPool; }
+ set { _canceledSmartThreadPool = value; }
}
///
@@ -259,9 +269,10 @@ namespace Amib.Threading.Internal
///
public bool StartingWorkItem()
{
- _beginProcessTime = DateTime.Now;
+ _waitingOnQueueStopwatch.Stop();
+ _processingStopwatch.Start();
- lock(this)
+ lock (this)
{
if (IsCanceled)
{
@@ -277,6 +288,9 @@ namespace Amib.Threading.Internal
Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
+ // No need for a lock yet, only after the state has changed to InProgress
+ _executingThread = Thread.CurrentThread;
+
SetWorkItemState(WorkItemState.InProgress);
}
@@ -291,7 +305,7 @@ namespace Amib.Threading.Internal
CallToPostExecute currentCallToPostExecute = 0;
// Execute the work item if we are in the correct state
- switch(GetWorkItemState())
+ switch (GetWorkItemState())
{
case WorkItemState.InProgress:
currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled;
@@ -311,7 +325,7 @@ namespace Amib.Threading.Internal
PostExecute();
}
- _endProcessTime = DateTime.Now;
+ _processingStopwatch.Stop();
}
internal void FireWorkItemCompleted()
@@ -323,8 +337,21 @@ namespace Amib.Threading.Internal
_workItemCompletedEvent(this);
}
}
- catch // Ignore exceptions
- {}
+ catch // Suppress exceptions
+ { }
+ }
+
+ internal void FireWorkItemStarted()
+ {
+ try
+ {
+ if (null != _workItemStartedEvent)
+ {
+ _workItemStartedEvent(this);
+ }
+ }
+ catch // Suppress exceptions
+ { }
}
///
@@ -332,32 +359,70 @@ namespace Amib.Threading.Internal
///
private void ExecuteWorkItem()
{
+
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
CallerThreadContext ctc = null;
if (null != _callerContext)
{
ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
CallerThreadContext.Apply(_callerContext);
}
+#endif
Exception exception = null;
object result = null;
try
{
- result = _callback(_state);
+ try
+ {
+ result = _callback(_state);
+ }
+ catch (Exception e)
+ {
+ // Save the exception so we can rethrow it later
+ exception = e;
+ }
+
+ // Remove the value of the execution thread, so it will be impossible to cancel the work item,
+ // since it is already completed.
+ // Cancelling a work item that already completed may cause the abortion of the next work item!!!
+ Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
+
+ if (null == executionThread)
+ {
+ // Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
+ Thread.Sleep(60 * 1000);
+
+ // If after 1 minute this thread was not aborted then let it continue working.
+ }
}
- catch (Exception e)
+ // We must treat the ThreadAbortException or else it will be stored in the exception variable
+ catch (ThreadAbortException tae)
{
- // Save the exception so we can rethrow it later
- exception = e;
+ tae.GetHashCode();
+ // Check if the work item was cancelled
+ // If we got a ThreadAbortException and the STP is not shutting down, it means the
+ // work items was cancelled.
+ if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown)
+ {
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
+ Thread.ResetAbort();
+#endif
+ }
}
-
+
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
if (null != _callerContext)
{
CallerThreadContext.Apply(ctc);
}
+#endif
- SetResult(result, exception);
+ if (!SmartThreadPool.IsWorkItemCanceled)
+ {
+ SetResult(result, exception);
+ }
}
///
@@ -369,9 +434,9 @@ namespace Amib.Threading.Internal
{
try
{
- _workItemInfo.PostExecuteWorkItemCallback(this._workItemResult);
+ _workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
}
- catch (Exception e)
+ catch (Exception e)
{
Debug.Assert(null != e);
}
@@ -382,6 +447,8 @@ namespace Amib.Threading.Internal
/// Set the result of the work item to return
///
/// The result of the work item
+ /// The exception that was throw while the workitem executed, null
+ /// if there was no exception.
internal void SetResult(object result, Exception exception)
{
_result = result;
@@ -401,48 +468,48 @@ namespace Amib.Threading.Internal
///
/// Wait for all work items to complete
///
- /// Array of work item result objects
+ /// Array of work item result objects
/// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.
///
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
///
/// A cancel wait handle to interrupt the wait if needed
///
- /// true when every work item in workItemResults has completed; otherwise false.
+ /// true when every work item in waitableResults has completed; otherwise false.
///
internal static bool WaitAll(
- IWorkItemResult [] workItemResults,
+ IWaitableResult[] waitableResults,
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle)
{
- if (0 == workItemResults.Length)
+ if (0 == waitableResults.Length)
{
return true;
}
bool success;
- WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];;
- GetWaitHandles(workItemResults, waitHandles);
+ WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
+ GetWaitHandles(waitableResults, waitHandles);
if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
{
- success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
+ success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
}
else
{
success = true;
int millisecondsLeft = millisecondsTimeout;
- DateTime start = DateTime.Now;
+ Stopwatch stopwatch = Stopwatch.StartNew();
- WaitHandle [] whs;
+ WaitHandle[] whs;
if (null != cancelWaitHandle)
{
- whs = new WaitHandle [] { null, cancelWaitHandle };
+ whs = new WaitHandle[] { null, cancelWaitHandle };
}
else
{
- whs = new WaitHandle [] { null };
+ whs = new WaitHandle[] { null };
}
bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
@@ -450,7 +517,7 @@ namespace Amib.Threading.Internal
// We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
// won't affect it.
// Each iteration we update the time left for the timeout.
- for(int i = 0; i < workItemResults.Length; ++i)
+ for (int i = 0; i < waitableResults.Length; ++i)
{
// WaitAny don't work with negative numbers
if (!waitInfinitely && (millisecondsLeft < 0))
@@ -460,23 +527,22 @@ namespace Amib.Threading.Internal
}
whs[0] = waitHandles[i];
- int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
- if((result > 0) || (WaitHandle.WaitTimeout == result))
+ int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
+ if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result))
{
success = false;
break;
}
- if(!waitInfinitely)
+ if (!waitInfinitely)
{
// Update the time left to wait
- TimeSpan ts = DateTime.Now - start;
- millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
+ millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
}
}
}
// Release the wait handles
- ReleaseWaitHandles(workItemResults);
+ ReleaseWaitHandles(waitableResults);
return success;
}
@@ -484,7 +550,7 @@ namespace Amib.Threading.Internal
///
/// Waits for any of the work items in the specified array to complete, cancel, or timeout
///
- /// Array of work item result objects
+ /// Array of work item result objects
/// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.
///
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
@@ -493,38 +559,38 @@ namespace Amib.Threading.Internal
///
/// 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.
///
- internal static int WaitAny(
- IWorkItemResult [] workItemResults,
+ internal static int WaitAny(
+ IWaitableResult[] waitableResults,
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle)
{
- WaitHandle [] waitHandles = null;
+ WaitHandle[] waitHandles;
if (null != cancelWaitHandle)
{
- waitHandles = new WaitHandle[workItemResults.Length+1];
- GetWaitHandles(workItemResults, waitHandles);
- waitHandles[workItemResults.Length] = cancelWaitHandle;
+ waitHandles = new WaitHandle[waitableResults.Length + 1];
+ GetWaitHandles(waitableResults, waitHandles);
+ waitHandles[waitableResults.Length] = cancelWaitHandle;
}
else
{
- waitHandles = new WaitHandle[workItemResults.Length];
- GetWaitHandles(workItemResults, waitHandles);
+ waitHandles = new WaitHandle[waitableResults.Length];
+ GetWaitHandles(waitableResults, waitHandles);
}
- int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
+ int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
// Treat cancel as timeout
if (null != cancelWaitHandle)
{
- if (result == workItemResults.Length)
+ if (result == waitableResults.Length)
{
- result = WaitHandle.WaitTimeout;
+ result = STPEventWaitHandle.WaitTimeout;
}
}
- ReleaseWaitHandles(workItemResults);
+ ReleaseWaitHandles(waitableResults);
return result;
}
@@ -532,16 +598,16 @@ namespace Amib.Threading.Internal
///
/// Fill an array of wait handles with the work items wait handles.
///
- /// An array of work item results
+ /// An array of work item results
/// An array of wait handles to fill
private static void GetWaitHandles(
- IWorkItemResult [] workItemResults,
- WaitHandle [] waitHandles)
+ IWaitableResult[] waitableResults,
+ WaitHandle[] waitHandles)
{
- for(int i = 0; i < workItemResults.Length; ++i)
+ for (int i = 0; i < waitableResults.Length; ++i)
{
- WorkItemResult wir = workItemResults[i] as WorkItemResult;
- Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects");
+ WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
+ Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
}
@@ -550,40 +616,64 @@ namespace Amib.Threading.Internal
///
/// Release the work items' wait handles
///
- /// An array of work item results
- private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults)
+ /// An array of work item results
+ private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
{
- for(int i = 0; i < workItemResults.Length; ++i)
+ for (int i = 0; i < waitableResults.Length; ++i)
{
- WorkItemResult wir = workItemResults[i] as WorkItemResult;
+ WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
wir.GetWorkItem().ReleaseWaitHandle();
}
}
-
#endregion
-
+
#region Private Members
private WorkItemState GetWorkItemState()
{
- if (_canceledWorkItemsGroup.IsCanceled)
+ lock (this)
{
- return WorkItemState.Canceled;
- }
- return _workItemState;
+ if (WorkItemState.Completed == _workItemState)
+ {
+ return _workItemState;
+ }
+ long nowTicks = DateTime.UtcNow.Ticks;
+
+ if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
+ {
+ _workItemState = WorkItemState.Canceled;
+ }
+
+ if (WorkItemState.InProgress == _workItemState)
+ {
+ return _workItemState;
+ }
+
+ if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
+ {
+ return WorkItemState.Canceled;
+ }
+
+ return _workItemState;
+ }
}
+
+
///
/// Sets the work item's state
///
/// The state to set the work item to
private void SetWorkItemState(WorkItemState workItemState)
{
- lock(this)
+ lock (this)
{
- _workItemState = workItemState;
+ if (IsValidStatesTransition(_workItemState, workItemState))
+ {
+ _workItemState = workItemState;
+ }
}
}
@@ -594,7 +684,7 @@ namespace Amib.Threading.Internal
private void SignalComplete(bool canceled)
{
SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed);
- lock(this)
+ lock (this)
{
// If someone is waiting then signal.
if (null != _workItemCompleted)
@@ -606,40 +696,83 @@ namespace Amib.Threading.Internal
internal void WorkItemIsQueued()
{
- _queuedTime = DateTime.Now;
+ _waitingOnQueueStopwatch.Start();
}
#endregion
-
+
#region Members exposed by WorkItemResult
///
/// Cancel the work item if it didn't start running yet.
///
/// Returns true on success or false if the work item is in progress or already completed
- private bool Cancel()
+ private bool Cancel(bool abortExecution)
{
- lock(this)
+#if (_WINDOWS_CE)
+ if(abortExecution)
{
- switch(GetWorkItemState())
+ throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
+ }
+#endif
+ bool success = false;
+ bool signalComplete = false;
+
+ lock (this)
+ {
+ switch (GetWorkItemState())
{
case WorkItemState.Canceled:
//Debug.WriteLine("Work item already canceled");
- return true;
+ if (abortExecution)
+ {
+ Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
+ if (null != executionThread)
+ {
+ executionThread.Abort(); // "Cancel"
+ // No need to signalComplete, because we already cancelled this work item
+ // so it already signaled its completion.
+ //signalComplete = true;
+ }
+ }
+ success = true;
+ break;
case WorkItemState.Completed:
- case WorkItemState.InProgress:
//Debug.WriteLine("Work item cannot be canceled");
- return false;
+ break;
+ case WorkItemState.InProgress:
+ if (abortExecution)
+ {
+ Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
+ if (null != executionThread)
+ {
+ executionThread.Abort(); // "Cancel"
+ success = true;
+ signalComplete = true;
+ }
+ }
+ else
+ {
+ success = false;
+ signalComplete = false;
+ }
+ break;
case WorkItemState.InQueue:
// Signal to the wait for completion that the work
// item has been completed (canceled). There is no
// reason to wait for it to get out of the queue
- SignalComplete(true);
+ signalComplete = true;
//Debug.WriteLine("Work item canceled");
- return true;
+ success = true;
+ break;
+ }
+
+ if (signalComplete)
+ {
+ SignalComplete(true);
}
}
- return false;
+ return success;
}
///
@@ -653,7 +786,7 @@ namespace Amib.Threading.Internal
bool exitContext,
WaitHandle cancelWaitHandle)
{
- Exception e = null;
+ Exception e;
object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
if (null != e)
{
@@ -694,7 +827,7 @@ namespace Amib.Threading.Internal
{
WaitHandle wh = GetWaitHandle();
- bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext);
+ bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);
ReleaseWaitHandle();
@@ -706,10 +839,10 @@ namespace Amib.Threading.Internal
else
{
WaitHandle wh = GetWaitHandle();
- int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
+ int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
ReleaseWaitHandle();
- switch(result)
+ switch (result)
{
case 0:
// The work item signaled
@@ -717,7 +850,7 @@ namespace Amib.Threading.Internal
// work item (not the get result)
break;
case 1:
- case WaitHandle.WaitTimeout:
+ case STPEventWaitHandle.WaitTimeout:
throw new WorkItemTimeoutException("Work item timeout");
default:
Debug.Assert(false);
@@ -745,11 +878,11 @@ namespace Amib.Threading.Internal
///
private WaitHandle GetWaitHandle()
{
- lock(this)
+ lock (this)
{
if (null == _workItemCompleted)
{
- _workItemCompleted = new ManualResetEvent(IsCompleted);
+ _workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
}
++_workItemCompletedRefCount;
}
@@ -758,7 +891,7 @@ namespace Amib.Threading.Internal
private void ReleaseWaitHandle()
{
- lock(this)
+ lock (this)
{
if (null != _workItemCompleted)
{
@@ -779,10 +912,10 @@ namespace Amib.Threading.Internal
{
get
{
- lock(this)
+ lock (this)
{
WorkItemState workItemState = GetWorkItemState();
- return ((workItemState == WorkItemState.Completed) ||
+ return ((workItemState == WorkItemState.Completed) ||
(workItemState == WorkItemState.Canceled));
}
}
@@ -795,7 +928,7 @@ namespace Amib.Threading.Internal
{
get
{
- lock(this)
+ lock (this)
{
return (GetWorkItemState() == WorkItemState.Canceled);
}
@@ -843,172 +976,6 @@ namespace Amib.Threading.Internal
}
}
-
- #region WorkItemResult class
-
- private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult
- {
- ///
- /// A back reference to the work item
- ///
- private WorkItem _workItem;
-
- public WorkItemResult(WorkItem workItem)
- {
- _workItem = workItem;
- }
-
- internal WorkItem GetWorkItem()
- {
- return _workItem;
- }
-
- #region IWorkItemResult Members
-
- public bool IsCompleted
- {
- get
- {
- return _workItem.IsCompleted;
- }
- }
-
- public void Abort()
- {
- _workItem.Abort();
- }
-
- public bool IsCanceled
- {
- get
- {
- return _workItem.IsCanceled;
- }
- }
-
- public object GetResult()
- {
- return _workItem.GetResult(Timeout.Infinite, true, null);
- }
-
- public object GetResult(int millisecondsTimeout, bool exitContext)
- {
- return _workItem.GetResult(millisecondsTimeout, exitContext, null);
- }
-
- public object GetResult(TimeSpan timeout, bool exitContext)
- {
- return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
- }
-
- public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
- {
- return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
- }
-
- public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
- {
- return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
- }
-
- public object GetResult(out Exception e)
- {
- return _workItem.GetResult(Timeout.Infinite, true, null, out e);
- }
-
- public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
- {
- return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
- }
-
- public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
- {
- return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
- }
-
- public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
- {
- return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
- }
-
- public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
- {
- return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
- }
-
- public bool Cancel()
- {
- return _workItem.Cancel();
- }
-
- public object State
- {
- get
- {
- return _workItem._state;
- }
- }
-
- public WorkItemPriority WorkItemPriority
- {
- get
- {
- return _workItem._workItemInfo.WorkItemPriority;
- }
- }
-
- ///
- /// Return the result, same as GetResult()
- ///
- public object Result
- {
- get { return GetResult(); }
- }
-
- ///
- /// Returns the exception if occured otherwise returns null.
- /// This value is valid only after the work item completed,
- /// before that it is always null.
- ///
- public object Exception
- {
- get { return _workItem._exception; }
- }
-
- #endregion
-
- #region IInternalWorkItemResult Members
-
- public event WorkItemStateCallback OnWorkItemStarted
- {
- add
- {
- _workItem.OnWorkItemStarted += value;
- }
- remove
- {
- _workItem.OnWorkItemStarted -= value;
- }
- }
-
-
- public event WorkItemStateCallback OnWorkItemCompleted
- {
- add
- {
- _workItem.OnWorkItemCompleted += value;
- }
- remove
- {
- _workItem.OnWorkItemCompleted -= value;
- }
- }
-
- #endregion
- }
-
- #endregion
-
public void DisposeOfState()
{
if (_workItemInfo.DisposeOfStateObjects)
@@ -1021,15 +988,5 @@ namespace Amib.Threading.Internal
}
}
}
-
- public void Abort()
- {
- lock (this)
- {
- if(currentThread != null)
- currentThread.Abort();
- }
- }
}
- #endregion
}
diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs
index dfcb54f7e1..2d6601ea19 100644
--- a/ThirdParty/SmartThreadPool/WorkItemFactory.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs
@@ -1,333 +1,343 @@
-// Ami Bar
-// amibar@gmail.com
-
-using System;
-
-namespace Amib.Threading.Internal
-{
- #region WorkItemFactory class
-
- public class WorkItemFactory
- {
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback)
- {
- return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- /// The priority of the work item
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- WorkItemPriority workItemPriority)
- {
- return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// Work item info
- /// A callback to execute
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemInfo workItemInfo,
- WorkItemCallback callback)
- {
- return CreateWorkItem(
- workItemsGroup,
- wigStartInfo,
- workItemInfo,
- callback,
- null);
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- object state)
- {
- ValidateCallback(callback);
-
- WorkItemInfo workItemInfo = new WorkItemInfo();
- workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
- workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
- workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
- workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
- workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- workItemInfo,
- callback,
- state);
- return workItem;
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- /// The work item priority
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- object state,
- WorkItemPriority workItemPriority)
- {
- ValidateCallback(callback);
-
- WorkItemInfo workItemInfo = new WorkItemInfo();
- workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
- workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
- workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
- workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
- workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
- workItemInfo.WorkItemPriority = workItemPriority;
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- workItemInfo,
- callback,
- state);
-
- return workItem;
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// Work item information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemInfo workItemInfo,
- WorkItemCallback callback,
- object state)
- {
- ValidateCallback(callback);
- ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- new WorkItemInfo(workItemInfo),
- callback,
- state);
-
- return workItem;
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback)
- {
- ValidateCallback(callback);
- ValidateCallback(postExecuteWorkItemCallback);
-
- WorkItemInfo workItemInfo = new WorkItemInfo();
- workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
- workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
- workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
- workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
- workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- workItemInfo,
- callback,
- state);
-
- return workItem;
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// The work item priority
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback,
- WorkItemPriority workItemPriority)
- {
- ValidateCallback(callback);
- ValidateCallback(postExecuteWorkItemCallback);
-
- WorkItemInfo workItemInfo = new WorkItemInfo();
- workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
- workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
- workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
- workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
- workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
- workItemInfo.WorkItemPriority = workItemPriority;
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- workItemInfo,
- callback,
- state);
-
- return workItem;
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// Indicates on which cases to call to the post execute callback
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback,
- CallToPostExecute callToPostExecute)
- {
- ValidateCallback(callback);
- ValidateCallback(postExecuteWorkItemCallback);
-
- WorkItemInfo workItemInfo = new WorkItemInfo();
- workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
- workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
- workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
- workItemInfo.CallToPostExecute = callToPostExecute;
- workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- workItemInfo,
- callback,
- state);
-
- return workItem;
- }
-
- ///
- /// Create a new work item
- ///
- /// Work item group start information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// Indicates on which cases to call to the post execute callback
- /// The work item priority
- /// Returns a work item
- public static WorkItem CreateWorkItem(
- IWorkItemsGroup workItemsGroup,
- WIGStartInfo wigStartInfo,
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback,
- CallToPostExecute callToPostExecute,
- WorkItemPriority workItemPriority)
- {
-
- ValidateCallback(callback);
- ValidateCallback(postExecuteWorkItemCallback);
-
- WorkItemInfo workItemInfo = new WorkItemInfo();
- workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
- workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
- workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
- workItemInfo.CallToPostExecute = callToPostExecute;
- workItemInfo.WorkItemPriority = workItemPriority;
- workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
-
- WorkItem workItem = new WorkItem(
- workItemsGroup,
- workItemInfo,
- callback,
- state);
-
- return workItem;
- }
-
- private static void ValidateCallback(Delegate callback)
- {
- if(callback.GetInvocationList().Length > 1)
- {
- throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
- }
- }
- }
-
- #endregion
-}
+using System;
+
+namespace Amib.Threading.Internal
+{
+ #region WorkItemFactory class
+
+ public class WorkItemFactory
+ {
+ ///
+ /// Create a new work item
+ ///
+ /// The WorkItemsGroup of this workitem
+ /// Work item group start information
+ /// A callback to execute
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback)
+ {
+ return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The WorkItemsGroup of this workitem
+ /// Work item group start information
+ /// A callback to execute
+ /// The priority of the work item
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ WorkItemPriority workItemPriority)
+ {
+ return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The WorkItemsGroup of this workitem
+ /// Work item group start information
+ /// Work item info
+ /// A callback to execute
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemInfo workItemInfo,
+ WorkItemCallback callback)
+ {
+ return CreateWorkItem(
+ workItemsGroup,
+ wigStartInfo,
+ workItemInfo,
+ callback,
+ null);
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The WorkItemsGroup of this workitem
+ /// Work item group start information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ object state)
+ {
+ ValidateCallback(callback);
+
+ WorkItemInfo workItemInfo = new WorkItemInfo();
+ workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+ workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+ workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
+ workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+ workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+ workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ workItemInfo,
+ callback,
+ state);
+ return workItem;
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The work items group
+ /// Work item group start information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// The work item priority
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ object state,
+ WorkItemPriority workItemPriority)
+ {
+ ValidateCallback(callback);
+
+ WorkItemInfo workItemInfo = new WorkItemInfo();
+ workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+ workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+ workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
+ workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+ workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+ workItemInfo.WorkItemPriority = workItemPriority;
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ workItemInfo,
+ callback,
+ state);
+
+ return workItem;
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The work items group
+ /// Work item group start information
+ /// Work item information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemInfo workItemInfo,
+ WorkItemCallback callback,
+ object state)
+ {
+ ValidateCallback(callback);
+ ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ new WorkItemInfo(workItemInfo),
+ callback,
+ state);
+
+ return workItem;
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The work items group
+ /// Work item group start information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback)
+ {
+ ValidateCallback(callback);
+ ValidateCallback(postExecuteWorkItemCallback);
+
+ WorkItemInfo workItemInfo = new WorkItemInfo();
+ workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+ workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+ workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+ workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+ workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+ workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ workItemInfo,
+ callback,
+ state);
+
+ return workItem;
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The work items group
+ /// Work item group start information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// The work item priority
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+ WorkItemPriority workItemPriority)
+ {
+ ValidateCallback(callback);
+ ValidateCallback(postExecuteWorkItemCallback);
+
+ WorkItemInfo workItemInfo = new WorkItemInfo();
+ workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+ workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+ workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+ workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+ workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+ workItemInfo.WorkItemPriority = workItemPriority;
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ workItemInfo,
+ callback,
+ state);
+
+ return workItem;
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The work items group
+ /// Work item group start information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Indicates on which cases to call to the post execute callback
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+ CallToPostExecute callToPostExecute)
+ {
+ ValidateCallback(callback);
+ ValidateCallback(postExecuteWorkItemCallback);
+
+ WorkItemInfo workItemInfo = new WorkItemInfo();
+ workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+ workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+ workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+ workItemInfo.CallToPostExecute = callToPostExecute;
+ workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+ workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ workItemInfo,
+ callback,
+ state);
+
+ return workItem;
+ }
+
+ ///
+ /// Create a new work item
+ ///
+ /// The work items group
+ /// Work item group start information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Indicates on which cases to call to the post execute callback
+ /// The work item priority
+ /// Returns a work item
+ public static WorkItem CreateWorkItem(
+ IWorkItemsGroup workItemsGroup,
+ WIGStartInfo wigStartInfo,
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+ CallToPostExecute callToPostExecute,
+ WorkItemPriority workItemPriority)
+ {
+
+ ValidateCallback(callback);
+ ValidateCallback(postExecuteWorkItemCallback);
+
+ WorkItemInfo workItemInfo = new WorkItemInfo();
+ workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+ workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+ workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+ workItemInfo.CallToPostExecute = callToPostExecute;
+ workItemInfo.WorkItemPriority = workItemPriority;
+ workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+
+ WorkItem workItem = new WorkItem(
+ workItemsGroup,
+ workItemInfo,
+ callback,
+ state);
+
+ return workItem;
+ }
+
+ private static void ValidateCallback(Delegate callback)
+ {
+ if (callback != null && callback.GetInvocationList().Length > 1)
+ {
+ throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
+ }
+ }
+ }
+
+ #endregion
+}
diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs
index c259339cc2..5fbceb85e1 100644
--- a/ThirdParty/SmartThreadPool/WorkItemInfo.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs
@@ -1,102 +1,69 @@
-// Ami Bar
-// amibar@gmail.com
-
-namespace Amib.Threading
-{
- #region WorkItemInfo class
-
- ///
- /// Summary description for WorkItemInfo.
- ///
- public class WorkItemInfo
- {
- ///
- /// Use the caller's security context
- ///
- private bool _useCallerCallContext;
-
- ///
- /// Use the caller's security context
- ///
- private bool _useCallerHttpContext;
-
- ///
- /// Dispose of the state object of a work item
- ///
- private bool _disposeOfStateObjects;
-
- ///
- /// The option to run the post execute
- ///
- private CallToPostExecute _callToPostExecute;
-
- ///
- /// A post execute callback to call when none is provided in
- /// the QueueWorkItem method.
- ///
- private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
-
- ///
- /// The priority of the work item
- ///
- private WorkItemPriority _workItemPriority;
-
- public WorkItemInfo()
- {
- _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
- _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
- _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
- _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
- _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
- _workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
- }
-
- public WorkItemInfo(WorkItemInfo workItemInfo)
- {
- _useCallerCallContext = workItemInfo._useCallerCallContext;
- _useCallerHttpContext = workItemInfo._useCallerHttpContext;
- _disposeOfStateObjects = workItemInfo._disposeOfStateObjects;
- _callToPostExecute = workItemInfo._callToPostExecute;
- _postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
- _workItemPriority = workItemInfo._workItemPriority;
- }
-
- public bool UseCallerCallContext
- {
- get { return _useCallerCallContext; }
- set { _useCallerCallContext = value; }
- }
-
- public bool UseCallerHttpContext
- {
- get { return _useCallerHttpContext; }
- set { _useCallerHttpContext = value; }
- }
-
- public bool DisposeOfStateObjects
- {
- get { return _disposeOfStateObjects; }
- set { _disposeOfStateObjects = value; }
- }
-
- public CallToPostExecute CallToPostExecute
- {
- get { return _callToPostExecute; }
- set { _callToPostExecute = value; }
- }
-
- public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
- {
- get { return _postExecuteWorkItemCallback; }
- set { _postExecuteWorkItemCallback = value; }
- }
-
- public WorkItemPriority WorkItemPriority
- {
- get { return _workItemPriority; }
- set { _workItemPriority = value; }
- }
- }
-
- #endregion
-}
+namespace Amib.Threading
+{
+ #region WorkItemInfo class
+
+ ///
+ /// Summary description for WorkItemInfo.
+ ///
+ public class WorkItemInfo
+ {
+ public WorkItemInfo()
+ {
+ UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
+ UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
+ DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
+ CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
+ PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
+ WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
+ }
+
+ public WorkItemInfo(WorkItemInfo workItemInfo)
+ {
+ UseCallerCallContext = workItemInfo.UseCallerCallContext;
+ UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
+ DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
+ CallToPostExecute = workItemInfo.CallToPostExecute;
+ PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
+ WorkItemPriority = workItemInfo.WorkItemPriority;
+ Timeout = workItemInfo.Timeout;
+ }
+
+ ///
+ /// Get/Set if to use the caller's security context
+ ///
+ public bool UseCallerCallContext { get; set; }
+
+ ///
+ /// Get/Set if to use the caller's HTTP context
+ ///
+ public bool UseCallerHttpContext { get; set; }
+
+ ///
+ /// Get/Set if to dispose of the state object of a work item
+ ///
+ public bool DisposeOfStateObjects { get; set; }
+
+ ///
+ /// Get/Set the run the post execute options
+ ///
+ public CallToPostExecute CallToPostExecute { get; set; }
+
+ ///
+ /// Get/Set the post execute callback
+ ///
+ public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
+
+ ///
+ /// Get/Set the work item's priority
+ ///
+ public WorkItemPriority WorkItemPriority { get; set; }
+
+ ///
+ /// Get/Set the work item's timout in milliseconds.
+ /// This is a passive timout. When the timout expires the work item won't be actively aborted!
+ ///
+ public long Timeout { get; set; }
+ }
+
+ #endregion
+}
diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
new file mode 100644
index 0000000000..a0bf8b8811
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Threading;
+
+namespace Amib.Threading.Internal
+{
+ #region WorkItemResultTWrapper class
+
+ internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult
+ {
+ private readonly IWorkItemResult _workItemResult;
+
+ public WorkItemResultTWrapper(IWorkItemResult workItemResult)
+ {
+ _workItemResult = workItemResult;
+ }
+
+ #region IWorkItemResult Members
+
+ public TResult GetResult()
+ {
+ return (TResult)_workItemResult.GetResult();
+ }
+
+ public TResult GetResult(int millisecondsTimeout, bool exitContext)
+ {
+ return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext);
+ }
+
+ public TResult GetResult(TimeSpan timeout, bool exitContext)
+ {
+ return (TResult)_workItemResult.GetResult(timeout, exitContext);
+ }
+
+ public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
+ {
+ return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
+ }
+
+ public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
+ {
+ return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle);
+ }
+
+ public TResult GetResult(out Exception e)
+ {
+ return (TResult)_workItemResult.GetResult(out e);
+ }
+
+ public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
+ {
+ return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e);
+ }
+
+ public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e)
+ {
+ return (TResult)_workItemResult.GetResult(timeout, exitContext, out e);
+ }
+
+ public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
+ {
+ return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
+ }
+
+ public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
+ {
+ return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e);
+ }
+
+ public bool IsCompleted
+ {
+ get { return _workItemResult.IsCompleted; }
+ }
+
+ public bool IsCanceled
+ {
+ get { return _workItemResult.IsCanceled; }
+ }
+
+ public object State
+ {
+ get { return _workItemResult.State; }
+ }
+
+ public bool Cancel()
+ {
+ return _workItemResult.Cancel();
+ }
+
+ public bool Cancel(bool abortExecution)
+ {
+ return _workItemResult.Cancel(abortExecution);
+ }
+
+ public WorkItemPriority WorkItemPriority
+ {
+ get { return _workItemResult.WorkItemPriority; }
+ }
+
+ public TResult Result
+ {
+ get { return (TResult)_workItemResult.Result; }
+ }
+
+ public object Exception
+ {
+ get { return (TResult)_workItemResult.Exception; }
+ }
+
+ #region IInternalWorkItemResult Members
+
+ public IWorkItemResult GetWorkItemResult()
+ {
+ return _workItemResult.GetWorkItemResult();
+ }
+
+ public IWorkItemResult GetWorkItemResultT()
+ {
+ return (IWorkItemResult)this;
+ }
+
+ #endregion
+
+ #endregion
+ }
+
+ #endregion
+
+}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
index 01ac8ddaa6..67dcbdd2af 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs
@@ -1,512 +1,361 @@
-// Ami Bar
-// amibar@gmail.com
-
-using System;
-using System.Threading;
-using System.Runtime.CompilerServices;
-using System.Diagnostics;
-
-namespace Amib.Threading.Internal
-{
- #region WorkItemsGroup class
-
- ///
- /// Summary description for WorkItemsGroup.
- ///
- public class WorkItemsGroup : IWorkItemsGroup
- {
- #region Private members
-
- private object _lock = new object();
- ///
- /// Contains the name of this instance of SmartThreadPool.
- /// Can be changed by the user.
- ///
- private string _name = "WorkItemsGroup";
-
- ///
- /// A reference to the SmartThreadPool instance that created this
- /// WorkItemsGroup.
- ///
- private SmartThreadPool _stp;
-
- ///
- /// The OnIdle event
- ///
- private event WorkItemsGroupIdleHandler _onIdle;
-
- ///
- /// Defines how many work items of this WorkItemsGroup can run at once.
- ///
- private int _concurrency;
-
- ///
- /// Priority queue to hold work items before they are passed
- /// to the SmartThreadPool.
- ///
- private PriorityQueue _workItemsQueue;
-
- ///
- /// Indicate how many work items are waiting in the SmartThreadPool
- /// queue.
- /// This value is used to apply the concurrency.
- ///
- private int _workItemsInStpQueue;
-
- ///
- /// Indicate how many work items are currently running in the SmartThreadPool.
- /// This value is used with the Cancel, to calculate if we can send new
- /// work items to the STP.
- ///
- private int _workItemsExecutingInStp = 0;
-
- ///
- /// WorkItemsGroup start information
- ///
- private WIGStartInfo _workItemsGroupStartInfo;
-
- ///
- /// Signaled when all of the WorkItemsGroup's work item completed.
- ///
- private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
-
- ///
- /// A common object for all the work items that this work items group
- /// generate so we can mark them to cancel in O(1)
- ///
- private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
-
- #endregion
-
- #region Construction
-
- public WorkItemsGroup(
- SmartThreadPool stp,
- int concurrency,
- WIGStartInfo wigStartInfo)
- {
- if (concurrency <= 0)
- {
- throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero");
- }
- _stp = stp;
- _concurrency = concurrency;
- _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
- _workItemsQueue = new PriorityQueue();
-
- // The _workItemsInStpQueue gets the number of currently executing work items,
- // because once a work item is executing, it cannot be cancelled.
- _workItemsInStpQueue = _workItemsExecutingInStp;
- }
-
- #endregion
-
- #region IWorkItemsGroup implementation
-
- ///
- /// Get/Set the name of the SmartThreadPool instance
- ///
- public string Name
- {
- get
- {
- return _name;
- }
-
- set
- {
- _name = value;
- }
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- /// The priority of the work item
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// Work item info
- /// A callback to execute
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- /// The work item priority
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// Work item information
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// The work item priority
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback,
- WorkItemPriority workItemPriority)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// Indicates on which cases to call to the post execute callback
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback,
- CallToPostExecute callToPostExecute)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Queue a work item
- ///
- /// A callback to execute
- ///
- /// The context object of the work item. Used for passing arguments to the work item.
- ///
- ///
- /// A delegate to call after the callback completion
- ///
- /// Indicates on which cases to call to the post execute callback
- /// The work item priority
- /// Returns a work item result
- public IWorkItemResult QueueWorkItem(
- WorkItemCallback callback,
- object state,
- PostExecuteWorkItemCallback postExecuteWorkItemCallback,
- CallToPostExecute callToPostExecute,
- WorkItemPriority workItemPriority)
- {
- WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
- EnqueueToSTPNextWorkItem(workItem);
- return workItem.GetWorkItemResult();
- }
-
- ///
- /// Wait for the thread pool to be idle
- ///
- public void WaitForIdle()
- {
- WaitForIdle(Timeout.Infinite);
- }
-
- ///
- /// Wait for the thread pool to be idle
- ///
- public bool WaitForIdle(TimeSpan timeout)
- {
- return WaitForIdle((int)timeout.TotalMilliseconds);
- }
-
- ///
- /// Wait for the thread pool to be idle
- ///
- public bool WaitForIdle(int millisecondsTimeout)
- {
- _stp.ValidateWorkItemsGroupWaitForIdle(this);
- return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false);
- }
-
- public int WaitingCallbacks
- {
- get
- {
- return _workItemsQueue.Count;
- }
- }
-
- public event WorkItemsGroupIdleHandler OnIdle
- {
- add
- {
- _onIdle += value;
- }
- remove
- {
- _onIdle -= value;
- }
- }
-
- public void Cancel()
- {
- lock(_lock)
- {
- _canceledWorkItemsGroup.IsCanceled = true;
- _workItemsQueue.Clear();
- _workItemsInStpQueue = 0;
- _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
- }
- }
-
- public void Start()
- {
- lock (this)
- {
- if (!_workItemsGroupStartInfo.StartSuspended)
- {
- return;
- }
- _workItemsGroupStartInfo.StartSuspended = false;
- }
-
- for(int i = 0; i < _concurrency; ++i)
- {
- EnqueueToSTPNextWorkItem(null, false);
- }
- }
-
- #endregion
-
- #region Private methods
-
- private void RegisterToWorkItemCompletion(IWorkItemResult wir)
- {
- IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
- iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
- iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
- }
-
- public void OnSTPIsStarting()
- {
- lock (this)
- {
- if (_workItemsGroupStartInfo.StartSuspended)
- {
- return;
- }
- }
-
- for(int i = 0; i < _concurrency; ++i)
- {
- EnqueueToSTPNextWorkItem(null, false);
- }
- }
-
- private object FireOnIdle(object state)
- {
- FireOnIdleImpl(_onIdle);
- return null;
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
- {
- if(null == onIdle)
- {
- return;
- }
-
- Delegate[] delegates = onIdle.GetInvocationList();
- foreach(WorkItemsGroupIdleHandler eh in delegates)
- {
- try
- {
- eh(this);
- }
- // Ignore exceptions
- catch{}
- }
- }
-
- private void OnWorkItemStartedCallback(WorkItem workItem)
- {
- lock(_lock)
- {
- ++_workItemsExecutingInStp;
- }
- }
-
- private void OnWorkItemCompletedCallback(WorkItem workItem)
- {
- EnqueueToSTPNextWorkItem(null, true);
- }
-
- private void EnqueueToSTPNextWorkItem(WorkItem workItem)
- {
- EnqueueToSTPNextWorkItem(workItem, false);
- }
-
- private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
- {
- lock(_lock)
- {
- // Got here from OnWorkItemCompletedCallback()
- if (decrementWorkItemsInStpQueue)
- {
- --_workItemsInStpQueue;
-
- if(_workItemsInStpQueue < 0)
- {
- _workItemsInStpQueue = 0;
- }
-
- --_workItemsExecutingInStp;
-
- if(_workItemsExecutingInStp < 0)
- {
- _workItemsExecutingInStp = 0;
- }
- }
-
- // If the work item is not null then enqueue it
- if (null != workItem)
- {
- workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
-
- RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
- _workItemsQueue.Enqueue(workItem);
- //_stp.IncrementWorkItemsCount();
-
- if ((1 == _workItemsQueue.Count) &&
- (0 == _workItemsInStpQueue))
- {
- _stp.RegisterWorkItemsGroup(this);
- Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
- _isIdleWaitHandle.Reset();
- }
- }
-
- // If the work items queue of the group is empty than quit
- if (0 == _workItemsQueue.Count)
- {
- if (0 == _workItemsInStpQueue)
- {
- _stp.UnregisterWorkItemsGroup(this);
- Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
- _isIdleWaitHandle.Set();
- _stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
- }
- return;
- }
-
- if (!_workItemsGroupStartInfo.StartSuspended)
- {
- if (_workItemsInStpQueue < _concurrency)
- {
- WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
- _stp.Enqueue(nextWorkItem, true);
- ++_workItemsInStpQueue;
- }
- }
- }
- }
-
- #endregion
- }
-
- #endregion
-}
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Diagnostics;
+
+namespace Amib.Threading.Internal
+{
+
+ #region WorkItemsGroup class
+
+ ///
+ /// Summary description for WorkItemsGroup.
+ ///
+ public class WorkItemsGroup : WorkItemsGroupBase
+ {
+ #region Private members
+
+ private readonly object _lock = new object();
+
+ ///
+ /// A reference to the SmartThreadPool instance that created this
+ /// WorkItemsGroup.
+ ///
+ private readonly SmartThreadPool _stp;
+
+ ///
+ /// The OnIdle event
+ ///
+ private event WorkItemsGroupIdleHandler _onIdle;
+
+ ///
+ /// A flag to indicate if the Work Items Group is now suspended.
+ ///
+ private bool _isSuspended;
+
+ ///
+ /// Defines how many work items of this WorkItemsGroup can run at once.
+ ///
+ private int _concurrency;
+
+ ///
+ /// Priority queue to hold work items before they are passed
+ /// to the SmartThreadPool.
+ ///
+ private readonly PriorityQueue _workItemsQueue;
+
+ ///
+ /// Indicate how many work items are waiting in the SmartThreadPool
+ /// queue.
+ /// This value is used to apply the concurrency.
+ ///
+ private int _workItemsInStpQueue;
+
+ ///
+ /// Indicate how many work items are currently running in the SmartThreadPool.
+ /// This value is used with the Cancel, to calculate if we can send new
+ /// work items to the STP.
+ ///
+ private int _workItemsExecutingInStp = 0;
+
+ ///
+ /// WorkItemsGroup start information
+ ///
+ private readonly WIGStartInfo _workItemsGroupStartInfo;
+
+ ///
+ /// Signaled when all of the WorkItemsGroup's work item completed.
+ ///
+ //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
+ private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
+
+ ///
+ /// A common object for all the work items that this work items group
+ /// generate so we can mark them to cancel in O(1)
+ ///
+ private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
+
+ #endregion
+
+ #region Construction
+
+ public WorkItemsGroup(
+ SmartThreadPool stp,
+ int concurrency,
+ WIGStartInfo wigStartInfo)
+ {
+ if (concurrency <= 0)
+ {
+ throw new ArgumentOutOfRangeException(
+ "concurrency",
+#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
+ concurrency,
+#endif
+ "concurrency must be greater than zero");
+ }
+ _stp = stp;
+ _concurrency = concurrency;
+ _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
+ _workItemsQueue = new PriorityQueue();
+ Name = "WorkItemsGroup";
+
+ // The _workItemsInStpQueue gets the number of currently executing work items,
+ // because once a work item is executing, it cannot be cancelled.
+ _workItemsInStpQueue = _workItemsExecutingInStp;
+
+ _isSuspended = _workItemsGroupStartInfo.StartSuspended;
+ }
+
+ #endregion
+
+ #region WorkItemsGroupBase Overrides
+
+ public override int Concurrency
+ {
+ get { return _concurrency; }
+ set
+ {
+ Debug.Assert(value > 0);
+
+ int diff = value - _concurrency;
+ _concurrency = value;
+ if (diff > 0)
+ {
+ EnqueueToSTPNextNWorkItem(diff);
+ }
+ }
+ }
+
+ public override int WaitingCallbacks
+ {
+ get { return _workItemsQueue.Count; }
+ }
+
+ public override object[] GetStates()
+ {
+ lock (_lock)
+ {
+ object[] states = new object[_workItemsQueue.Count];
+ int i = 0;
+ foreach (WorkItem workItem in _workItemsQueue)
+ {
+ states[i] = workItem.GetWorkItemResult().State;
+ ++i;
+ }
+ return states;
+ }
+ }
+
+ ///
+ /// WorkItemsGroup start information
+ ///
+ public override WIGStartInfo WIGStartInfo
+ {
+ get { return _workItemsGroupStartInfo; }
+ }
+
+ ///
+ /// Start the Work Items Group if it was started suspended
+ ///
+ public override void Start()
+ {
+ // If the Work Items Group already started then quit
+ if (!_isSuspended)
+ {
+ return;
+ }
+ _isSuspended = false;
+
+ EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
+ }
+
+ public override void Cancel(bool abortExecution)
+ {
+ lock (_lock)
+ {
+ _canceledWorkItemsGroup.IsCanceled = true;
+ _workItemsQueue.Clear();
+ _workItemsInStpQueue = 0;
+ _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
+ }
+
+ if (abortExecution)
+ {
+ _stp.CancelAbortWorkItemsGroup(this);
+ }
+ }
+
+ ///
+ /// Wait for the thread pool to be idle
+ ///
+ public override bool WaitForIdle(int millisecondsTimeout)
+ {
+ SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
+ return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
+ }
+
+ public override event WorkItemsGroupIdleHandler OnIdle
+ {
+ add { _onIdle += value; }
+ remove { _onIdle -= value; }
+ }
+
+ #endregion
+
+ #region Private methods
+
+ private void RegisterToWorkItemCompletion(IWorkItemResult wir)
+ {
+ IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
+ iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
+ iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
+ }
+
+ public void OnSTPIsStarting()
+ {
+ if (_isSuspended)
+ {
+ return;
+ }
+
+ EnqueueToSTPNextNWorkItem(_concurrency);
+ }
+
+ public void EnqueueToSTPNextNWorkItem(int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ EnqueueToSTPNextWorkItem(null, false);
+ }
+ }
+
+ private object FireOnIdle(object state)
+ {
+ FireOnIdleImpl(_onIdle);
+ return null;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
+ {
+ if(null == onIdle)
+ {
+ return;
+ }
+
+ Delegate[] delegates = onIdle.GetInvocationList();
+ foreach(WorkItemsGroupIdleHandler eh in delegates)
+ {
+ try
+ {
+ eh(this);
+ }
+ catch { } // Suppress exceptions
+ }
+ }
+
+ private void OnWorkItemStartedCallback(WorkItem workItem)
+ {
+ lock(_lock)
+ {
+ ++_workItemsExecutingInStp;
+ }
+ }
+
+ private void OnWorkItemCompletedCallback(WorkItem workItem)
+ {
+ EnqueueToSTPNextWorkItem(null, true);
+ }
+
+ internal override void Enqueue(WorkItem workItem)
+ {
+ EnqueueToSTPNextWorkItem(workItem);
+ }
+
+ private void EnqueueToSTPNextWorkItem(WorkItem workItem)
+ {
+ EnqueueToSTPNextWorkItem(workItem, false);
+ }
+
+ private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
+ {
+ lock(_lock)
+ {
+ // Got here from OnWorkItemCompletedCallback()
+ if (decrementWorkItemsInStpQueue)
+ {
+ --_workItemsInStpQueue;
+
+ if(_workItemsInStpQueue < 0)
+ {
+ _workItemsInStpQueue = 0;
+ }
+
+ --_workItemsExecutingInStp;
+
+ if(_workItemsExecutingInStp < 0)
+ {
+ _workItemsExecutingInStp = 0;
+ }
+ }
+
+ // If the work item is not null then enqueue it
+ if (null != workItem)
+ {
+ workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
+
+ RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
+ _workItemsQueue.Enqueue(workItem);
+ //_stp.IncrementWorkItemsCount();
+
+ if ((1 == _workItemsQueue.Count) &&
+ (0 == _workItemsInStpQueue))
+ {
+ _stp.RegisterWorkItemsGroup(this);
+ IsIdle = false;
+ _isIdleWaitHandle.Reset();
+ }
+ }
+
+ // If the work items queue of the group is empty than quit
+ if (0 == _workItemsQueue.Count)
+ {
+ if (0 == _workItemsInStpQueue)
+ {
+ _stp.UnregisterWorkItemsGroup(this);
+ IsIdle = true;
+ _isIdleWaitHandle.Set();
+ if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
+ {
+ _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
+ }
+ }
+ return;
+ }
+
+ if (!_isSuspended)
+ {
+ if (_workItemsInStpQueue < _concurrency)
+ {
+ WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
+ try
+ {
+ _stp.Enqueue(nextWorkItem);
+ }
+ catch (ObjectDisposedException e)
+ {
+ e.GetHashCode();
+ // The STP has been shutdown
+ }
+
+ ++_workItemsInStpQueue;
+ }
+ }
+ }
+ }
+
+ #endregion
+ }
+
+ #endregion
+}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
new file mode 100644
index 0000000000..429de1249b
--- /dev/null
+++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
@@ -0,0 +1,471 @@
+using System;
+using System.Threading;
+
+namespace Amib.Threading.Internal
+{
+ public abstract class WorkItemsGroupBase : IWorkItemsGroup
+ {
+ #region Private Fields
+
+ ///
+ /// Contains the name of this instance of SmartThreadPool.
+ /// Can be changed by the user.
+ ///
+ private string _name = "WorkItemsGroupBase";
+
+ public WorkItemsGroupBase()
+ {
+ IsIdle = true;
+ }
+
+ #endregion
+
+ #region IWorkItemsGroup Members
+
+ #region Public Methods
+
+ ///
+ /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
+ ///
+ public string Name
+ {
+ get { return _name; }
+ set { _name = value; }
+ }
+
+ #endregion
+
+ #region Abstract Methods
+
+ public abstract int Concurrency { get; set; }
+ public abstract int WaitingCallbacks { get; }
+ public abstract object[] GetStates();
+ public abstract WIGStartInfo WIGStartInfo { get; }
+ public abstract void Start();
+ public abstract void Cancel(bool abortExecution);
+ public abstract bool WaitForIdle(int millisecondsTimeout);
+ public abstract event WorkItemsGroupIdleHandler OnIdle;
+
+ internal abstract void Enqueue(WorkItem workItem);
+ internal virtual void PreQueueWorkItem() { }
+
+ #endregion
+
+ #region Common Base Methods
+
+ ///
+ /// Cancel all the work items.
+ /// Same as Cancel(false)
+ ///
+ public virtual void Cancel()
+ {
+ Cancel(false);
+ }
+
+ ///
+ /// Wait for the SmartThreadPool/WorkItemsGroup to be idle
+ ///
+ public void WaitForIdle()
+ {
+ WaitForIdle(Timeout.Infinite);
+ }
+
+ ///
+ /// Wait for the SmartThreadPool/WorkItemsGroup to be idle
+ ///
+ public bool WaitForIdle(TimeSpan timeout)
+ {
+ return WaitForIdle((int)timeout.TotalMilliseconds);
+ }
+
+ ///
+ /// IsIdle is true when there are no work items running or queued.
+ ///
+ public bool IsIdle { get; protected set; }
+
+ #endregion
+
+ #region QueueWorkItem
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
+ {
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ /// The priority of the work item
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// Work item info
+ /// A callback to execute
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
+ {
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// The work item priority
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// Work item information
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// The work item priority
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+ WorkItemPriority workItemPriority)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Indicates on which cases to call to the post execute callback
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+ CallToPostExecute callToPostExecute)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ ///
+ /// Queue a work item
+ ///
+ /// A callback to execute
+ ///
+ /// The context object of the work item. Used for passing arguments to the work item.
+ ///
+ ///
+ /// A delegate to call after the callback completion
+ ///
+ /// Indicates on which cases to call to the post execute callback
+ /// The work item priority
+ /// Returns a work item result
+ public IWorkItemResult QueueWorkItem(
+ WorkItemCallback callback,
+ object state,
+ PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+ CallToPostExecute callToPostExecute,
+ WorkItemPriority workItemPriority)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
+ Enqueue(workItem);
+ return workItem.GetWorkItemResult();
+ }
+
+ #endregion
+
+ #region QueueWorkItem(Action<...>)
+
+ public IWorkItemResult QueueWorkItem(Action action)
+ {
+ return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority);
+ }
+
+ public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority)
+ {
+ PreQueueWorkItem ();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem (
+ this,
+ WIGStartInfo,
+ delegate
+ {
+ action.Invoke ();
+ return null;
+ }, priority);
+ Enqueue (workItem);
+ return workItem.GetWorkItemResult ();
+ }
+
+ public IWorkItemResult QueueWorkItem(Action action, T arg)
+ {
+ return QueueWorkItem (action, arg, SmartThreadPool.DefaultWorkItemPriority);
+ }
+
+ public IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority)
+ {
+ PreQueueWorkItem ();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem (
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ action.Invoke (arg);
+ return null;
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority);
+ Enqueue (workItem);
+ return workItem.GetWorkItemResult ();
+ }
+
+ public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2)
+ {
+ return QueueWorkItem (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority);
+ }
+
+ public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority)
+ {
+ PreQueueWorkItem ();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem (
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ action.Invoke (arg1, arg2);
+ return null;
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority);
+ Enqueue (workItem);
+ return workItem.GetWorkItemResult ();
+ }
+
+ public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3)
+ {
+ return QueueWorkItem (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority);
+ ;
+ }
+
+ public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority)
+ {
+ PreQueueWorkItem ();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem (
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ action.Invoke (arg1, arg2, arg3);
+ return null;
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority);
+ Enqueue (workItem);
+ return workItem.GetWorkItemResult ();
+ }
+
+ public IWorkItemResult QueueWorkItem(
+ Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
+ {
+ return QueueWorkItem (action, arg1, arg2, arg3, arg4,
+ SmartThreadPool.DefaultWorkItemPriority);
+ }
+
+ public IWorkItemResult QueueWorkItem (
+ Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority)
+ {
+ PreQueueWorkItem ();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem (
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ action.Invoke (arg1, arg2, arg3, arg4);
+ return null;
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority);
+ Enqueue (workItem);
+ return workItem.GetWorkItemResult ();
+ }
+
+ #endregion
+
+ #region QueueWorkItem(Func<...>)
+
+ public IWorkItemResult QueueWorkItem(Func func)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ return func.Invoke();
+ });
+ Enqueue(workItem);
+ return new WorkItemResultTWrapper(workItem.GetWorkItemResult());
+ }
+
+ public IWorkItemResult QueueWorkItem(Func func, T arg)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ return func.Invoke(arg);
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null);
+ Enqueue(workItem);
+ return new WorkItemResultTWrapper(workItem.GetWorkItemResult());
+ }
+
+ public IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ return func.Invoke(arg1, arg2);
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null);
+ Enqueue(workItem);
+ return new WorkItemResultTWrapper(workItem.GetWorkItemResult());
+ }
+
+ public IWorkItemResult QueueWorkItem(
+ Func func, T1 arg1, T2 arg2, T3 arg3)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ return func.Invoke(arg1, arg2, arg3);
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null);
+ Enqueue(workItem);
+ return new WorkItemResultTWrapper(workItem.GetWorkItemResult());
+ }
+
+ public IWorkItemResult QueueWorkItem(
+ Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
+ {
+ PreQueueWorkItem();
+ WorkItem workItem = WorkItemFactory.CreateWorkItem(
+ this,
+ WIGStartInfo,
+ state =>
+ {
+ return func.Invoke(arg1, arg2, arg3, arg4);
+ },
+ WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null);
+ Enqueue(workItem);
+ return new WorkItemResultTWrapper(workItem.GetWorkItemResult());
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
index af5af07b80..156a1311b6 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
@@ -1,600 +1,645 @@
-// Ami Bar
-// amibar@gmail.com
-
-using System;
-using System.Threading;
-
-namespace Amib.Threading.Internal
-{
- #region WorkItemsQueue class
-
- ///
- /// WorkItemsQueue class.
- ///
- public class WorkItemsQueue : IDisposable
- {
- #region Member variables
-
- ///
- /// Waiters queue (implemented as stack).
- ///
- private WaiterEntry _headWaiterEntry = new WaiterEntry();
-
- ///
- /// Waiters count
- ///
- private int _waitersCount = 0;
-
- ///
- /// Work items queue
- ///
- private PriorityQueue _workItems = new PriorityQueue();
-
- ///
- /// Indicate that work items are allowed to be queued
- ///
- private bool _isWorkItemsQueueActive = true;
-
- ///
- /// Each thread in the thread pool keeps its own waiter entry.
- ///
- [ThreadStatic]
- private static WaiterEntry _waiterEntry;
-
- ///
- /// A flag that indicates if the WorkItemsQueue has been disposed.
- ///
- private bool _isDisposed = false;
-
- #endregion
-
- #region Public properties
-
- ///
- /// Returns the current number of work items in the queue
- ///
- public int Count
- {
- get
- {
- lock(this)
- {
- ValidateNotDisposed();
- return _workItems.Count;
- }
- }
- }
-
- ///
- /// Returns the current number of waiters
- ///
- public int WaitersCount
- {
- get
- {
- lock(this)
- {
- ValidateNotDisposed();
- return _waitersCount;
- }
- }
- }
-
-
- #endregion
-
- #region Public methods
-
- ///
- /// Enqueue a work item to the queue.
- ///
- public bool EnqueueWorkItem(WorkItem workItem)
- {
- // A work item cannot be null, since null is used in the
- // WaitForWorkItem() method to indicate timeout or cancel
- if (null == workItem)
- {
- throw new ArgumentNullException("workItem" , "workItem cannot be null");
- }
-
- bool enqueue = true;
-
- // First check if there is a waiter waiting for work item. During
- // the check, timed out waiters are ignored. If there is no
- // waiter then the work item is queued.
- lock(this)
- {
- ValidateNotDisposed();
-
- if (!_isWorkItemsQueueActive)
- {
- return false;
- }
-
- while(_waitersCount > 0)
- {
- // Dequeue a waiter.
- WaiterEntry waiterEntry = PopWaiter();
-
- // Signal the waiter. On success break the loop
- if (waiterEntry.Signal(workItem))
- {
- enqueue = false;
- break;
- }
- }
-
- if (enqueue)
- {
- // Enqueue the work item
- _workItems.Enqueue(workItem);
- }
- }
- return true;
- }
-
-
- ///
- /// Waits for a work item or exits on timeout or cancel
- ///
- /// Timeout in milliseconds
- /// Cancel wait handle
- /// Returns true if the resource was granted
- public WorkItem DequeueWorkItem(
- int millisecondsTimeout,
- WaitHandle cancelEvent)
- {
- /// This method cause the caller to wait for a work item.
- /// If there is at least one waiting work item then the
- /// method returns immidiately with true.
- ///
- /// If there are no waiting work items then the caller
- /// is queued between other waiters for a work item to arrive.
- ///
- /// If a work item didn't come within millisecondsTimeout or
- /// the user canceled the wait by signaling the cancelEvent
- /// then the method returns false to indicate that the caller
- /// didn't get a work item.
-
- WaiterEntry waiterEntry = null;
- WorkItem workItem = null;
-
- lock(this)
- {
- ValidateNotDisposed();
-
- // If there are waiting work items then take one and return.
- if (_workItems.Count > 0)
- {
- workItem = _workItems.Dequeue() as WorkItem;
- return workItem;
- }
- // No waiting work items ...
- else
- {
- // Get the wait entry for the waiters queue
- waiterEntry = GetThreadWaiterEntry();
-
- // Put the waiter with the other waiters
- PushWaiter(waiterEntry);
- }
- }
-
- // Prepare array of wait handle for the WaitHandle.WaitAny()
- WaitHandle [] waitHandles = new WaitHandle [] {
- waiterEntry.WaitHandle,
- cancelEvent };
-
- // Wait for an available resource, cancel event, or timeout.
-
- // During the wait we are supposes to exit the synchronization
- // domain. (Placing true as the third argument of the WaitAny())
- // It just doesn't work, I don't know why, so I have lock(this)
- // statments insted of one.
-
- int index = WaitHandle.WaitAny(
- waitHandles,
- millisecondsTimeout,
- true);
-
- lock(this)
- {
- // success is true if it got a work item.
- bool success = (0 == index);
-
- // The timeout variable is used only for readability.
- // (We treat cancel as timeout)
- bool timeout = !success;
-
- // On timeout update the waiterEntry that it is timed out
- if (timeout)
- {
- // The Timeout() fails if the waiter has already been signaled
- timeout = waiterEntry.Timeout();
-
- // On timeout remove the waiter from the queue.
- // Note that the complexity is O(1).
- if(timeout)
- {
- RemoveWaiter(waiterEntry, false);
- }
-
- // Again readability
- success = !timeout;
- }
-
- // On success return the work item
- if (success)
- {
- workItem = waiterEntry.WorkItem;
-
- if (null == workItem)
- {
- workItem = _workItems.Dequeue() as WorkItem;
- }
- }
- }
- // On failure return null.
- return workItem;
- }
-
- ///
- /// Cleanup the work items queue, hence no more work
- /// items are allowed to be queue
- ///
- protected virtual void Cleanup()
- {
- lock(this)
- {
- // Deactivate only once
- if (!_isWorkItemsQueueActive)
- {
- return;
- }
-
- // Don't queue more work items
- _isWorkItemsQueueActive = false;
-
- foreach(WorkItem workItem in _workItems)
- {
- workItem.DisposeOfState();
- }
-
- // Clear the work items that are already queued
- _workItems.Clear();
-
- // Note:
- // I don't iterate over the queue and dispose of work items's states,
- // since if a work item has a state object that is still in use in the
- // application then I must not dispose it.
-
- // Tell the waiters that they were timed out.
- // It won't signal them to exit, but to ignore their
- // next work item.
- while(_waitersCount > 0)
- {
- WaiterEntry waiterEntry = PopWaiter();
- waiterEntry.Timeout();
- }
- }
- }
-
- #endregion
-
- #region Private methods
-
- ///
- /// Returns the WaiterEntry of the current thread
- ///
- ///
- /// In order to avoid creation and destuction of WaiterEntry
- /// objects each thread has its own WaiterEntry object.
- private WaiterEntry GetThreadWaiterEntry()
- {
- if (null == _waiterEntry)
- {
- _waiterEntry = new WaiterEntry();
- }
- _waiterEntry.Reset();
- return _waiterEntry;
- }
-
- #region Waiters stack methods
-
- ///
- /// Push a new waiter into the waiter's stack
- ///
- /// A waiter to put in the stack
- public void PushWaiter(WaiterEntry newWaiterEntry)
- {
- // Remove the waiter if it is already in the stack and
- // update waiter's count as needed
- RemoveWaiter(newWaiterEntry, false);
-
- // If the stack is empty then newWaiterEntry is the new head of the stack
- if (null == _headWaiterEntry._nextWaiterEntry)
- {
- _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
- newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
-
- }
- // If the stack is not empty then put newWaiterEntry as the new head
- // of the stack.
- else
- {
- // Save the old first waiter entry
- WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
-
- // Update the links
- _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
- newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
- newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
- oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
- }
-
- // Increment the number of waiters
- ++_waitersCount;
- }
-
- ///
- /// Pop a waiter from the waiter's stack
- ///
- /// Returns the first waiter in the stack
- private WaiterEntry PopWaiter()
- {
- // Store the current stack head
- WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
-
- // Store the new stack head
- WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
-
- // Update the old stack head list links and decrement the number
- // waiters.
- RemoveWaiter(oldFirstWaiterEntry, true);
-
- // Update the new stack head
- _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
- if (null != newHeadWaiterEntry)
- {
- newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
- }
-
- // Return the old stack head
- return oldFirstWaiterEntry;
- }
-
- ///
- /// Remove a waiter from the stack
- ///
- /// A waiter entry to remove
- /// If true the waiter count is always decremented
- private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
- {
- // Store the prev entry in the list
- WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
-
- // Store the next entry in the list
- WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
-
- // A flag to indicate if we need to decrement the waiters count.
- // If we got here from PopWaiter then we must decrement.
- // If we got here from PushWaiter then we decrement only if
- // the waiter was already in the stack.
- bool decrementCounter = popDecrement;
-
- // Null the waiter's entry links
- waiterEntry._prevWaiterEntry = null;
- waiterEntry._nextWaiterEntry = null;
-
- // If the waiter entry had a prev link then update it.
- // It also means that the waiter is already in the list and we
- // need to decrement the waiters count.
- if (null != prevWaiterEntry)
- {
- prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
- decrementCounter = true;
- }
-
- // If the waiter entry had a next link then update it.
- // It also means that the waiter is already in the list and we
- // need to decrement the waiters count.
- if (null != nextWaiterEntry)
- {
- nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
- decrementCounter = true;
- }
-
- // Decrement the waiters count if needed
- if (decrementCounter)
- {
- --_waitersCount;
- }
- }
-
- #endregion
-
- #endregion
-
- #region WaiterEntry class
-
- // A waiter entry in the _waiters queue.
- public class WaiterEntry : IDisposable
- {
- #region Member variables
-
- ///
- /// Event to signal the waiter that it got the work item.
- ///
- private AutoResetEvent _waitHandle = new AutoResetEvent(false);
-
- ///
- /// Flag to know if this waiter already quited from the queue
- /// because of a timeout.
- ///
- private bool _isTimedout = false;
-
- ///
- /// Flag to know if the waiter was signaled and got a work item.
- ///
- private bool _isSignaled = false;
-
- ///
- /// A work item that passed directly to the waiter withou going
- /// through the queue
- ///
- private WorkItem _workItem = null;
-
- private bool _isDisposed = false;
-
- // Linked list members
- internal WaiterEntry _nextWaiterEntry = null;
- internal WaiterEntry _prevWaiterEntry = null;
-
- #endregion
-
- #region Construction
-
- public WaiterEntry()
- {
- Reset();
- }
-
- #endregion
-
- #region Public methods
-
- public WaitHandle WaitHandle
- {
- get { return _waitHandle; }
- }
-
- public WorkItem WorkItem
- {
- get
- {
- lock(this)
- {
- return _workItem;
- }
- }
- }
-
- ///
- /// Signal the waiter that it got a work item.
- ///
- /// Return true on success
- /// The method fails if Timeout() preceded its call
- public bool Signal(WorkItem workItem)
- {
- lock(this)
- {
- if (!_isTimedout)
- {
- _workItem = workItem;
- _isSignaled = true;
- _waitHandle.Set();
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Mark the wait entry that it has been timed out
- ///
- /// Return true on success
- /// The method fails if Signal() preceded its call
- public bool Timeout()
- {
- lock(this)
- {
- // Time out can happen only if the waiter wasn't marked as
- // signaled
- if (!_isSignaled)
- {
- // We don't remove the waiter from the queue, the DequeueWorkItem
- // method skips _waiters that were timed out.
- _isTimedout = true;
- return true;
- }
- }
- return false;
- }
-
- ///
- /// Reset the wait entry so it can be used again
- ///
- public void Reset()
- {
- _workItem = null;
- _isTimedout = false;
- _isSignaled = false;
- _waitHandle.Reset();
- }
-
- ///
- /// Free resources
- ///
- public void Close()
- {
- if (null != _waitHandle)
- {
- _waitHandle.Close();
- _waitHandle = null;
- }
- }
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- if (!_isDisposed)
- {
- Close();
- _isDisposed = true;
- }
- }
-
- ~WaiterEntry()
- {
- Dispose();
- }
-
- #endregion
- }
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- if (!_isDisposed)
- {
- Cleanup();
- _isDisposed = true;
- GC.SuppressFinalize(this);
- }
- }
-
- ~WorkItemsQueue()
- {
- Cleanup();
- }
-
- private void ValidateNotDisposed()
- {
- if(_isDisposed)
- {
- throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
- }
- }
-
- #endregion
- }
-
- #endregion
-}
-
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Amib.Threading.Internal
+{
+ #region WorkItemsQueue class
+
+ ///
+ /// WorkItemsQueue class.
+ ///
+ public class WorkItemsQueue : IDisposable
+ {
+ #region Member variables
+
+ ///
+ /// Waiters queue (implemented as stack).
+ ///
+ private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
+
+ ///
+ /// Waiters count
+ ///
+ private int _waitersCount = 0;
+
+ ///
+ /// Work items queue
+ ///
+ private readonly PriorityQueue _workItems = new PriorityQueue();
+
+ ///
+ /// Indicate that work items are allowed to be queued
+ ///
+ private bool _isWorkItemsQueueActive = true;
+
+
+#if (WINDOWS_PHONE)
+ private static readonly Dictionary _waiterEntries = new Dictionary();
+#elif (_WINDOWS_CE)
+ private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
+#else
+
+ [ThreadStatic]
+ private static WaiterEntry _waiterEntry;
+#endif
+
+
+ ///
+ /// Each thread in the thread pool keeps its own waiter entry.
+ ///
+ private static WaiterEntry CurrentWaiterEntry
+ {
+#if (WINDOWS_PHONE)
+ get
+ {
+ lock (_waiterEntries)
+ {
+ WaiterEntry waiterEntry;
+ if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
+ {
+ return waiterEntry;
+ }
+ }
+ return null;
+ }
+ set
+ {
+ lock (_waiterEntries)
+ {
+ _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
+ }
+ }
+#elif (_WINDOWS_CE)
+ get
+ {
+ return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
+ }
+ set
+ {
+ Thread.SetData(_waiterEntrySlot, value);
+ }
+#else
+ get
+ {
+ return _waiterEntry;
+ }
+ set
+ {
+ _waiterEntry = value;
+ }
+#endif
+ }
+
+ ///
+ /// A flag that indicates if the WorkItemsQueue has been disposed.
+ ///
+ private bool _isDisposed = false;
+
+ #endregion
+
+ #region Public properties
+
+ ///
+ /// Returns the current number of work items in the queue
+ ///
+ public int Count
+ {
+ get
+ {
+ return _workItems.Count;
+ }
+ }
+
+ ///
+ /// Returns the current number of waiters
+ ///
+ public int WaitersCount
+ {
+ get
+ {
+ return _waitersCount;
+ }
+ }
+
+
+ #endregion
+
+ #region Public methods
+
+ ///
+ /// Enqueue a work item to the queue.
+ ///
+ public bool EnqueueWorkItem(WorkItem workItem)
+ {
+ // A work item cannot be null, since null is used in the
+ // WaitForWorkItem() method to indicate timeout or cancel
+ if (null == workItem)
+ {
+ throw new ArgumentNullException("workItem" , "workItem cannot be null");
+ }
+
+ bool enqueue = true;
+
+ // First check if there is a waiter waiting for work item. During
+ // the check, timed out waiters are ignored. If there is no
+ // waiter then the work item is queued.
+ lock(this)
+ {
+ ValidateNotDisposed();
+
+ if (!_isWorkItemsQueueActive)
+ {
+ return false;
+ }
+
+ while(_waitersCount > 0)
+ {
+ // Dequeue a waiter.
+ WaiterEntry waiterEntry = PopWaiter();
+
+ // Signal the waiter. On success break the loop
+ if (waiterEntry.Signal(workItem))
+ {
+ enqueue = false;
+ break;
+ }
+ }
+
+ if (enqueue)
+ {
+ // Enqueue the work item
+ _workItems.Enqueue(workItem);
+ }
+ }
+ return true;
+ }
+
+
+ ///
+ /// Waits for a work item or exits on timeout or cancel
+ ///
+ /// Timeout in milliseconds
+ /// Cancel wait handle
+ /// Returns true if the resource was granted
+ public WorkItem DequeueWorkItem(
+ int millisecondsTimeout,
+ WaitHandle cancelEvent)
+ {
+ // This method cause the caller to wait for a work item.
+ // If there is at least one waiting work item then the
+ // method returns immidiately with it.
+ //
+ // If there are no waiting work items then the caller
+ // is queued between other waiters for a work item to arrive.
+ //
+ // If a work item didn't come within millisecondsTimeout or
+ // the user canceled the wait by signaling the cancelEvent
+ // then the method returns null to indicate that the caller
+ // didn't get a work item.
+
+ WaiterEntry waiterEntry;
+ WorkItem workItem = null;
+ lock (this)
+ {
+ ValidateNotDisposed();
+
+ // If there are waiting work items then take one and return.
+ if (_workItems.Count > 0)
+ {
+ workItem = _workItems.Dequeue() as WorkItem;
+ return workItem;
+ }
+
+ // No waiting work items ...
+
+ // Get the waiter entry for the waiters queue
+ waiterEntry = GetThreadWaiterEntry();
+
+ // Put the waiter with the other waiters
+ PushWaiter(waiterEntry);
+ }
+
+ // Prepare array of wait handle for the WaitHandle.WaitAny()
+ WaitHandle [] waitHandles = new WaitHandle[] {
+ waiterEntry.WaitHandle,
+ cancelEvent };
+
+ // Wait for an available resource, cancel event, or timeout.
+
+ // During the wait we are supposes to exit the synchronization
+ // domain. (Placing true as the third argument of the WaitAny())
+ // It just doesn't work, I don't know why, so I have two lock(this)
+ // statments instead of one.
+
+ int index = STPEventWaitHandle.WaitAny(
+ waitHandles,
+ millisecondsTimeout,
+ true);
+
+ lock(this)
+ {
+ // success is true if it got a work item.
+ bool success = (0 == index);
+
+ // The timeout variable is used only for readability.
+ // (We treat cancel as timeout)
+ bool timeout = !success;
+
+ // On timeout update the waiterEntry that it is timed out
+ if (timeout)
+ {
+ // The Timeout() fails if the waiter has already been signaled
+ timeout = waiterEntry.Timeout();
+
+ // On timeout remove the waiter from the queue.
+ // Note that the complexity is O(1).
+ if(timeout)
+ {
+ RemoveWaiter(waiterEntry, false);
+ }
+
+ // Again readability
+ success = !timeout;
+ }
+
+ // On success return the work item
+ if (success)
+ {
+ workItem = waiterEntry.WorkItem;
+
+ if (null == workItem)
+ {
+ workItem = _workItems.Dequeue() as WorkItem;
+ }
+ }
+ }
+ // On failure return null.
+ return workItem;
+ }
+
+ ///
+ /// Cleanup the work items queue, hence no more work
+ /// items are allowed to be queue
+ ///
+ private void Cleanup()
+ {
+ lock(this)
+ {
+ // Deactivate only once
+ if (!_isWorkItemsQueueActive)
+ {
+ return;
+ }
+
+ // Don't queue more work items
+ _isWorkItemsQueueActive = false;
+
+ foreach(WorkItem workItem in _workItems)
+ {
+ workItem.DisposeOfState();
+ }
+
+ // Clear the work items that are already queued
+ _workItems.Clear();
+
+ // Note:
+ // I don't iterate over the queue and dispose of work items's states,
+ // since if a work item has a state object that is still in use in the
+ // application then I must not dispose it.
+
+ // Tell the waiters that they were timed out.
+ // It won't signal them to exit, but to ignore their
+ // next work item.
+ while(_waitersCount > 0)
+ {
+ WaiterEntry waiterEntry = PopWaiter();
+ waiterEntry.Timeout();
+ }
+ }
+ }
+
+ public object[] GetStates()
+ {
+ lock (this)
+ {
+ object[] states = new object[_workItems.Count];
+ int i = 0;
+ foreach (WorkItem workItem in _workItems)
+ {
+ states[i] = workItem.GetWorkItemResult().State;
+ ++i;
+ }
+ return states;
+ }
+ }
+
+ #endregion
+
+ #region Private methods
+
+ ///
+ /// Returns the WaiterEntry of the current thread
+ ///
+ ///
+ /// In order to avoid creation and destuction of WaiterEntry
+ /// objects each thread has its own WaiterEntry object.
+ private static WaiterEntry GetThreadWaiterEntry()
+ {
+ if (null == CurrentWaiterEntry)
+ {
+ CurrentWaiterEntry = new WaiterEntry();
+ }
+ CurrentWaiterEntry.Reset();
+ return CurrentWaiterEntry;
+ }
+
+ #region Waiters stack methods
+
+ ///
+ /// Push a new waiter into the waiter's stack
+ ///
+ /// A waiter to put in the stack
+ public void PushWaiter(WaiterEntry newWaiterEntry)
+ {
+ // Remove the waiter if it is already in the stack and
+ // update waiter's count as needed
+ RemoveWaiter(newWaiterEntry, false);
+
+ // If the stack is empty then newWaiterEntry is the new head of the stack
+ if (null == _headWaiterEntry._nextWaiterEntry)
+ {
+ _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
+ newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
+
+ }
+ // If the stack is not empty then put newWaiterEntry as the new head
+ // of the stack.
+ else
+ {
+ // Save the old first waiter entry
+ WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
+
+ // Update the links
+ _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
+ newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
+ newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
+ oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
+ }
+
+ // Increment the number of waiters
+ ++_waitersCount;
+ }
+
+ ///
+ /// Pop a waiter from the waiter's stack
+ ///
+ /// Returns the first waiter in the stack
+ private WaiterEntry PopWaiter()
+ {
+ // Store the current stack head
+ WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
+
+ // Store the new stack head
+ WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
+
+ // Update the old stack head list links and decrement the number
+ // waiters.
+ RemoveWaiter(oldFirstWaiterEntry, true);
+
+ // Update the new stack head
+ _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
+ if (null != newHeadWaiterEntry)
+ {
+ newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
+ }
+
+ // Return the old stack head
+ return oldFirstWaiterEntry;
+ }
+
+ ///
+ /// Remove a waiter from the stack
+ ///
+ /// A waiter entry to remove
+ /// If true the waiter count is always decremented
+ private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
+ {
+ // Store the prev entry in the list
+ WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
+
+ // Store the next entry in the list
+ WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
+
+ // A flag to indicate if we need to decrement the waiters count.
+ // If we got here from PopWaiter then we must decrement.
+ // If we got here from PushWaiter then we decrement only if
+ // the waiter was already in the stack.
+ bool decrementCounter = popDecrement;
+
+ // Null the waiter's entry links
+ waiterEntry._prevWaiterEntry = null;
+ waiterEntry._nextWaiterEntry = null;
+
+ // If the waiter entry had a prev link then update it.
+ // It also means that the waiter is already in the list and we
+ // need to decrement the waiters count.
+ if (null != prevWaiterEntry)
+ {
+ prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
+ decrementCounter = true;
+ }
+
+ // If the waiter entry had a next link then update it.
+ // It also means that the waiter is already in the list and we
+ // need to decrement the waiters count.
+ if (null != nextWaiterEntry)
+ {
+ nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
+ decrementCounter = true;
+ }
+
+ // Decrement the waiters count if needed
+ if (decrementCounter)
+ {
+ --_waitersCount;
+ }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region WaiterEntry class
+
+ // A waiter entry in the _waiters queue.
+ public sealed class WaiterEntry : IDisposable
+ {
+ #region Member variables
+
+ ///
+ /// Event to signal the waiter that it got the work item.
+ ///
+ //private AutoResetEvent _waitHandle = new AutoResetEvent(false);
+ private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
+
+ ///
+ /// Flag to know if this waiter already quited from the queue
+ /// because of a timeout.
+ ///
+ private bool _isTimedout = false;
+
+ ///
+ /// Flag to know if the waiter was signaled and got a work item.
+ ///
+ private bool _isSignaled = false;
+
+ ///
+ /// A work item that passed directly to the waiter withou going
+ /// through the queue
+ ///
+ private WorkItem _workItem = null;
+
+ private bool _isDisposed = false;
+
+ // Linked list members
+ internal WaiterEntry _nextWaiterEntry = null;
+ internal WaiterEntry _prevWaiterEntry = null;
+
+ #endregion
+
+ #region Construction
+
+ public WaiterEntry()
+ {
+ Reset();
+ }
+
+ #endregion
+
+ #region Public methods
+
+ public WaitHandle WaitHandle
+ {
+ get { return _waitHandle; }
+ }
+
+ public WorkItem WorkItem
+ {
+ get
+ {
+ return _workItem;
+ }
+ }
+
+ ///
+ /// Signal the waiter that it got a work item.
+ ///
+ /// Return true on success
+ /// The method fails if Timeout() preceded its call
+ public bool Signal(WorkItem workItem)
+ {
+ lock(this)
+ {
+ if (!_isTimedout)
+ {
+ _workItem = workItem;
+ _isSignaled = true;
+ _waitHandle.Set();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Mark the wait entry that it has been timed out
+ ///
+ /// Return true on success
+ /// The method fails if Signal() preceded its call
+ public bool Timeout()
+ {
+ lock(this)
+ {
+ // Time out can happen only if the waiter wasn't marked as
+ // signaled
+ if (!_isSignaled)
+ {
+ // We don't remove the waiter from the queue, the DequeueWorkItem
+ // method skips _waiters that were timed out.
+ _isTimedout = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Reset the wait entry so it can be used again
+ ///
+ public void Reset()
+ {
+ _workItem = null;
+ _isTimedout = false;
+ _isSignaled = false;
+ _waitHandle.Reset();
+ }
+
+ ///
+ /// Free resources
+ ///
+ public void Close()
+ {
+ if (null != _waitHandle)
+ {
+ _waitHandle.Close();
+ _waitHandle = null;
+ }
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ lock (this)
+ {
+ if (!_isDisposed)
+ {
+ Close();
+ }
+ _isDisposed = true;
+ }
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ if (!_isDisposed)
+ {
+ Cleanup();
+ }
+ _isDisposed = true;
+ }
+
+ private void ValidateNotDisposed()
+ {
+ if(_isDisposed)
+ {
+ throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
+ }
+ }
+
+ #endregion
+ }
+
+ #endregion
+}
+