From ac135c649c55fefc73e2f5f654a5ff65f45d50c0 Mon Sep 17 00:00:00 2001
From: Melanie
Date: Tue, 30 Apr 2013 23:35:59 +0200
Subject: Fix CAPS to work like they should - do not send caps to the viewer if
they're not in the requested caps list. The previous wrong behavior caused
the debug setting "UseHTTPInventory" to fail on all viewers when turned off.
UDB inventory would not be correctly used in that case.
---
OpenSim/Capabilities/CapsHandlers.cs | 7 +++++--
.../ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 13 ++++++++++++-
.../Region/CoreModules/Framework/Caps/CapabilitiesModule.cs | 2 +-
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs
index 1709f46..458272d 100644
--- a/OpenSim/Capabilities/CapsHandlers.cs
+++ b/OpenSim/Capabilities/CapsHandlers.cs
@@ -158,7 +158,7 @@ namespace OpenSim.Framework.Capabilities
/// capabilities and their handler details.
///
/// If true, then exclude the seed cap.
- public Hashtable GetCapsDetails(bool excludeSeed)
+ public Hashtable GetCapsDetails(bool excludeSeed, List requestedCaps)
{
Hashtable caps = new Hashtable();
string protocol = "http://";
@@ -175,6 +175,9 @@ namespace OpenSim.Framework.Capabilities
if (excludeSeed && "SEED" == capsName)
continue;
+ if (requestedCaps != null && !requestedCaps.Contains(capsName))
+ continue;
+
caps[capsName] = baseUrl + m_capsHandlers[capsName].Path;
}
}
@@ -182,4 +185,4 @@ namespace OpenSim.Framework.Capabilities
return caps;
}
}
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8752404..a46c24a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -273,11 +273,22 @@ namespace OpenSim.Region.ClientStack.Linden
return string.Empty;
}
- Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true);
+ OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request);
+ List validCaps = new List();
+
+ foreach (OSD c in capsRequested)
+ validCaps.Add(c.AsString());
+
+ Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps);
// Add the external too
foreach (KeyValuePair kvp in m_HostCapsObj.ExternalCapsHandlers)
+ {
+ if (!validCaps.Contains(kvp.Key))
+ continue;
+
caps[kvp.Key] = kvp.Value;
+ }
string result = LLSDHelpers.SerialiseLLSDReply(caps);
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 8329af0..6ae9448 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -240,7 +240,7 @@ namespace OpenSim.Region.CoreModules.Framework
{
caps.AppendFormat("** User {0}:\n", kvp.Key);
- for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); )
+ for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); )
{
Uri uri = new Uri(kvp2.Value.ToString());
caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
--
cgit v1.1
From 206fb306a7820cf593570e35ddfa8e7c5a10e449 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 1 May 2013 19:01:43 +0100
Subject: Update SmartThreadPool to latest version 2.2.3 with a major and minor
change.
SmartThreadPool code comes from http://www.codeproject.com/Articles/7933/Smart-Thread-Pool
This version implements thread abort (via WorkItem.Cancel(true)), threadpool naming, max thread stack, etc. so we no longer need to manually patch those.
However, two changes have been made to stock 2.2.3.
Major change: WorkItem.Cancel(bool abortExecution) in our version does not succeed if the work item was in progress and thread abort was not specified.
This is to match previous behaviour where we handle co-operative termination via another mechanism rather than checking WorkItem.IsCanceled.
Minor change: Did not add STP's StopWatch implementation as this is only used WinCE and Silverlight and causes a build clash with System.Diagnostics.StopWatch
The reason for updating is to see if this improves http://opensimulator.org/mantis/view.php?id=6557 and http://opensimulator.org/mantis/view.php?id=6586
---
OpenSim/Framework/Util.cs | 20 +-
.../ScriptEngine/Interfaces/IScriptInstance.cs | 2 +-
.../ScriptEngine/Shared/Instance/ScriptInstance.cs | 9 +-
OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 4 +-
OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs | 6 +-
ThirdParty/SmartThreadPool/AssemblyInfo.cs | 61 -
ThirdParty/SmartThreadPool/CallerThreadContext.cs | 361 +--
.../SmartThreadPool/CanceledWorkItemsGroup.cs | 14 +
ThirdParty/SmartThreadPool/EventWaitHandle.cs | 104 +
.../SmartThreadPool/EventWaitHandleFactory.cs | 82 +
ThirdParty/SmartThreadPool/Exceptions.cs | 192 +-
ThirdParty/SmartThreadPool/Interfaces.cs | 899 ++++--
ThirdParty/SmartThreadPool/InternalInterfaces.cs | 27 +
ThirdParty/SmartThreadPool/PriorityQueue.cs | 479 ++-
.../SmartThreadPool/Properties/AssemblyInfo.cs | 23 +
ThirdParty/SmartThreadPool/SLExt.cs | 16 +
ThirdParty/SmartThreadPool/STPEventWaitHandle.cs | 62 +
.../SmartThreadPool/STPPerformanceCounter.cs | 802 ++---
ThirdParty/SmartThreadPool/STPStartInfo.cs | 325 +-
.../SmartThreadPool/SmartThreadPool.ThreadEntry.cs | 60 +
ThirdParty/SmartThreadPool/SmartThreadPool.cs | 3180 +++++++++++---------
.../SmartThreadPool/SynchronizedDictionary.cs | 89 +
ThirdParty/SmartThreadPool/WIGStartInfo.cs | 270 +-
.../SmartThreadPool/WorkItem.WorkItemResult.cs | 190 ++
ThirdParty/SmartThreadPool/WorkItem.cs | 649 ++--
ThirdParty/SmartThreadPool/WorkItemFactory.cs | 676 +++--
ThirdParty/SmartThreadPool/WorkItemInfo.cs | 171 +-
.../SmartThreadPool/WorkItemResultTWrapper.cs | 128 +
ThirdParty/SmartThreadPool/WorkItemsGroup.cs | 873 +++---
ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs | 471 +++
ThirdParty/SmartThreadPool/WorkItemsQueue.cs | 1245 ++++----
31 files changed, 6688 insertions(+), 4802 deletions(-)
delete mode 100644 ThirdParty/SmartThreadPool/AssemblyInfo.cs
create mode 100644 ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs
create mode 100644 ThirdParty/SmartThreadPool/EventWaitHandle.cs
create mode 100644 ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs
create mode 100644 ThirdParty/SmartThreadPool/InternalInterfaces.cs
create mode 100644 ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs
create mode 100644 ThirdParty/SmartThreadPool/SLExt.cs
create mode 100644 ThirdParty/SmartThreadPool/STPEventWaitHandle.cs
create mode 100644 ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
create mode 100644 ThirdParty/SmartThreadPool/SynchronizedDictionary.cs
create mode 100644 ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs
create mode 100644 ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs
create mode 100644 ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index bde4673..a3602e9 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1840,7 +1840,7 @@ namespace OpenSim.Framework
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 35ae44c..b9a217b 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
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 1e6db43..f9d3afc 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -564,9 +564,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
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 0d9babb..5804aa8 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -483,7 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
///
/// 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 8dd7677..9d9dee1 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
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 e2465b0..0000000
--- 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 6ea53f6..2177241 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 0000000..4a2a3e7
--- /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 0000000..70a1a29
--- /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 0000000..2f8c55b
--- /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 c454709..8e66ce9 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 f1c1fcf..29c8a3e 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
}
- #endregion
+ 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;
+ }
- #region Member Variables
+ return valid;
+ }
- public Thread currentThread;
+ #endregion
+
+ #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;
///
+ /// A reference to an object that indicates whatever the
+ /// SmartThreadPool has been canceled
+ ///
+ private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
+
+ ///
/// The work item group this work item belong to.
- ///
///
- private IWorkItemsGroup _workItemsGroup;
+ private readonly IWorkItemsGroup _workItemsGroup;
- #region Performance Counter fields
+ ///
+ /// 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 time when the work items is queued.
- /// Used with the performance counter.
+ /// The absulote time when the work item will be timeout
///
- private DateTime _queuedTime;
+ private long _expirationTime;
+
+ #region Performance Counter fields
+
+
+
///
- /// 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 _processingStopwatch.Elapsed;
+ }
+ }
+
+ internal WorkItemInfo WorkItemInfo
+ {
+ get
{
- return (_endProcessTime - _beginProcessTime);
+ 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)
+ {
+ throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
+ }
+#endif
+ bool success = false;
+ bool signalComplete = false;
+
+ lock (this)
{
- switch(GetWorkItemState())
+ 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 dfcb54f..2d6601e 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 c259339..5fbceb8 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 0000000..a0bf8b8
--- /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 01ac8dd..67dcbdd 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 0000000..429de12
--- /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 af5af07..156a131 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
+}
+
--
cgit v1.1
From 8d3250cee4d16113e955c42d3cce02b0024bea55 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 1 May 2013 19:15:05 +0100
Subject: Add information about creating a PID file for robust to the
Robust.ini and Robust.HG.ini example files
---
bin/Robust.HG.ini.example | 27 +++++++++++++++------------
bin/Robust.ini.example | 28 +++++++++++++++-------------
2 files changed, 30 insertions(+), 25 deletions(-)
diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example
index 581c31d..d74f205 100644
--- a/bin/Robust.HG.ini.example
+++ b/bin/Robust.HG.ini.example
@@ -21,18 +21,21 @@
; * [[@]/][:]
; *
[Startup]
-
- ; Plugin Registry Location
- ; Set path to directory for plugin registry. Information
- ; about the registered repositories and installed plugins
- ; will be stored here
- ; The Robust.exe process must have R/W access to the location
- RegistryLocation = "."
-
- ; Modular configurations
- ; Set path to directory for modular ini files...
- ; The Robust.exe process must have R/W access to the location
- ConfigDirectory = "/home/opensim/etc/Configs"
+ ; Place to create a PID file
+ ; If no path if specified then a PID file is not created.
+ ; PIDFile = "/tmp/my.pid"
+
+ ; Plugin Registry Location
+ ; Set path to directory for plugin registry. Information
+ ; about the registered repositories and installed plugins
+ ; will be stored here
+ ; The Robust.exe process must have R/W access to the location
+ RegistryLocation = "."
+
+ ; Modular configurations
+ ; Set path to directory for modular ini files...
+ ; The Robust.exe process must have R/W access to the location
+ ConfigDirectory = "/home/opensim/etc/Configs"
[ServiceList]
diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example
index b98132e..b7b2524 100644
--- a/bin/Robust.ini.example
+++ b/bin/Robust.ini.example
@@ -13,19 +13,21 @@
; * [[@]/][:]
; *
[Startup]
-
- ; Plugin Registry Location
- ; Set path to directory for plugin registry. Information
- ; about the registered repositories and installed plugins
- ; will be stored here
- ; The Robust.exe process must have R/W access to the location
- RegistryLocation = "."
-
-
- ; Modular configurations
- ; Set path to directory for modular ini files...
- ; The Robust.exe process must have R/W access to the location
- ConfigDirectory = "/home/opensim/etc/Configs"
+ ; Place to create a PID file
+ ; If no path if specified then a PID file is not created.
+ ; PIDFile = "/tmp/my.pid"
+
+ ; Plugin Registry Location
+ ; Set path to directory for plugin registry. Information
+ ; about the registered repositories and installed plugins
+ ; will be stored here
+ ; The Robust.exe process must have R/W access to the location
+ RegistryLocation = "."
+
+ ; Modular configurations
+ ; Set path to directory for modular ini files...
+ ; The Robust.exe process must have R/W access to the location
+ ConfigDirectory = "/home/opensim/etc/Configs"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
--
cgit v1.1
From 81a90e30c637f84e6ef5d1cf7c188c1f6db12eb3 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 1 May 2013 19:29:46 +0100
Subject: Add in-code exaplanation for the change in cancellation signalling in
STP 2.2.3. Remove left in Console.WriteLine accidentally inserted in recent
206fb306
---
OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 2 --
ThirdParty/SmartThreadPool/WorkItem.cs | 10 ++++++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index f9d3afc..887a317 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -628,8 +628,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
}
}
- Console.WriteLine("Here9");
-
lock (EventQueue)
{
workItem = m_CurrentWorkItem;
diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs
index f229d1f..185f10c 100644
--- a/ThirdParty/SmartThreadPool/WorkItem.cs
+++ b/ThirdParty/SmartThreadPool/WorkItem.cs
@@ -753,6 +753,16 @@ namespace Amib.Threading.Internal
}
else
{
+ // **************************
+ // Stock SmartThreadPool 2.2.3 sets these to true and relies on the thread to check the
+ // WorkItem cancellation status. However, OpenSimulator uses a different mechanism to notify
+ // scripts of co-operative termination and the abort code also relies on this method
+ // returning false in order to implement a small wait.
+ //
+ // Therefore, as was the case previously with STP, we will not signal successful cancellation
+ // here. It's possible that OpenSimulator code could be changed in the future to remove
+ // the need for this change.
+ // **************************
success = false;
signalComplete = false;
}
--
cgit v1.1
From b26276c8c48a8cf4edb468b2fd428815034a6320 Mon Sep 17 00:00:00 2001
From: Melanie
Date: Wed, 1 May 2013 21:35:50 +0100
Subject: Fix the long standing bug of items being delivered to lost and found
or trash when takig copy. This bug was recently aggravated through the perms
changes required for the export permission.
---
.../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index e0009bb..eb37626 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -646,11 +646,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
}
else
{
- if (remoteClient == null || so.OwnerID != remoteClient.AgentId)
+ if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
{
// Taking copy of another person's item. Take to
// Objects folder.
folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
+ so.FromFolderID = UUID.Zero;
}
else
{
@@ -666,7 +667,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
//
if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
{
- if (so.FromFolderID != UUID.Zero && userID == remoteClient.AgentId)
+ if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
{
InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
folder = m_Scene.InventoryService.GetFolder(f);
--
cgit v1.1