diff options
Diffstat (limited to '')
58 files changed, 8903 insertions, 0 deletions
diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs new file mode 100644 index 0000000..925c39b --- /dev/null +++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs | |||
@@ -0,0 +1,138 @@ | |||
1 | |||
2 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
3 | |||
4 | using System; | ||
5 | using System.Diagnostics; | ||
6 | using System.Threading; | ||
7 | using System.Reflection; | ||
8 | using System.Web; | ||
9 | using System.Runtime.Remoting.Messaging; | ||
10 | |||
11 | |||
12 | namespace Amib.Threading.Internal | ||
13 | { | ||
14 | #region CallerThreadContext class | ||
15 | |||
16 | /// <summary> | ||
17 | /// This class stores the caller call context in order to restore | ||
18 | /// it when the work item is executed in the thread pool environment. | ||
19 | /// </summary> | ||
20 | internal class CallerThreadContext | ||
21 | { | ||
22 | #region Prepare reflection information | ||
23 | |||
24 | // Cached type information. | ||
25 | private static readonly MethodInfo getLogicalCallContextMethodInfo = | ||
26 | typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); | ||
27 | |||
28 | private static readonly MethodInfo setLogicalCallContextMethodInfo = | ||
29 | typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); | ||
30 | |||
31 | private static string HttpContextSlotName = GetHttpContextSlotName(); | ||
32 | |||
33 | private static string GetHttpContextSlotName() | ||
34 | { | ||
35 | FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); | ||
36 | |||
37 | if (fi != null) | ||
38 | { | ||
39 | return (string) fi.GetValue(null); | ||
40 | } | ||
41 | |||
42 | return "HttpContext"; | ||
43 | } | ||
44 | |||
45 | #endregion | ||
46 | |||
47 | #region Private fields | ||
48 | |||
49 | private HttpContext _httpContext; | ||
50 | private LogicalCallContext _callContext; | ||
51 | |||
52 | #endregion | ||
53 | |||
54 | /// <summary> | ||
55 | /// Constructor | ||
56 | /// </summary> | ||
57 | private CallerThreadContext() | ||
58 | { | ||
59 | } | ||
60 | |||
61 | public bool CapturedCallContext | ||
62 | { | ||
63 | get | ||
64 | { | ||
65 | return (null != _callContext); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | public bool CapturedHttpContext | ||
70 | { | ||
71 | get | ||
72 | { | ||
73 | return (null != _httpContext); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | /// <summary> | ||
78 | /// Captures the current thread context | ||
79 | /// </summary> | ||
80 | /// <returns></returns> | ||
81 | public static CallerThreadContext Capture( | ||
82 | bool captureCallContext, | ||
83 | bool captureHttpContext) | ||
84 | { | ||
85 | Debug.Assert(captureCallContext || captureHttpContext); | ||
86 | |||
87 | CallerThreadContext callerThreadContext = new CallerThreadContext(); | ||
88 | |||
89 | // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() | ||
90 | // Capture Call Context | ||
91 | if(captureCallContext && (getLogicalCallContextMethodInfo != null)) | ||
92 | { | ||
93 | callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); | ||
94 | if (callerThreadContext._callContext != null) | ||
95 | { | ||
96 | callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | // Capture httpContext | ||
101 | if (captureHttpContext && (null != HttpContext.Current)) | ||
102 | { | ||
103 | callerThreadContext._httpContext = HttpContext.Current; | ||
104 | } | ||
105 | |||
106 | return callerThreadContext; | ||
107 | } | ||
108 | |||
109 | /// <summary> | ||
110 | /// Applies the thread context stored earlier | ||
111 | /// </summary> | ||
112 | /// <param name="callerThreadContext"></param> | ||
113 | public static void Apply(CallerThreadContext callerThreadContext) | ||
114 | { | ||
115 | if (null == callerThreadContext) | ||
116 | { | ||
117 | throw new ArgumentNullException("callerThreadContext"); | ||
118 | } | ||
119 | |||
120 | // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() | ||
121 | // Restore call context | ||
122 | if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) | ||
123 | { | ||
124 | setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); | ||
125 | } | ||
126 | |||
127 | // Restore HttpContext | ||
128 | if (callerThreadContext._httpContext != null) | ||
129 | { | ||
130 | HttpContext.Current = callerThreadContext._httpContext; | ||
131 | //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | #endregion | ||
137 | } | ||
138 | #endif | ||
diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs new file mode 100644 index 0000000..5752957 --- /dev/null +++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs | |||
@@ -0,0 +1,14 @@ | |||
1 | namespace Amib.Threading.Internal | ||
2 | { | ||
3 | internal class CanceledWorkItemsGroup | ||
4 | { | ||
5 | public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); | ||
6 | |||
7 | public CanceledWorkItemsGroup() | ||
8 | { | ||
9 | IsCanceled = false; | ||
10 | } | ||
11 | |||
12 | public bool IsCanceled { get; set; } | ||
13 | } | ||
14 | } \ No newline at end of file | ||
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs new file mode 100644 index 0000000..b7983cd --- /dev/null +++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs | |||
@@ -0,0 +1,104 @@ | |||
1 | #if (_WINDOWS_CE) | ||
2 | |||
3 | using System; | ||
4 | using System.Runtime.InteropServices; | ||
5 | using System.Threading; | ||
6 | |||
7 | namespace Amib.Threading.Internal | ||
8 | { | ||
9 | /// <summary> | ||
10 | /// EventWaitHandle class | ||
11 | /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation. | ||
12 | /// So I wrote this class to implement these two methods with some of their overloads. | ||
13 | /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny. | ||
14 | /// Note that this class doesn't even inherit from WaitHandle! | ||
15 | /// </summary> | ||
16 | public class STPEventWaitHandle | ||
17 | { | ||
18 | #region Public Constants | ||
19 | |||
20 | public const int WaitTimeout = Timeout.Infinite; | ||
21 | |||
22 | #endregion | ||
23 | |||
24 | #region Private External Constants | ||
25 | |||
26 | private const Int32 WAIT_FAILED = -1; | ||
27 | private const Int32 WAIT_TIMEOUT = 0x102; | ||
28 | private const UInt32 INFINITE = 0xFFFFFFFF; | ||
29 | |||
30 | #endregion | ||
31 | |||
32 | #region WaitAll and WaitAny | ||
33 | |||
34 | internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) | ||
35 | { | ||
36 | return waitHandle.WaitOne(millisecondsTimeout, exitContext); | ||
37 | } | ||
38 | |||
39 | private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles) | ||
40 | { | ||
41 | IntPtr[] nativeHandles = new IntPtr[waitHandles.Length]; | ||
42 | for (int i = 0; i < waitHandles.Length; i++) | ||
43 | { | ||
44 | nativeHandles[i] = waitHandles[i].Handle; | ||
45 | } | ||
46 | return nativeHandles; | ||
47 | } | ||
48 | |||
49 | public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) | ||
50 | { | ||
51 | uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; | ||
52 | |||
53 | IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); | ||
54 | |||
55 | int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout); | ||
56 | |||
57 | if (result == WAIT_TIMEOUT || result == WAIT_FAILED) | ||
58 | { | ||
59 | return false; | ||
60 | } | ||
61 | |||
62 | return true; | ||
63 | } | ||
64 | |||
65 | |||
66 | public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) | ||
67 | { | ||
68 | uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; | ||
69 | |||
70 | IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); | ||
71 | |||
72 | int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout); | ||
73 | |||
74 | if (result >= 0 && result < waitHandles.Length) | ||
75 | { | ||
76 | return result; | ||
77 | } | ||
78 | |||
79 | return -1; | ||
80 | } | ||
81 | |||
82 | public static int WaitAny(WaitHandle[] waitHandles) | ||
83 | { | ||
84 | return WaitAny(waitHandles, Timeout.Infinite, false); | ||
85 | } | ||
86 | |||
87 | public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) | ||
88 | { | ||
89 | int millisecondsTimeout = (int)timeout.TotalMilliseconds; | ||
90 | |||
91 | return WaitAny(waitHandles, millisecondsTimeout, false); | ||
92 | } | ||
93 | |||
94 | #endregion | ||
95 | |||
96 | #region External methods | ||
97 | |||
98 | [DllImport("coredll.dll", SetLastError = true)] | ||
99 | public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds); | ||
100 | |||
101 | #endregion | ||
102 | } | ||
103 | } | ||
104 | #endif \ No newline at end of file | ||
diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs new file mode 100644 index 0000000..ece24de --- /dev/null +++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs | |||
@@ -0,0 +1,82 @@ | |||
1 | using System.Threading; | ||
2 | |||
3 | #if (_WINDOWS_CE) | ||
4 | using System; | ||
5 | using System.Runtime.InteropServices; | ||
6 | #endif | ||
7 | |||
8 | namespace Amib.Threading.Internal | ||
9 | { | ||
10 | /// <summary> | ||
11 | /// EventWaitHandleFactory class. | ||
12 | /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. | ||
13 | /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property | ||
14 | /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. | ||
15 | /// Consequently this class creates the needed XxxResetEvent and replaces the handle if | ||
16 | /// it's a WindowsCE OS. | ||
17 | /// </summary> | ||
18 | public static class EventWaitHandleFactory | ||
19 | { | ||
20 | /// <summary> | ||
21 | /// Create a new AutoResetEvent object | ||
22 | /// </summary> | ||
23 | /// <returns>Return a new AutoResetEvent object</returns> | ||
24 | public static AutoResetEvent CreateAutoResetEvent() | ||
25 | { | ||
26 | AutoResetEvent waitHandle = new AutoResetEvent(false); | ||
27 | |||
28 | #if (_WINDOWS_CE) | ||
29 | ReplaceEventHandle(waitHandle, false, false); | ||
30 | #endif | ||
31 | |||
32 | return waitHandle; | ||
33 | } | ||
34 | |||
35 | /// <summary> | ||
36 | /// Create a new ManualResetEvent object | ||
37 | /// </summary> | ||
38 | /// <returns>Return a new ManualResetEvent object</returns> | ||
39 | public static ManualResetEvent CreateManualResetEvent(bool initialState) | ||
40 | { | ||
41 | ManualResetEvent waitHandle = new ManualResetEvent(initialState); | ||
42 | |||
43 | #if (_WINDOWS_CE) | ||
44 | ReplaceEventHandle(waitHandle, true, initialState); | ||
45 | #endif | ||
46 | |||
47 | return waitHandle; | ||
48 | } | ||
49 | |||
50 | #if (_WINDOWS_CE) | ||
51 | |||
52 | /// <summary> | ||
53 | /// Replace the event handle | ||
54 | /// </summary> | ||
55 | /// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param> | ||
56 | /// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param> | ||
57 | /// <param name="initialState">The initial state of the event</param> | ||
58 | private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState) | ||
59 | { | ||
60 | // Store the old handle | ||
61 | IntPtr oldHandle = waitHandle.Handle; | ||
62 | |||
63 | // Create a new event | ||
64 | IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null); | ||
65 | |||
66 | // Replace the old event with the new event | ||
67 | waitHandle.Handle = newHandle; | ||
68 | |||
69 | // Close the old event | ||
70 | CloseHandle (oldHandle); | ||
71 | } | ||
72 | |||
73 | [DllImport("coredll.dll", SetLastError = true)] | ||
74 | public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); | ||
75 | |||
76 | //Handle | ||
77 | [DllImport("coredll.dll", SetLastError = true)] | ||
78 | public static extern bool CloseHandle(IntPtr hObject); | ||
79 | #endif | ||
80 | |||
81 | } | ||
82 | } | ||
diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs new file mode 100644 index 0000000..6c6a88b --- /dev/null +++ b/ThirdParty/SmartThreadPool/Exceptions.cs | |||
@@ -0,0 +1,111 @@ | |||
1 | using System; | ||
2 | #if !(_WINDOWS_CE) | ||
3 | using System.Runtime.Serialization; | ||
4 | #endif | ||
5 | |||
6 | namespace Amib.Threading | ||
7 | { | ||
8 | #region Exceptions | ||
9 | |||
10 | /// <summary> | ||
11 | /// Represents an exception in case IWorkItemResult.GetResult has been canceled | ||
12 | /// </summary> | ||
13 | public sealed partial class WorkItemCancelException : Exception | ||
14 | { | ||
15 | public WorkItemCancelException() | ||
16 | { | ||
17 | } | ||
18 | |||
19 | public WorkItemCancelException(string message) | ||
20 | : base(message) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | public WorkItemCancelException(string message, Exception e) | ||
25 | : base(message, e) | ||
26 | { | ||
27 | } | ||
28 | } | ||
29 | |||
30 | /// <summary> | ||
31 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out | ||
32 | /// </summary> | ||
33 | public sealed partial class WorkItemTimeoutException : Exception | ||
34 | { | ||
35 | public WorkItemTimeoutException() | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public WorkItemTimeoutException(string message) | ||
40 | : base(message) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | public WorkItemTimeoutException(string message, Exception e) | ||
45 | : base(message, e) | ||
46 | { | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /// <summary> | ||
51 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out | ||
52 | /// </summary> | ||
53 | public sealed partial class WorkItemResultException : Exception | ||
54 | { | ||
55 | public WorkItemResultException() | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public WorkItemResultException(string message) | ||
60 | : base(message) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | public WorkItemResultException(string message, Exception e) | ||
65 | : base(message, e) | ||
66 | { | ||
67 | } | ||
68 | } | ||
69 | |||
70 | |||
71 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
72 | /// <summary> | ||
73 | /// Represents an exception in case IWorkItemResult.GetResult has been canceled | ||
74 | /// </summary> | ||
75 | [Serializable] | ||
76 | public sealed partial class WorkItemCancelException | ||
77 | { | ||
78 | public WorkItemCancelException(SerializationInfo si, StreamingContext sc) | ||
79 | : base(si, sc) | ||
80 | { | ||
81 | } | ||
82 | } | ||
83 | |||
84 | /// <summary> | ||
85 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out | ||
86 | /// </summary> | ||
87 | [Serializable] | ||
88 | public sealed partial class WorkItemTimeoutException | ||
89 | { | ||
90 | public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) | ||
91 | : base(si, sc) | ||
92 | { | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /// <summary> | ||
97 | /// Represents an exception in case IWorkItemResult.GetResult has been timed out | ||
98 | /// </summary> | ||
99 | [Serializable] | ||
100 | public sealed partial class WorkItemResultException | ||
101 | { | ||
102 | public WorkItemResultException(SerializationInfo si, StreamingContext sc) | ||
103 | : base(si, sc) | ||
104 | { | ||
105 | } | ||
106 | } | ||
107 | |||
108 | #endif | ||
109 | |||
110 | #endregion | ||
111 | } | ||
diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs new file mode 100644 index 0000000..8cc23a0 --- /dev/null +++ b/ThirdParty/SmartThreadPool/Interfaces.cs | |||
@@ -0,0 +1,628 @@ | |||
1 | using System; | ||
2 | using System.Threading; | ||
3 | |||
4 | namespace Amib.Threading | ||
5 | { | ||
6 | #region Delegates | ||
7 | |||
8 | /// <summary> | ||
9 | /// A delegate that represents the method to run as the work item | ||
10 | /// </summary> | ||
11 | /// <param name="state">A state object for the method to run</param> | ||
12 | public delegate object WorkItemCallback(object state); | ||
13 | |||
14 | /// <summary> | ||
15 | /// A delegate to call after the WorkItemCallback completed | ||
16 | /// </summary> | ||
17 | /// <param name="wir">The work item result object</param> | ||
18 | public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); | ||
19 | |||
20 | /// <summary> | ||
21 | /// A delegate to call after the WorkItemCallback completed | ||
22 | /// </summary> | ||
23 | /// <param name="wir">The work item result object</param> | ||
24 | public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir); | ||
25 | |||
26 | /// <summary> | ||
27 | /// A delegate to call when a WorkItemsGroup becomes idle | ||
28 | /// </summary> | ||
29 | /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param> | ||
30 | public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); | ||
31 | |||
32 | /// <summary> | ||
33 | /// A delegate to call after a thread is created, but before | ||
34 | /// it's first use. | ||
35 | /// </summary> | ||
36 | public delegate void ThreadInitializationHandler(); | ||
37 | |||
38 | /// <summary> | ||
39 | /// A delegate to call when a thread is about to exit, after | ||
40 | /// it is no longer belong to the pool. | ||
41 | /// </summary> | ||
42 | public delegate void ThreadTerminationHandler(); | ||
43 | |||
44 | #endregion | ||
45 | |||
46 | #region WorkItem Priority | ||
47 | |||
48 | /// <summary> | ||
49 | /// Defines the availeable priorities of a work item. | ||
50 | /// The higher the priority a work item has, the sooner | ||
51 | /// it will be executed. | ||
52 | /// </summary> | ||
53 | public enum WorkItemPriority | ||
54 | { | ||
55 | Lowest, | ||
56 | BelowNormal, | ||
57 | Normal, | ||
58 | AboveNormal, | ||
59 | Highest, | ||
60 | } | ||
61 | |||
62 | #endregion | ||
63 | |||
64 | #region IWorkItemsGroup interface | ||
65 | |||
66 | /// <summary> | ||
67 | /// IWorkItemsGroup interface | ||
68 | /// Created by SmartThreadPool.CreateWorkItemsGroup() | ||
69 | /// </summary> | ||
70 | public interface IWorkItemsGroup | ||
71 | { | ||
72 | /// <summary> | ||
73 | /// Get/Set the name of the WorkItemsGroup | ||
74 | /// </summary> | ||
75 | string Name { get; set; } | ||
76 | |||
77 | /// <summary> | ||
78 | /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool | ||
79 | /// </summary> | ||
80 | int Concurrency { get; set; } | ||
81 | |||
82 | /// <summary> | ||
83 | /// Get the number of work items waiting in the queue. | ||
84 | /// </summary> | ||
85 | int WaitingCallbacks { get; } | ||
86 | |||
87 | /// <summary> | ||
88 | /// Get an array with all the state objects of the currently running items. | ||
89 | /// The array represents a snap shot and impact performance. | ||
90 | /// </summary> | ||
91 | object[] GetStates(); | ||
92 | |||
93 | /// <summary> | ||
94 | /// Get the WorkItemsGroup start information | ||
95 | /// </summary> | ||
96 | WIGStartInfo WIGStartInfo { get; } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Starts to execute work items | ||
100 | /// </summary> | ||
101 | void Start(); | ||
102 | |||
103 | /// <summary> | ||
104 | /// Cancel all the work items. | ||
105 | /// Same as Cancel(false) | ||
106 | /// </summary> | ||
107 | void Cancel(); | ||
108 | |||
109 | /// <summary> | ||
110 | /// Cancel all work items using thread abortion | ||
111 | /// </summary> | ||
112 | /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param> | ||
113 | void Cancel(bool abortExecution); | ||
114 | |||
115 | /// <summary> | ||
116 | /// Wait for all work item to complete. | ||
117 | /// </summary> | ||
118 | void WaitForIdle(); | ||
119 | |||
120 | /// <summary> | ||
121 | /// Wait for all work item to complete, until timeout expired | ||
122 | /// </summary> | ||
123 | /// <param name="timeout">How long to wait for the work items to complete</param> | ||
124 | /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns> | ||
125 | bool WaitForIdle(TimeSpan timeout); | ||
126 | |||
127 | /// <summary> | ||
128 | /// Wait for all work item to complete, until timeout expired | ||
129 | /// </summary> | ||
130 | /// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param> | ||
131 | /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns> | ||
132 | bool WaitForIdle(int millisecondsTimeout); | ||
133 | |||
134 | /// <summary> | ||
135 | /// IsIdle is true when there are no work items running or queued. | ||
136 | /// </summary> | ||
137 | bool IsIdle { get; } | ||
138 | |||
139 | /// <summary> | ||
140 | /// This event is fired when all work items are completed. | ||
141 | /// (When IsIdle changes to true) | ||
142 | /// This event only work on WorkItemsGroup. On SmartThreadPool | ||
143 | /// it throws the NotImplementedException. | ||
144 | /// </summary> | ||
145 | event WorkItemsGroupIdleHandler OnIdle; | ||
146 | |||
147 | #region QueueWorkItem | ||
148 | |||
149 | /// <summary> | ||
150 | /// Queue a work item | ||
151 | /// </summary> | ||
152 | /// <param name="callback">A callback to execute</param> | ||
153 | /// <returns>Returns a work item result</returns> | ||
154 | IWorkItemResult QueueWorkItem(WorkItemCallback callback); | ||
155 | |||
156 | /// <summary> | ||
157 | /// Queue a work item | ||
158 | /// </summary> | ||
159 | /// <param name="callback">A callback to execute</param> | ||
160 | /// <param name="workItemPriority">The priority of the work item</param> | ||
161 | /// <returns>Returns a work item result</returns> | ||
162 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); | ||
163 | |||
164 | /// <summary> | ||
165 | /// Queue a work item | ||
166 | /// </summary> | ||
167 | /// <param name="callback">A callback to execute</param> | ||
168 | /// <param name="state"> | ||
169 | /// The context object of the work item. Used for passing arguments to the work item. | ||
170 | /// </param> | ||
171 | /// <returns>Returns a work item result</returns> | ||
172 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); | ||
173 | |||
174 | /// <summary> | ||
175 | /// Queue a work item | ||
176 | /// </summary> | ||
177 | /// <param name="callback">A callback to execute</param> | ||
178 | /// <param name="state"> | ||
179 | /// The context object of the work item. Used for passing arguments to the work item. | ||
180 | /// </param> | ||
181 | /// <param name="workItemPriority">The work item priority</param> | ||
182 | /// <returns>Returns a work item result</returns> | ||
183 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); | ||
184 | |||
185 | /// <summary> | ||
186 | /// Queue a work item | ||
187 | /// </summary> | ||
188 | /// <param name="callback">A callback to execute</param> | ||
189 | /// <param name="state"> | ||
190 | /// The context object of the work item. Used for passing arguments to the work item. | ||
191 | /// </param> | ||
192 | /// <param name="postExecuteWorkItemCallback"> | ||
193 | /// A delegate to call after the callback completion | ||
194 | /// </param> | ||
195 | /// <returns>Returns a work item result</returns> | ||
196 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); | ||
197 | |||
198 | /// <summary> | ||
199 | /// Queue a work item | ||
200 | /// </summary> | ||
201 | /// <param name="callback">A callback to execute</param> | ||
202 | /// <param name="state"> | ||
203 | /// The context object of the work item. Used for passing arguments to the work item. | ||
204 | /// </param> | ||
205 | /// <param name="postExecuteWorkItemCallback"> | ||
206 | /// A delegate to call after the callback completion | ||
207 | /// </param> | ||
208 | /// <param name="workItemPriority">The work item priority</param> | ||
209 | /// <returns>Returns a work item result</returns> | ||
210 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); | ||
211 | |||
212 | /// <summary> | ||
213 | /// Queue a work item | ||
214 | /// </summary> | ||
215 | /// <param name="callback">A callback to execute</param> | ||
216 | /// <param name="state"> | ||
217 | /// The context object of the work item. Used for passing arguments to the work item. | ||
218 | /// </param> | ||
219 | /// <param name="postExecuteWorkItemCallback"> | ||
220 | /// A delegate to call after the callback completion | ||
221 | /// </param> | ||
222 | /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> | ||
223 | /// <returns>Returns a work item result</returns> | ||
224 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); | ||
225 | |||
226 | /// <summary> | ||
227 | /// Queue a work item | ||
228 | /// </summary> | ||
229 | /// <param name="callback">A callback to execute</param> | ||
230 | /// <param name="state"> | ||
231 | /// The context object of the work item. Used for passing arguments to the work item. | ||
232 | /// </param> | ||
233 | /// <param name="postExecuteWorkItemCallback"> | ||
234 | /// A delegate to call after the callback completion | ||
235 | /// </param> | ||
236 | /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> | ||
237 | /// <param name="workItemPriority">The work item priority</param> | ||
238 | /// <returns>Returns a work item result</returns> | ||
239 | IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); | ||
240 | |||
241 | /// <summary> | ||
242 | /// Queue a work item | ||
243 | /// </summary> | ||
244 | /// <param name="workItemInfo">Work item info</param> | ||
245 | /// <param name="callback">A callback to execute</param> | ||
246 | /// <returns>Returns a work item result</returns> | ||
247 | IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); | ||
248 | |||
249 | /// <summary> | ||
250 | /// Queue a work item | ||
251 | /// </summary> | ||
252 | /// <param name="workItemInfo">Work item information</param> | ||
253 | /// <param name="callback">A callback to execute</param> | ||
254 | /// <param name="state"> | ||
255 | /// The context object of the work item. Used for passing arguments to the work item. | ||
256 | /// </param> | ||
257 | /// <returns>Returns a work item result</returns> | ||
258 | IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); | ||
259 | |||
260 | #endregion | ||
261 | |||
262 | #region QueueWorkItem(Action<...>) | ||
263 | |||
264 | /// <summary> | ||
265 | /// Queue a work item. | ||
266 | /// </summary> | ||
267 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
268 | IWorkItemResult QueueWorkItem(Action action); | ||
269 | |||
270 | /// <summary> | ||
271 | /// Queue a work item. | ||
272 | /// </summary> | ||
273 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
274 | IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority); | ||
275 | |||
276 | /// <summary> | ||
277 | /// Queue a work item. | ||
278 | /// </summary> | ||
279 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
280 | IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority); | ||
281 | |||
282 | /// <summary> | ||
283 | /// Queue a work item. | ||
284 | /// </summary> | ||
285 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
286 | IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg); | ||
287 | |||
288 | /// <summary> | ||
289 | /// Queue a work item. | ||
290 | /// </summary> | ||
291 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
292 | IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2); | ||
293 | |||
294 | /// <summary> | ||
295 | /// Queue a work item. | ||
296 | /// </summary> | ||
297 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
298 | IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority); | ||
299 | |||
300 | /// <summary> | ||
301 | /// Queue a work item. | ||
302 | /// </summary> | ||
303 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
304 | IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3); | ||
305 | |||
306 | /// <summary> | ||
307 | /// Queue a work item. | ||
308 | /// </summary> | ||
309 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
310 | IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority); | ||
311 | |||
312 | /// <summary> | ||
313 | /// Queue a work item. | ||
314 | /// </summary> | ||
315 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
316 | IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4); | ||
317 | |||
318 | /// <summary> | ||
319 | /// Queue a work item. | ||
320 | /// </summary> | ||
321 | /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns> | ||
322 | IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority); | ||
323 | |||
324 | #endregion | ||
325 | |||
326 | #region QueueWorkItem(Func<...>) | ||
327 | |||
328 | /// <summary> | ||
329 | /// Queue a work item. | ||
330 | /// </summary> | ||
331 | /// <returns>Returns a IWorkItemResult<TResult> object. | ||
332 | /// its GetResult() returns a TResult object</returns> | ||
333 | IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func); | ||
334 | |||
335 | /// <summary> | ||
336 | /// Queue a work item. | ||
337 | /// </summary> | ||
338 | /// <returns>Returns a IWorkItemResult<TResult> object. | ||
339 | /// its GetResult() returns a TResult object</returns> | ||
340 | IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg); | ||
341 | |||
342 | /// <summary> | ||
343 | /// Queue a work item. | ||
344 | /// </summary> | ||
345 | /// <returns>Returns a IWorkItemResult<TResult> object. | ||
346 | /// its GetResult() returns a TResult object</returns> | ||
347 | IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2); | ||
348 | |||
349 | /// <summary> | ||
350 | /// Queue a work item. | ||
351 | /// </summary> | ||
352 | /// <returns>Returns a IWorkItemResult<TResult> object. | ||
353 | /// its GetResult() returns a TResult object</returns> | ||
354 | IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3); | ||
355 | |||
356 | /// <summary> | ||
357 | /// Queue a work item. | ||
358 | /// </summary> | ||
359 | /// <returns>Returns a IWorkItemResult<TResult> object. | ||
360 | /// its GetResult() returns a TResult object</returns> | ||
361 | IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4); | ||
362 | |||
363 | #endregion | ||
364 | } | ||
365 | |||
366 | #endregion | ||
367 | |||
368 | #region CallToPostExecute enumerator | ||
369 | |||
370 | [Flags] | ||
371 | public enum CallToPostExecute | ||
372 | { | ||
373 | /// <summary> | ||
374 | /// Never call to the PostExecute call back | ||
375 | /// </summary> | ||
376 | Never = 0x00, | ||
377 | |||
378 | /// <summary> | ||
379 | /// Call to the PostExecute only when the work item is cancelled | ||
380 | /// </summary> | ||
381 | WhenWorkItemCanceled = 0x01, | ||
382 | |||
383 | /// <summary> | ||
384 | /// Call to the PostExecute only when the work item is not cancelled | ||
385 | /// </summary> | ||
386 | WhenWorkItemNotCanceled = 0x02, | ||
387 | |||
388 | /// <summary> | ||
389 | /// Always call to the PostExecute | ||
390 | /// </summary> | ||
391 | Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, | ||
392 | } | ||
393 | |||
394 | #endregion | ||
395 | |||
396 | #region IWorkItemResult interface | ||
397 | |||
398 | /// <summary> | ||
399 | /// The common interface of IWorkItemResult and IWorkItemResult<T> | ||
400 | /// </summary> | ||
401 | public interface IWaitableResult | ||
402 | { | ||
403 | /// <summary> | ||
404 | /// This method intent is for internal use. | ||
405 | /// </summary> | ||
406 | /// <returns></returns> | ||
407 | IWorkItemResult GetWorkItemResult(); | ||
408 | |||
409 | /// <summary> | ||
410 | /// This method intent is for internal use. | ||
411 | /// </summary> | ||
412 | /// <returns></returns> | ||
413 | IWorkItemResult<TResult> GetWorkItemResultT<TResult>(); | ||
414 | } | ||
415 | |||
416 | /// <summary> | ||
417 | /// IWorkItemResult interface. | ||
418 | /// Created when a WorkItemCallback work item is queued. | ||
419 | /// </summary> | ||
420 | public interface IWorkItemResult : IWorkItemResult<object> | ||
421 | { | ||
422 | } | ||
423 | |||
424 | /// <summary> | ||
425 | /// IWorkItemResult<TResult> interface. | ||
426 | /// Created when a Func<TResult> work item is queued. | ||
427 | /// </summary> | ||
428 | public interface IWorkItemResult<TResult> : IWaitableResult | ||
429 | { | ||
430 | /// <summary> | ||
431 | /// Get the result of the work item. | ||
432 | /// If the work item didn't run yet then the caller waits. | ||
433 | /// </summary> | ||
434 | /// <returns>The result of the work item</returns> | ||
435 | TResult GetResult(); | ||
436 | |||
437 | /// <summary> | ||
438 | /// Get the result of the work item. | ||
439 | /// If the work item didn't run yet then the caller waits until timeout. | ||
440 | /// </summary> | ||
441 | /// <returns>The result of the work item</returns> | ||
442 | /// On timeout throws WorkItemTimeoutException | ||
443 | TResult GetResult( | ||
444 | int millisecondsTimeout, | ||
445 | bool exitContext); | ||
446 | |||
447 | /// <summary> | ||
448 | /// Get the result of the work item. | ||
449 | /// If the work item didn't run yet then the caller waits until timeout. | ||
450 | /// </summary> | ||
451 | /// <returns>The result of the work item</returns> | ||
452 | /// On timeout throws WorkItemTimeoutException | ||
453 | TResult GetResult( | ||
454 | TimeSpan timeout, | ||
455 | bool exitContext); | ||
456 | |||
457 | /// <summary> | ||
458 | /// Get the result of the work item. | ||
459 | /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. | ||
460 | /// </summary> | ||
461 | /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> | ||
462 | /// <param name="exitContext"> | ||
463 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
464 | /// </param> | ||
465 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param> | ||
466 | /// <returns>The result of the work item</returns> | ||
467 | /// On timeout throws WorkItemTimeoutException | ||
468 | /// On cancel throws WorkItemCancelException | ||
469 | TResult GetResult( | ||
470 | int millisecondsTimeout, | ||
471 | bool exitContext, | ||
472 | WaitHandle cancelWaitHandle); | ||
473 | |||
474 | /// <summary> | ||
475 | /// Get the result of the work item. | ||
476 | /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. | ||
477 | /// </summary> | ||
478 | /// <returns>The result of the work item</returns> | ||
479 | /// On timeout throws WorkItemTimeoutException | ||
480 | /// On cancel throws WorkItemCancelException | ||
481 | TResult GetResult( | ||
482 | TimeSpan timeout, | ||
483 | bool exitContext, | ||
484 | WaitHandle cancelWaitHandle); | ||
485 | |||
486 | /// <summary> | ||
487 | /// Get the result of the work item. | ||
488 | /// If the work item didn't run yet then the caller waits. | ||
489 | /// </summary> | ||
490 | /// <param name="e">Filled with the exception if one was thrown</param> | ||
491 | /// <returns>The result of the work item</returns> | ||
492 | TResult GetResult(out Exception e); | ||
493 | |||
494 | /// <summary> | ||
495 | /// Get the result of the work item. | ||
496 | /// If the work item didn't run yet then the caller waits until timeout. | ||
497 | /// </summary> | ||
498 | /// <param name="millisecondsTimeout"></param> | ||
499 | /// <param name="exitContext"></param> | ||
500 | /// <param name="e">Filled with the exception if one was thrown</param> | ||
501 | /// <returns>The result of the work item</returns> | ||
502 | /// On timeout throws WorkItemTimeoutException | ||
503 | TResult GetResult( | ||
504 | int millisecondsTimeout, | ||
505 | bool exitContext, | ||
506 | out Exception e); | ||
507 | |||
508 | /// <summary> | ||
509 | /// Get the result of the work item. | ||
510 | /// If the work item didn't run yet then the caller waits until timeout. | ||
511 | /// </summary> | ||
512 | /// <param name="exitContext"></param> | ||
513 | /// <param name="e">Filled with the exception if one was thrown</param> | ||
514 | /// <param name="timeout"></param> | ||
515 | /// <returns>The result of the work item</returns> | ||
516 | /// On timeout throws WorkItemTimeoutException | ||
517 | TResult GetResult( | ||
518 | TimeSpan timeout, | ||
519 | bool exitContext, | ||
520 | out Exception e); | ||
521 | |||
522 | /// <summary> | ||
523 | /// Get the result of the work item. | ||
524 | /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. | ||
525 | /// </summary> | ||
526 | /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> | ||
527 | /// <param name="exitContext"> | ||
528 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
529 | /// </param> | ||
530 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param> | ||
531 | /// <param name="e">Filled with the exception if one was thrown</param> | ||
532 | /// <returns>The result of the work item</returns> | ||
533 | /// On timeout throws WorkItemTimeoutException | ||
534 | /// On cancel throws WorkItemCancelException | ||
535 | TResult GetResult( | ||
536 | int millisecondsTimeout, | ||
537 | bool exitContext, | ||
538 | WaitHandle cancelWaitHandle, | ||
539 | out Exception e); | ||
540 | |||
541 | /// <summary> | ||
542 | /// Get the result of the work item. | ||
543 | /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. | ||
544 | /// </summary> | ||
545 | /// <returns>The result of the work item</returns> | ||
546 | /// <param name="cancelWaitHandle"></param> | ||
547 | /// <param name="e">Filled with the exception if one was thrown</param> | ||
548 | /// <param name="timeout"></param> | ||
549 | /// <param name="exitContext"></param> | ||
550 | /// On timeout throws WorkItemTimeoutException | ||
551 | /// On cancel throws WorkItemCancelException | ||
552 | TResult GetResult( | ||
553 | TimeSpan timeout, | ||
554 | bool exitContext, | ||
555 | WaitHandle cancelWaitHandle, | ||
556 | out Exception e); | ||
557 | |||
558 | /// <summary> | ||
559 | /// Gets an indication whether the asynchronous operation has completed. | ||
560 | /// </summary> | ||
561 | bool IsCompleted { get; } | ||
562 | |||
563 | /// <summary> | ||
564 | /// Gets an indication whether the asynchronous operation has been canceled. | ||
565 | /// </summary> | ||
566 | bool IsCanceled { get; } | ||
567 | |||
568 | /// <summary> | ||
569 | /// Gets the user-defined object that contains context data | ||
570 | /// for the work item method. | ||
571 | /// </summary> | ||
572 | object State { get; } | ||
573 | |||
574 | /// <summary> | ||
575 | /// Same as Cancel(false). | ||
576 | /// </summary> | ||
577 | bool Cancel(); | ||
578 | |||
579 | /// <summary> | ||
580 | /// Cancel the work item execution. | ||
581 | /// If the work item is in the queue then it won't execute | ||
582 | /// If the work item is completed, it will remain completed | ||
583 | /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled | ||
584 | /// property to check if the work item has been cancelled. If the abortExecution is set to true then | ||
585 | /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution | ||
586 | /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException. | ||
587 | /// If the work item is already cancelled it will remain cancelled | ||
588 | /// </summary> | ||
589 | /// <param name="abortExecution">When true send an AbortException to the executing thread.</param> | ||
590 | /// <returns>Returns true if the work item was not completed, otherwise false.</returns> | ||
591 | bool Cancel(bool abortExecution); | ||
592 | |||
593 | /// <summary> | ||
594 | /// Get the work item's priority | ||
595 | /// </summary> | ||
596 | WorkItemPriority WorkItemPriority { get; } | ||
597 | |||
598 | /// <summary> | ||
599 | /// Return the result, same as GetResult() | ||
600 | /// </summary> | ||
601 | TResult Result { get; } | ||
602 | |||
603 | /// <summary> | ||
604 | /// Returns the exception if occured otherwise returns null. | ||
605 | /// </summary> | ||
606 | object Exception { get; } | ||
607 | } | ||
608 | |||
609 | #endregion | ||
610 | |||
611 | #region .NET 3.5 | ||
612 | |||
613 | // All these delegate are built-in .NET 3.5 | ||
614 | // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity. | ||
615 | |||
616 | public delegate void Action(); | ||
617 | public delegate void Action<T1, T2>(T1 arg1, T2 arg2); | ||
618 | public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3); | ||
619 | public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4); | ||
620 | |||
621 | public delegate TResult Func<TResult>(); | ||
622 | public delegate TResult Func<T, TResult>(T arg1); | ||
623 | public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2); | ||
624 | public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3); | ||
625 | public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4); | ||
626 | |||
627 | #endregion | ||
628 | } | ||
diff --git a/ThirdParty/SmartThreadPool/InternalInterfaces.cs b/ThirdParty/SmartThreadPool/InternalInterfaces.cs new file mode 100644 index 0000000..3055117 --- /dev/null +++ b/ThirdParty/SmartThreadPool/InternalInterfaces.cs | |||
@@ -0,0 +1,27 @@ | |||
1 | |||
2 | namespace Amib.Threading.Internal | ||
3 | { | ||
4 | /// <summary> | ||
5 | /// An internal delegate to call when the WorkItem starts or completes | ||
6 | /// </summary> | ||
7 | internal delegate void WorkItemStateCallback(WorkItem workItem); | ||
8 | |||
9 | internal interface IInternalWorkItemResult | ||
10 | { | ||
11 | event WorkItemStateCallback OnWorkItemStarted; | ||
12 | event WorkItemStateCallback OnWorkItemCompleted; | ||
13 | } | ||
14 | |||
15 | internal interface IInternalWaitableResult | ||
16 | { | ||
17 | /// <summary> | ||
18 | /// This method is intent for internal use. | ||
19 | /// </summary> | ||
20 | IWorkItemResult GetWorkItemResult(); | ||
21 | } | ||
22 | |||
23 | public interface IHasWorkItemPriority | ||
24 | { | ||
25 | WorkItemPriority WorkItemPriority { get; } | ||
26 | } | ||
27 | } | ||
diff --git a/ThirdParty/SmartThreadPool/PriorityQueue.cs b/ThirdParty/SmartThreadPool/PriorityQueue.cs new file mode 100644 index 0000000..3ea6084 --- /dev/null +++ b/ThirdParty/SmartThreadPool/PriorityQueue.cs | |||
@@ -0,0 +1,239 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | using System.Diagnostics; | ||
5 | |||
6 | namespace Amib.Threading.Internal | ||
7 | { | ||
8 | #region PriorityQueue class | ||
9 | |||
10 | /// <summary> | ||
11 | /// PriorityQueue class | ||
12 | /// This class is not thread safe because we use external lock | ||
13 | /// </summary> | ||
14 | public sealed class PriorityQueue : IEnumerable | ||
15 | { | ||
16 | #region Private members | ||
17 | |||
18 | /// <summary> | ||
19 | /// The number of queues, there is one for each type of priority | ||
20 | /// </summary> | ||
21 | private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; | ||
22 | |||
23 | /// <summary> | ||
24 | /// Work items queues. There is one for each type of priority | ||
25 | /// </summary> | ||
26 | private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount]; | ||
27 | |||
28 | /// <summary> | ||
29 | /// The total number of work items within the queues | ||
30 | /// </summary> | ||
31 | private int _workItemsCount; | ||
32 | |||
33 | /// <summary> | ||
34 | /// Use with IEnumerable interface | ||
35 | /// </summary> | ||
36 | private int _version; | ||
37 | |||
38 | #endregion | ||
39 | |||
40 | #region Contructor | ||
41 | |||
42 | public PriorityQueue() | ||
43 | { | ||
44 | for(int i = 0; i < _queues.Length; ++i) | ||
45 | { | ||
46 | _queues[i] = new LinkedList<IHasWorkItemPriority>(); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | #endregion | ||
51 | |||
52 | #region Methods | ||
53 | |||
54 | /// <summary> | ||
55 | /// Enqueue a work item. | ||
56 | /// </summary> | ||
57 | /// <param name="workItem">A work item</param> | ||
58 | public void Enqueue(IHasWorkItemPriority workItem) | ||
59 | { | ||
60 | Debug.Assert(null != workItem); | ||
61 | |||
62 | int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; | ||
63 | Debug.Assert(queueIndex >= 0); | ||
64 | Debug.Assert(queueIndex < _queuesCount); | ||
65 | |||
66 | _queues[queueIndex].AddLast(workItem); | ||
67 | ++_workItemsCount; | ||
68 | ++_version; | ||
69 | } | ||
70 | |||
71 | /// <summary> | ||
72 | /// Dequeque a work item. | ||
73 | /// </summary> | ||
74 | /// <returns>Returns the next work item</returns> | ||
75 | public IHasWorkItemPriority Dequeue() | ||
76 | { | ||
77 | IHasWorkItemPriority workItem = null; | ||
78 | |||
79 | if(_workItemsCount > 0) | ||
80 | { | ||
81 | int queueIndex = GetNextNonEmptyQueue(-1); | ||
82 | Debug.Assert(queueIndex >= 0); | ||
83 | workItem = _queues[queueIndex].First.Value; | ||
84 | _queues[queueIndex].RemoveFirst(); | ||
85 | Debug.Assert(null != workItem); | ||
86 | --_workItemsCount; | ||
87 | ++_version; | ||
88 | } | ||
89 | |||
90 | return workItem; | ||
91 | } | ||
92 | |||
93 | /// <summary> | ||
94 | /// Find the next non empty queue starting at queue queueIndex+1 | ||
95 | /// </summary> | ||
96 | /// <param name="queueIndex">The index-1 to start from</param> | ||
97 | /// <returns> | ||
98 | /// The index of the next non empty queue or -1 if all the queues are empty | ||
99 | /// </returns> | ||
100 | private int GetNextNonEmptyQueue(int queueIndex) | ||
101 | { | ||
102 | for(int i = queueIndex+1; i < _queuesCount; ++i) | ||
103 | { | ||
104 | if(_queues[i].Count > 0) | ||
105 | { | ||
106 | return i; | ||
107 | } | ||
108 | } | ||
109 | return -1; | ||
110 | } | ||
111 | |||
112 | /// <summary> | ||
113 | /// The number of work items | ||
114 | /// </summary> | ||
115 | public int Count | ||
116 | { | ||
117 | get | ||
118 | { | ||
119 | return _workItemsCount; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /// <summary> | ||
124 | /// Clear all the work items | ||
125 | /// </summary> | ||
126 | public void Clear() | ||
127 | { | ||
128 | if (_workItemsCount > 0) | ||
129 | { | ||
130 | foreach(LinkedList<IHasWorkItemPriority> queue in _queues) | ||
131 | { | ||
132 | queue.Clear(); | ||
133 | } | ||
134 | _workItemsCount = 0; | ||
135 | ++_version; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | #endregion | ||
140 | |||
141 | #region IEnumerable Members | ||
142 | |||
143 | /// <summary> | ||
144 | /// Returns an enumerator to iterate over the work items | ||
145 | /// </summary> | ||
146 | /// <returns>Returns an enumerator</returns> | ||
147 | public IEnumerator GetEnumerator() | ||
148 | { | ||
149 | return new PriorityQueueEnumerator(this); | ||
150 | } | ||
151 | |||
152 | #endregion | ||
153 | |||
154 | #region PriorityQueueEnumerator | ||
155 | |||
156 | /// <summary> | ||
157 | /// The class the implements the enumerator | ||
158 | /// </summary> | ||
159 | private class PriorityQueueEnumerator : IEnumerator | ||
160 | { | ||
161 | private readonly PriorityQueue _priorityQueue; | ||
162 | private int _version; | ||
163 | private int _queueIndex; | ||
164 | private IEnumerator _enumerator; | ||
165 | |||
166 | public PriorityQueueEnumerator(PriorityQueue priorityQueue) | ||
167 | { | ||
168 | _priorityQueue = priorityQueue; | ||
169 | _version = _priorityQueue._version; | ||
170 | _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); | ||
171 | if (_queueIndex >= 0) | ||
172 | { | ||
173 | _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | _enumerator = null; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | #region IEnumerator Members | ||
182 | |||
183 | public void Reset() | ||
184 | { | ||
185 | _version = _priorityQueue._version; | ||
186 | _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); | ||
187 | if (_queueIndex >= 0) | ||
188 | { | ||
189 | _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | _enumerator = null; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | public object Current | ||
198 | { | ||
199 | get | ||
200 | { | ||
201 | Debug.Assert(null != _enumerator); | ||
202 | return _enumerator.Current; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | public bool MoveNext() | ||
207 | { | ||
208 | if (null == _enumerator) | ||
209 | { | ||
210 | return false; | ||
211 | } | ||
212 | |||
213 | if(_version != _priorityQueue._version) | ||
214 | { | ||
215 | throw new InvalidOperationException("The collection has been modified"); | ||
216 | |||
217 | } | ||
218 | if (!_enumerator.MoveNext()) | ||
219 | { | ||
220 | _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); | ||
221 | if(-1 == _queueIndex) | ||
222 | { | ||
223 | return false; | ||
224 | } | ||
225 | _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); | ||
226 | _enumerator.MoveNext(); | ||
227 | return true; | ||
228 | } | ||
229 | return true; | ||
230 | } | ||
231 | |||
232 | #endregion | ||
233 | } | ||
234 | |||
235 | #endregion | ||
236 | } | ||
237 | |||
238 | #endregion | ||
239 | } | ||
diff --git a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4728c1f --- /dev/null +++ b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs | |||
@@ -0,0 +1,23 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using System.Runtime.InteropServices; | ||
4 | |||
5 | [assembly: AssemblyTitle("Amib.Threading")] | ||
6 | [assembly: AssemblyDescription("Smart Thread Pool")] | ||
7 | [assembly: AssemblyConfiguration("")] | ||
8 | [assembly: AssemblyCompany("")] | ||
9 | [assembly: AssemblyProduct("Amib.Threading")] | ||
10 | [assembly: AssemblyCopyright("")] | ||
11 | [assembly: AssemblyTrademark("")] | ||
12 | [assembly: AssemblyCulture("")] | ||
13 | [assembly: ComVisible(false)] | ||
14 | [assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")] | ||
15 | [assembly: AssemblyVersion("2.2.3.0")] | ||
16 | |||
17 | #if (_PUBLISH) | ||
18 | [assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")] | ||
19 | #else | ||
20 | [assembly: InternalsVisibleTo("STPTests")] | ||
21 | #endif | ||
22 | |||
23 | |||
diff --git a/ThirdParty/SmartThreadPool/SLExt.cs b/ThirdParty/SmartThreadPool/SLExt.cs new file mode 100644 index 0000000..23a60bc --- /dev/null +++ b/ThirdParty/SmartThreadPool/SLExt.cs | |||
@@ -0,0 +1,16 @@ | |||
1 | #if _SILVERLIGHT | ||
2 | |||
3 | using System.Threading; | ||
4 | |||
5 | namespace Amib.Threading | ||
6 | { | ||
7 | public enum ThreadPriority | ||
8 | { | ||
9 | Lowest, | ||
10 | BelowNormal, | ||
11 | Normal, | ||
12 | AboveNormal, | ||
13 | Highest, | ||
14 | } | ||
15 | } | ||
16 | #endif | ||
diff --git a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs new file mode 100644 index 0000000..9b17f69 --- /dev/null +++ b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs | |||
@@ -0,0 +1,62 @@ | |||
1 | #if !(_WINDOWS_CE) | ||
2 | |||
3 | using System; | ||
4 | using System.Threading; | ||
5 | |||
6 | namespace Amib.Threading.Internal | ||
7 | { | ||
8 | #if _WINDOWS || WINDOWS_PHONE | ||
9 | internal static class STPEventWaitHandle | ||
10 | { | ||
11 | public const int WaitTimeout = Timeout.Infinite; | ||
12 | |||
13 | internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) | ||
14 | { | ||
15 | return WaitHandle.WaitAll(waitHandles, millisecondsTimeout); | ||
16 | } | ||
17 | |||
18 | internal static int WaitAny(WaitHandle[] waitHandles) | ||
19 | { | ||
20 | return WaitHandle.WaitAny(waitHandles); | ||
21 | } | ||
22 | |||
23 | internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) | ||
24 | { | ||
25 | return WaitHandle.WaitAny(waitHandles, millisecondsTimeout); | ||
26 | } | ||
27 | |||
28 | internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) | ||
29 | { | ||
30 | return waitHandle.WaitOne(millisecondsTimeout); | ||
31 | } | ||
32 | } | ||
33 | #else | ||
34 | internal static class STPEventWaitHandle | ||
35 | { | ||
36 | public const int WaitTimeout = Timeout.Infinite; | ||
37 | |||
38 | internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) | ||
39 | { | ||
40 | return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); | ||
41 | } | ||
42 | |||
43 | internal static int WaitAny(WaitHandle[] waitHandles) | ||
44 | { | ||
45 | return WaitHandle.WaitAny(waitHandles); | ||
46 | } | ||
47 | |||
48 | internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) | ||
49 | { | ||
50 | return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); | ||
51 | } | ||
52 | |||
53 | internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) | ||
54 | { | ||
55 | return waitHandle.WaitOne(millisecondsTimeout, exitContext); | ||
56 | } | ||
57 | } | ||
58 | #endif | ||
59 | |||
60 | } | ||
61 | |||
62 | #endif \ No newline at end of file | ||
diff --git a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs new file mode 100644 index 0000000..bd68499 --- /dev/null +++ b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs | |||
@@ -0,0 +1,448 @@ | |||
1 | using System; | ||
2 | using System.Diagnostics; | ||
3 | using System.Threading; | ||
4 | |||
5 | namespace Amib.Threading | ||
6 | { | ||
7 | public interface ISTPPerformanceCountersReader | ||
8 | { | ||
9 | long InUseThreads { get; } | ||
10 | long ActiveThreads { get; } | ||
11 | long WorkItemsQueued { get; } | ||
12 | long WorkItemsProcessed { get; } | ||
13 | } | ||
14 | } | ||
15 | |||
16 | namespace Amib.Threading.Internal | ||
17 | { | ||
18 | internal interface ISTPInstancePerformanceCounters : IDisposable | ||
19 | { | ||
20 | void Close(); | ||
21 | void SampleThreads(long activeThreads, long inUseThreads); | ||
22 | void SampleWorkItems(long workItemsQueued, long workItemsProcessed); | ||
23 | void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); | ||
24 | void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); | ||
25 | } | ||
26 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
27 | |||
28 | internal enum STPPerformanceCounterType | ||
29 | { | ||
30 | // Fields | ||
31 | ActiveThreads = 0, | ||
32 | InUseThreads = 1, | ||
33 | OverheadThreads = 2, | ||
34 | OverheadThreadsPercent = 3, | ||
35 | OverheadThreadsPercentBase = 4, | ||
36 | |||
37 | WorkItems = 5, | ||
38 | WorkItemsInQueue = 6, | ||
39 | WorkItemsProcessed = 7, | ||
40 | |||
41 | WorkItemsQueuedPerSecond = 8, | ||
42 | WorkItemsProcessedPerSecond = 9, | ||
43 | |||
44 | AvgWorkItemWaitTime = 10, | ||
45 | AvgWorkItemWaitTimeBase = 11, | ||
46 | |||
47 | AvgWorkItemProcessTime = 12, | ||
48 | AvgWorkItemProcessTimeBase = 13, | ||
49 | |||
50 | WorkItemsGroups = 14, | ||
51 | |||
52 | LastCounter = 14, | ||
53 | } | ||
54 | |||
55 | |||
56 | /// <summary> | ||
57 | /// Summary description for STPPerformanceCounter. | ||
58 | /// </summary> | ||
59 | internal class STPPerformanceCounter | ||
60 | { | ||
61 | // Fields | ||
62 | private readonly PerformanceCounterType _pcType; | ||
63 | protected string _counterHelp; | ||
64 | protected string _counterName; | ||
65 | |||
66 | // Methods | ||
67 | public STPPerformanceCounter( | ||
68 | string counterName, | ||
69 | string counterHelp, | ||
70 | PerformanceCounterType pcType) | ||
71 | { | ||
72 | _counterName = counterName; | ||
73 | _counterHelp = counterHelp; | ||
74 | _pcType = pcType; | ||
75 | } | ||
76 | |||
77 | public void AddCounterToCollection(CounterCreationDataCollection counterData) | ||
78 | { | ||
79 | CounterCreationData counterCreationData = new CounterCreationData( | ||
80 | _counterName, | ||
81 | _counterHelp, | ||
82 | _pcType); | ||
83 | |||
84 | counterData.Add(counterCreationData); | ||
85 | } | ||
86 | |||
87 | // Properties | ||
88 | public string Name | ||
89 | { | ||
90 | get | ||
91 | { | ||
92 | return _counterName; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | internal class STPPerformanceCounters | ||
98 | { | ||
99 | // Fields | ||
100 | internal STPPerformanceCounter[] _stpPerformanceCounters; | ||
101 | private static readonly STPPerformanceCounters _instance; | ||
102 | internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; | ||
103 | internal const string _stpCategoryName = "SmartThreadPool"; | ||
104 | |||
105 | // Methods | ||
106 | static STPPerformanceCounters() | ||
107 | { | ||
108 | _instance = new STPPerformanceCounters(); | ||
109 | } | ||
110 | |||
111 | private STPPerformanceCounters() | ||
112 | { | ||
113 | STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] | ||
114 | { | ||
115 | new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), | ||
116 | new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), | ||
117 | new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), | ||
118 | new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), | ||
119 | new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), | ||
120 | |||
121 | new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), | ||
122 | new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), | ||
123 | new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), | ||
124 | |||
125 | new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), | ||
126 | new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), | ||
127 | |||
128 | new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), | ||
129 | new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), | ||
130 | |||
131 | new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), | ||
132 | new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), | ||
133 | |||
134 | new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), | ||
135 | }; | ||
136 | |||
137 | _stpPerformanceCounters = stpPerformanceCounters; | ||
138 | SetupCategory(); | ||
139 | } | ||
140 | |||
141 | private void SetupCategory() | ||
142 | { | ||
143 | if (!PerformanceCounterCategory.Exists(_stpCategoryName)) | ||
144 | { | ||
145 | CounterCreationDataCollection counters = new CounterCreationDataCollection(); | ||
146 | |||
147 | for (int i = 0; i < _stpPerformanceCounters.Length; i++) | ||
148 | { | ||
149 | _stpPerformanceCounters[i].AddCounterToCollection(counters); | ||
150 | } | ||
151 | |||
152 | PerformanceCounterCategory.Create( | ||
153 | _stpCategoryName, | ||
154 | _stpCategoryHelp, | ||
155 | PerformanceCounterCategoryType.MultiInstance, | ||
156 | counters); | ||
157 | |||
158 | } | ||
159 | } | ||
160 | |||
161 | // Properties | ||
162 | public static STPPerformanceCounters Instance | ||
163 | { | ||
164 | get | ||
165 | { | ||
166 | return _instance; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | internal class STPInstancePerformanceCounter : IDisposable | ||
172 | { | ||
173 | // Fields | ||
174 | private bool _isDisposed; | ||
175 | private PerformanceCounter _pcs; | ||
176 | |||
177 | // Methods | ||
178 | protected STPInstancePerformanceCounter() | ||
179 | { | ||
180 | _isDisposed = false; | ||
181 | } | ||
182 | |||
183 | public STPInstancePerformanceCounter( | ||
184 | string instance, | ||
185 | STPPerformanceCounterType spcType) : this() | ||
186 | { | ||
187 | STPPerformanceCounters counters = STPPerformanceCounters.Instance; | ||
188 | _pcs = new PerformanceCounter( | ||
189 | STPPerformanceCounters._stpCategoryName, | ||
190 | counters._stpPerformanceCounters[(int) spcType].Name, | ||
191 | instance, | ||
192 | false); | ||
193 | _pcs.RawValue = _pcs.RawValue; | ||
194 | } | ||
195 | |||
196 | |||
197 | public void Close() | ||
198 | { | ||
199 | if (_pcs != null) | ||
200 | { | ||
201 | _pcs.RemoveInstance(); | ||
202 | _pcs.Close(); | ||
203 | _pcs = null; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | public void Dispose() | ||
208 | { | ||
209 | Dispose(true); | ||
210 | } | ||
211 | |||
212 | public virtual void Dispose(bool disposing) | ||
213 | { | ||
214 | if (!_isDisposed) | ||
215 | { | ||
216 | if (disposing) | ||
217 | { | ||
218 | Close(); | ||
219 | } | ||
220 | } | ||
221 | _isDisposed = true; | ||
222 | } | ||
223 | |||
224 | public virtual void Increment() | ||
225 | { | ||
226 | _pcs.Increment(); | ||
227 | } | ||
228 | |||
229 | public virtual void IncrementBy(long val) | ||
230 | { | ||
231 | _pcs.IncrementBy(val); | ||
232 | } | ||
233 | |||
234 | public virtual void Set(long val) | ||
235 | { | ||
236 | _pcs.RawValue = val; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter | ||
241 | { | ||
242 | // Methods | ||
243 | public override void Increment() {} | ||
244 | public override void IncrementBy(long value) {} | ||
245 | public override void Set(long val) {} | ||
246 | } | ||
247 | |||
248 | |||
249 | |||
250 | internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters | ||
251 | { | ||
252 | private bool _isDisposed; | ||
253 | // Fields | ||
254 | private STPInstancePerformanceCounter[] _pcs; | ||
255 | private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; | ||
256 | |||
257 | // Methods | ||
258 | static STPInstancePerformanceCounters() | ||
259 | { | ||
260 | _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); | ||
261 | } | ||
262 | |||
263 | public STPInstancePerformanceCounters(string instance) | ||
264 | { | ||
265 | _isDisposed = false; | ||
266 | _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; | ||
267 | |||
268 | // Call the STPPerformanceCounters.Instance so the static constructor will | ||
269 | // intialize the STPPerformanceCounters singleton. | ||
270 | STPPerformanceCounters.Instance.GetHashCode(); | ||
271 | |||
272 | for (int i = 0; i < _pcs.Length; i++) | ||
273 | { | ||
274 | if (instance != null) | ||
275 | { | ||
276 | _pcs[i] = new STPInstancePerformanceCounter( | ||
277 | instance, | ||
278 | (STPPerformanceCounterType) i); | ||
279 | } | ||
280 | else | ||
281 | { | ||
282 | _pcs[i] = _stpInstanceNullPerformanceCounter; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | |||
288 | public void Close() | ||
289 | { | ||
290 | if (null != _pcs) | ||
291 | { | ||
292 | for (int i = 0; i < _pcs.Length; i++) | ||
293 | { | ||
294 | if (null != _pcs[i]) | ||
295 | { | ||
296 | _pcs[i].Dispose(); | ||
297 | } | ||
298 | } | ||
299 | _pcs = null; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | public void Dispose() | ||
304 | { | ||
305 | Dispose(true); | ||
306 | } | ||
307 | |||
308 | public virtual void Dispose(bool disposing) | ||
309 | { | ||
310 | if (!_isDisposed) | ||
311 | { | ||
312 | if (disposing) | ||
313 | { | ||
314 | Close(); | ||
315 | } | ||
316 | } | ||
317 | _isDisposed = true; | ||
318 | } | ||
319 | |||
320 | private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) | ||
321 | { | ||
322 | return _pcs[(int) spcType]; | ||
323 | } | ||
324 | |||
325 | public void SampleThreads(long activeThreads, long inUseThreads) | ||
326 | { | ||
327 | GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); | ||
328 | GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); | ||
329 | GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); | ||
330 | |||
331 | GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); | ||
332 | GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); | ||
333 | } | ||
334 | |||
335 | public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) | ||
336 | { | ||
337 | GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); | ||
338 | GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); | ||
339 | GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); | ||
340 | |||
341 | GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); | ||
342 | GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); | ||
343 | } | ||
344 | |||
345 | public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) | ||
346 | { | ||
347 | GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); | ||
348 | GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); | ||
349 | } | ||
350 | |||
351 | public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) | ||
352 | { | ||
353 | GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); | ||
354 | GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); | ||
355 | } | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader | ||
360 | { | ||
361 | private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(); | ||
362 | |||
363 | public static NullSTPInstancePerformanceCounters Instance | ||
364 | { | ||
365 | get { return _instance; } | ||
366 | } | ||
367 | |||
368 | public void Close() {} | ||
369 | public void Dispose() {} | ||
370 | |||
371 | public void SampleThreads(long activeThreads, long inUseThreads) {} | ||
372 | public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} | ||
373 | public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} | ||
374 | public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} | ||
375 | public long InUseThreads | ||
376 | { | ||
377 | get { return 0; } | ||
378 | } | ||
379 | |||
380 | public long ActiveThreads | ||
381 | { | ||
382 | get { return 0; } | ||
383 | } | ||
384 | |||
385 | public long WorkItemsQueued | ||
386 | { | ||
387 | get { return 0; } | ||
388 | } | ||
389 | |||
390 | public long WorkItemsProcessed | ||
391 | { | ||
392 | get { return 0; } | ||
393 | } | ||
394 | } | ||
395 | |||
396 | internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader | ||
397 | { | ||
398 | public void Close() { } | ||
399 | public void Dispose() { } | ||
400 | |||
401 | private long _activeThreads; | ||
402 | private long _inUseThreads; | ||
403 | private long _workItemsQueued; | ||
404 | private long _workItemsProcessed; | ||
405 | |||
406 | public long InUseThreads | ||
407 | { | ||
408 | get { return _inUseThreads; } | ||
409 | } | ||
410 | |||
411 | public long ActiveThreads | ||
412 | { | ||
413 | get { return _activeThreads; } | ||
414 | } | ||
415 | |||
416 | public long WorkItemsQueued | ||
417 | { | ||
418 | get { return _workItemsQueued; } | ||
419 | } | ||
420 | |||
421 | public long WorkItemsProcessed | ||
422 | { | ||
423 | get { return _workItemsProcessed; } | ||
424 | } | ||
425 | |||
426 | public void SampleThreads(long activeThreads, long inUseThreads) | ||
427 | { | ||
428 | _activeThreads = activeThreads; | ||
429 | _inUseThreads = inUseThreads; | ||
430 | } | ||
431 | |||
432 | public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) | ||
433 | { | ||
434 | _workItemsQueued = workItemsQueued; | ||
435 | _workItemsProcessed = workItemsProcessed; | ||
436 | } | ||
437 | |||
438 | public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) | ||
439 | { | ||
440 | // Not supported | ||
441 | } | ||
442 | |||
443 | public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) | ||
444 | { | ||
445 | // Not supported | ||
446 | } | ||
447 | } | ||
448 | } | ||
diff --git a/ThirdParty/SmartThreadPool/STPStartInfo.cs b/ThirdParty/SmartThreadPool/STPStartInfo.cs new file mode 100644 index 0000000..8ea547c --- /dev/null +++ b/ThirdParty/SmartThreadPool/STPStartInfo.cs | |||
@@ -0,0 +1,212 @@ | |||
1 | using System; | ||
2 | using System.Threading; | ||
3 | |||
4 | namespace Amib.Threading | ||
5 | { | ||
6 | /// <summary> | ||
7 | /// Summary description for STPStartInfo. | ||
8 | /// </summary> | ||
9 | public class STPStartInfo : WIGStartInfo | ||
10 | { | ||
11 | private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout; | ||
12 | private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; | ||
13 | private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; | ||
14 | #if !(WINDOWS_PHONE) | ||
15 | private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority; | ||
16 | #endif | ||
17 | private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; | ||
18 | private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground; | ||
19 | private bool _enableLocalPerformanceCounters; | ||
20 | private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName; | ||
21 | private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize; | ||
22 | |||
23 | public STPStartInfo() | ||
24 | { | ||
25 | _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; | ||
26 | #if !(WINDOWS_PHONE) | ||
27 | _threadPriority = SmartThreadPool.DefaultThreadPriority; | ||
28 | #endif | ||
29 | _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; | ||
30 | _idleTimeout = SmartThreadPool.DefaultIdleTimeout; | ||
31 | _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; | ||
32 | } | ||
33 | |||
34 | public STPStartInfo(STPStartInfo stpStartInfo) | ||
35 | : base(stpStartInfo) | ||
36 | { | ||
37 | _idleTimeout = stpStartInfo.IdleTimeout; | ||
38 | _minWorkerThreads = stpStartInfo.MinWorkerThreads; | ||
39 | _maxWorkerThreads = stpStartInfo.MaxWorkerThreads; | ||
40 | #if !(WINDOWS_PHONE) | ||
41 | _threadPriority = stpStartInfo.ThreadPriority; | ||
42 | #endif | ||
43 | _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName; | ||
44 | _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters; | ||
45 | _threadPoolName = stpStartInfo._threadPoolName; | ||
46 | _areThreadsBackground = stpStartInfo.AreThreadsBackground; | ||
47 | #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
48 | _apartmentState = stpStartInfo._apartmentState; | ||
49 | #endif | ||
50 | } | ||
51 | |||
52 | /// <summary> | ||
53 | /// Get/Set the idle timeout in milliseconds. | ||
54 | /// If a thread is idle (starved) longer than IdleTimeout then it may quit. | ||
55 | /// </summary> | ||
56 | public virtual int IdleTimeout | ||
57 | { | ||
58 | get { return _idleTimeout; } | ||
59 | set | ||
60 | { | ||
61 | ThrowIfReadOnly(); | ||
62 | _idleTimeout = value; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | |||
67 | /// <summary> | ||
68 | /// Get/Set the lower limit of threads in the pool. | ||
69 | /// </summary> | ||
70 | public virtual int MinWorkerThreads | ||
71 | { | ||
72 | get { return _minWorkerThreads; } | ||
73 | set | ||
74 | { | ||
75 | ThrowIfReadOnly(); | ||
76 | _minWorkerThreads = value; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | |||
81 | /// <summary> | ||
82 | /// Get/Set the upper limit of threads in the pool. | ||
83 | /// </summary> | ||
84 | public virtual int MaxWorkerThreads | ||
85 | { | ||
86 | get { return _maxWorkerThreads; } | ||
87 | set | ||
88 | { | ||
89 | ThrowIfReadOnly(); | ||
90 | _maxWorkerThreads = value; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | #if !(WINDOWS_PHONE) | ||
95 | /// <summary> | ||
96 | /// Get/Set the scheduling priority of the threads in the pool. | ||
97 | /// The Os handles the scheduling. | ||
98 | /// </summary> | ||
99 | public virtual ThreadPriority ThreadPriority | ||
100 | { | ||
101 | get { return _threadPriority; } | ||
102 | set | ||
103 | { | ||
104 | ThrowIfReadOnly(); | ||
105 | _threadPriority = value; | ||
106 | } | ||
107 | } | ||
108 | #endif | ||
109 | /// <summary> | ||
110 | /// Get/Set the thread pool name. Threads will get names depending on this. | ||
111 | /// </summary> | ||
112 | public virtual string ThreadPoolName { | ||
113 | get { return _threadPoolName; } | ||
114 | set | ||
115 | { | ||
116 | ThrowIfReadOnly (); | ||
117 | _threadPoolName = value; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Get/Set the performance counter instance name of this SmartThreadPool | ||
123 | /// The default is null which indicate not to use performance counters at all. | ||
124 | /// </summary> | ||
125 | public virtual string PerformanceCounterInstanceName | ||
126 | { | ||
127 | get { return _performanceCounterInstanceName; } | ||
128 | set | ||
129 | { | ||
130 | ThrowIfReadOnly(); | ||
131 | _performanceCounterInstanceName = value; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | /// <summary> | ||
136 | /// Enable/Disable the local performance counter. | ||
137 | /// This enables the user to get some performance information about the SmartThreadPool | ||
138 | /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.) | ||
139 | /// The default is false. | ||
140 | /// </summary> | ||
141 | public virtual bool EnableLocalPerformanceCounters | ||
142 | { | ||
143 | get { return _enableLocalPerformanceCounters; } | ||
144 | set | ||
145 | { | ||
146 | ThrowIfReadOnly(); | ||
147 | _enableLocalPerformanceCounters = value; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Get/Set backgroundness of thread in thread pool. | ||
153 | /// </summary> | ||
154 | public virtual bool AreThreadsBackground | ||
155 | { | ||
156 | get { return _areThreadsBackground; } | ||
157 | set | ||
158 | { | ||
159 | ThrowIfReadOnly (); | ||
160 | _areThreadsBackground = value; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /// <summary> | ||
165 | /// Get a readonly version of this STPStartInfo. | ||
166 | /// </summary> | ||
167 | /// <returns>Returns a readonly reference to this STPStartInfo</returns> | ||
168 | public new STPStartInfo AsReadOnly() | ||
169 | { | ||
170 | return new STPStartInfo(this) { _readOnly = true }; | ||
171 | } | ||
172 | |||
173 | #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
174 | |||
175 | private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState; | ||
176 | |||
177 | /// <summary> | ||
178 | /// Get/Set the apartment state of threads in the thread pool | ||
179 | /// </summary> | ||
180 | public ApartmentState ApartmentState | ||
181 | { | ||
182 | get { return _apartmentState; } | ||
183 | set | ||
184 | { | ||
185 | ThrowIfReadOnly(); | ||
186 | _apartmentState = value; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
191 | |||
192 | /// <summary> | ||
193 | /// Get/Set the max stack size of threads in the thread pool | ||
194 | /// </summary> | ||
195 | public int? MaxStackSize | ||
196 | { | ||
197 | get { return _maxStackSize; } | ||
198 | set | ||
199 | { | ||
200 | ThrowIfReadOnly(); | ||
201 | if (value.HasValue && value.Value < 0) | ||
202 | { | ||
203 | throw new ArgumentOutOfRangeException("value", "Value must be greater than 0."); | ||
204 | } | ||
205 | _maxStackSize = value; | ||
206 | } | ||
207 | } | ||
208 | #endif | ||
209 | |||
210 | #endif | ||
211 | } | ||
212 | } | ||
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs new file mode 100644 index 0000000..4713332 --- /dev/null +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs | |||
@@ -0,0 +1,60 @@ | |||
1 | |||
2 | using System; | ||
3 | using Amib.Threading.Internal; | ||
4 | |||
5 | namespace Amib.Threading | ||
6 | { | ||
7 | public partial class SmartThreadPool | ||
8 | { | ||
9 | #region ThreadEntry class | ||
10 | |||
11 | internal class ThreadEntry | ||
12 | { | ||
13 | /// <summary> | ||
14 | /// The thread creation time | ||
15 | /// The value is stored as UTC value. | ||
16 | /// </summary> | ||
17 | private readonly DateTime _creationTime; | ||
18 | |||
19 | /// <summary> | ||
20 | /// The last time this thread has been running | ||
21 | /// It is updated by IAmAlive() method | ||
22 | /// The value is stored as UTC value. | ||
23 | /// </summary> | ||
24 | private DateTime _lastAliveTime; | ||
25 | |||
26 | /// <summary> | ||
27 | /// A reference from each thread in the thread pool to its SmartThreadPool | ||
28 | /// object container. | ||
29 | /// With this variable a thread can know whatever it belongs to a | ||
30 | /// SmartThreadPool. | ||
31 | /// </summary> | ||
32 | private readonly SmartThreadPool _associatedSmartThreadPool; | ||
33 | |||
34 | /// <summary> | ||
35 | /// A reference to the current work item a thread from the thread pool | ||
36 | /// is executing. | ||
37 | /// </summary> | ||
38 | public WorkItem CurrentWorkItem { get; set; } | ||
39 | |||
40 | public ThreadEntry(SmartThreadPool stp) | ||
41 | { | ||
42 | _associatedSmartThreadPool = stp; | ||
43 | _creationTime = DateTime.UtcNow; | ||
44 | _lastAliveTime = DateTime.MinValue; | ||
45 | } | ||
46 | |||
47 | public SmartThreadPool AssociatedSmartThreadPool | ||
48 | { | ||
49 | get { return _associatedSmartThreadPool; } | ||
50 | } | ||
51 | |||
52 | public void IAmAlive() | ||
53 | { | ||
54 | _lastAliveTime = DateTime.UtcNow; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | #endregion | ||
59 | } | ||
60 | } \ No newline at end of file | ||
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs new file mode 100644 index 0000000..7cc7fbf --- /dev/null +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs | |||
@@ -0,0 +1,1737 @@ | |||
1 | #region Release History | ||
2 | |||
3 | // Smart Thread Pool | ||
4 | // 7 Aug 2004 - Initial release | ||
5 | // | ||
6 | // 14 Sep 2004 - Bug fixes | ||
7 | // | ||
8 | // 15 Oct 2004 - Added new features | ||
9 | // - Work items return result. | ||
10 | // - Support waiting synchronization for multiple work items. | ||
11 | // - Work items can be cancelled. | ||
12 | // - Passage of the caller thread’s context to the thread in the pool. | ||
13 | // - Minimal usage of WIN32 handles. | ||
14 | // - Minor bug fixes. | ||
15 | // | ||
16 | // 26 Dec 2004 - Changes: | ||
17 | // - Removed static constructors. | ||
18 | // - Added finalizers. | ||
19 | // - Changed Exceptions so they are serializable. | ||
20 | // - Fixed the bug in one of the SmartThreadPool constructors. | ||
21 | // - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. | ||
22 | // The SmartThreadPool.WaitAny() is still limited by the .NET Framework. | ||
23 | // - Added PostExecute with options on which cases to call it. | ||
24 | // - Added option to dispose of the state objects. | ||
25 | // - Added a WaitForIdle() method that waits until the work items queue is empty. | ||
26 | // - Added an STPStartInfo class for the initialization of the thread pool. | ||
27 | // - Changed exception handling so if a work item throws an exception it | ||
28 | // is rethrown at GetResult(), rather then firing an UnhandledException event. | ||
29 | // Note that PostExecute exception are always ignored. | ||
30 | // | ||
31 | // 25 Mar 2005 - Changes: | ||
32 | // - Fixed lost of work items bug | ||
33 | // | ||
34 | // 3 Jul 2005: Changes. | ||
35 | // - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. | ||
36 | // | ||
37 | // 16 Aug 2005: Changes. | ||
38 | // - Fixed bug where the InUseThreads becomes negative when canceling work items. | ||
39 | // | ||
40 | // 31 Jan 2006 - Changes: | ||
41 | // - Added work items priority | ||
42 | // - Removed support of chained delegates in callbacks and post executes (nobody really use this) | ||
43 | // - Added work items groups | ||
44 | // - Added work items groups idle event | ||
45 | // - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array | ||
46 | // it returns true rather then throwing an exception. | ||
47 | // - Added option to start the STP and the WIG as suspended | ||
48 | // - Exception behavior changed, the real exception is returned by an | ||
49 | // inner exception | ||
50 | // - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) | ||
51 | // - Added performance counters | ||
52 | // - Added priority to the threads in the pool | ||
53 | // | ||
54 | // 13 Feb 2006 - Changes: | ||
55 | // - Added a call to the dispose of the Performance Counter so | ||
56 | // their won't be a Performance Counter leak. | ||
57 | // - Added exception catch in case the Performance Counters cannot | ||
58 | // be created. | ||
59 | // | ||
60 | // 17 May 2008 - Changes: | ||
61 | // - Changed the dispose behavior and removed the Finalizers. | ||
62 | // - Enabled the change of the MaxThreads and MinThreads at run time. | ||
63 | // - Enabled the change of the Concurrency of a IWorkItemsGroup at run | ||
64 | // time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency | ||
65 | // refers to the MaxThreads. | ||
66 | // - Improved the cancel behavior. | ||
67 | // - Added events for thread creation and termination. | ||
68 | // - Fixed the HttpContext context capture. | ||
69 | // - Changed internal collections so they use generic collections | ||
70 | // - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup | ||
71 | // - Added support for WinCE | ||
72 | // - Added support for Action<T> and Func<T> | ||
73 | // | ||
74 | // 07 April 2009 - Changes: | ||
75 | // - Added support for Silverlight and Mono | ||
76 | // - Added Join, Choice, and Pipe to SmartThreadPool. | ||
77 | // - Added local performance counters (for Mono, Silverlight, and WindowsCE) | ||
78 | // - Changed duration measures from DateTime.Now to Stopwatch. | ||
79 | // - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList<T>. | ||
80 | // | ||
81 | // 21 December 2009 - Changes: | ||
82 | // - Added work item timeout (passive) | ||
83 | // | ||
84 | // 20 August 2012 - Changes: | ||
85 | // - Added set name to threads | ||
86 | // - Fixed the WorkItemsQueue.Dequeue. | ||
87 | // Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } | ||
88 | // - Fixed SmartThreadPool.Pipe | ||
89 | // - Added IsBackground option to threads | ||
90 | // - Added ApartmentState to threads | ||
91 | // - Fixed thread creation when queuing many work items at the same time. | ||
92 | // | ||
93 | // 24 August 2012 - Changes: | ||
94 | // - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan | ||
95 | // - Added option to set MaxStackSize of threads | ||
96 | |||
97 | #endregion | ||
98 | |||
99 | using System; | ||
100 | using System.Security; | ||
101 | using System.Threading; | ||
102 | using System.Collections; | ||
103 | using System.Collections.Generic; | ||
104 | using System.Diagnostics; | ||
105 | using System.Runtime.CompilerServices; | ||
106 | |||
107 | using Amib.Threading.Internal; | ||
108 | |||
109 | namespace Amib.Threading | ||
110 | { | ||
111 | #region SmartThreadPool class | ||
112 | /// <summary> | ||
113 | /// Smart thread pool class. | ||
114 | /// </summary> | ||
115 | public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable | ||
116 | { | ||
117 | #region Public Default Constants | ||
118 | |||
119 | /// <summary> | ||
120 | /// Default minimum number of threads the thread pool contains. (0) | ||
121 | /// </summary> | ||
122 | public const int DefaultMinWorkerThreads = 0; | ||
123 | |||
124 | /// <summary> | ||
125 | /// Default maximum number of threads the thread pool contains. (25) | ||
126 | /// </summary> | ||
127 | public const int DefaultMaxWorkerThreads = 25; | ||
128 | |||
129 | /// <summary> | ||
130 | /// Default idle timeout in milliseconds. (One minute) | ||
131 | /// </summary> | ||
132 | public const int DefaultIdleTimeout = 60*1000; // One minute | ||
133 | |||
134 | /// <summary> | ||
135 | /// Indicate to copy the security context of the caller and then use it in the call. (false) | ||
136 | /// </summary> | ||
137 | public const bool DefaultUseCallerCallContext = false; | ||
138 | |||
139 | /// <summary> | ||
140 | /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) | ||
141 | /// </summary> | ||
142 | public const bool DefaultUseCallerHttpContext = false; | ||
143 | |||
144 | /// <summary> | ||
145 | /// Indicate to dispose of the state objects if they support the IDispose interface. (false) | ||
146 | /// </summary> | ||
147 | public const bool DefaultDisposeOfStateObjects = false; | ||
148 | |||
149 | /// <summary> | ||
150 | /// The default option to run the post execute (CallToPostExecute.Always) | ||
151 | /// </summary> | ||
152 | public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; | ||
153 | |||
154 | /// <summary> | ||
155 | /// The default post execute method to run. (None) | ||
156 | /// When null it means not to call it. | ||
157 | /// </summary> | ||
158 | public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; | ||
159 | |||
160 | /// <summary> | ||
161 | /// The default work item priority (WorkItemPriority.Normal) | ||
162 | /// </summary> | ||
163 | public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; | ||
164 | |||
165 | /// <summary> | ||
166 | /// The default is to work on work items as soon as they arrive | ||
167 | /// and not to wait for the start. (false) | ||
168 | /// </summary> | ||
169 | public const bool DefaultStartSuspended = false; | ||
170 | |||
171 | /// <summary> | ||
172 | /// The default name to use for the performance counters instance. (null) | ||
173 | /// </summary> | ||
174 | public static readonly string DefaultPerformanceCounterInstanceName; | ||
175 | |||
176 | #if !(WINDOWS_PHONE) | ||
177 | |||
178 | /// <summary> | ||
179 | /// The default thread priority (ThreadPriority.Normal) | ||
180 | /// </summary> | ||
181 | public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; | ||
182 | #endif | ||
183 | /// <summary> | ||
184 | /// The default thread pool name. (SmartThreadPool) | ||
185 | /// </summary> | ||
186 | public const string DefaultThreadPoolName = "SmartThreadPool"; | ||
187 | |||
188 | /// <summary> | ||
189 | /// The default Max Stack Size. (SmartThreadPool) | ||
190 | /// </summary> | ||
191 | public static readonly int? DefaultMaxStackSize = null; | ||
192 | |||
193 | /// <summary> | ||
194 | /// The default fill state with params. (false) | ||
195 | /// It is relevant only to QueueWorkItem of Action<...>/Func<...> | ||
196 | /// </summary> | ||
197 | public const bool DefaultFillStateWithArgs = false; | ||
198 | |||
199 | /// <summary> | ||
200 | /// The default thread backgroundness. (true) | ||
201 | /// </summary> | ||
202 | public const bool DefaultAreThreadsBackground = true; | ||
203 | |||
204 | #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
205 | /// <summary> | ||
206 | /// The default apartment state of a thread in the thread pool. | ||
207 | /// The default is ApartmentState.Unknown which means the STP will not | ||
208 | /// set the apartment of the thread. It will use the .NET default. | ||
209 | /// </summary> | ||
210 | public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; | ||
211 | #endif | ||
212 | |||
213 | #endregion | ||
214 | |||
215 | #region Member Variables | ||
216 | |||
217 | /// <summary> | ||
218 | /// Dictionary of all the threads in the thread pool. | ||
219 | /// </summary> | ||
220 | private readonly SynchronizedDictionary<Thread, ThreadEntry> _workerThreads = new SynchronizedDictionary<Thread, ThreadEntry>(); | ||
221 | |||
222 | /// <summary> | ||
223 | /// Queue of work items. | ||
224 | /// </summary> | ||
225 | private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); | ||
226 | |||
227 | /// <summary> | ||
228 | /// Count the work items handled. | ||
229 | /// Used by the performance counter. | ||
230 | /// </summary> | ||
231 | private int _workItemsProcessed; | ||
232 | |||
233 | /// <summary> | ||
234 | /// Number of threads that currently work (not idle). | ||
235 | /// </summary> | ||
236 | private int _inUseWorkerThreads; | ||
237 | |||
238 | /// <summary> | ||
239 | /// Stores a copy of the original STPStartInfo. | ||
240 | /// It is used to change the MinThread and MaxThreads | ||
241 | /// </summary> | ||
242 | private STPStartInfo _stpStartInfo; | ||
243 | |||
244 | /// <summary> | ||
245 | /// Total number of work items that are stored in the work items queue | ||
246 | /// plus the work items that the threads in the pool are working on. | ||
247 | /// </summary> | ||
248 | private int _currentWorkItemsCount; | ||
249 | |||
250 | /// <summary> | ||
251 | /// Signaled when the thread pool is idle, i.e. no thread is busy | ||
252 | /// and the work items queue is empty | ||
253 | /// </summary> | ||
254 | //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); | ||
255 | private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); | ||
256 | |||
257 | /// <summary> | ||
258 | /// An event to signal all the threads to quit immediately. | ||
259 | /// </summary> | ||
260 | //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); | ||
261 | private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); | ||
262 | |||
263 | /// <summary> | ||
264 | /// A flag to indicate if the Smart Thread Pool is now suspended. | ||
265 | /// </summary> | ||
266 | private bool _isSuspended; | ||
267 | |||
268 | /// <summary> | ||
269 | /// A flag to indicate the threads to quit. | ||
270 | /// </summary> | ||
271 | private bool _shutdown; | ||
272 | |||
273 | /// <summary> | ||
274 | /// Counts the threads created in the pool. | ||
275 | /// It is used to name the threads. | ||
276 | /// </summary> | ||
277 | private int _threadCounter; | ||
278 | |||
279 | /// <summary> | ||
280 | /// Indicate that the SmartThreadPool has been disposed | ||
281 | /// </summary> | ||
282 | private bool _isDisposed; | ||
283 | |||
284 | /// <summary> | ||
285 | /// Holds all the WorkItemsGroup instaces that have at least one | ||
286 | /// work item int the SmartThreadPool | ||
287 | /// This variable is used in case of Shutdown | ||
288 | /// </summary> | ||
289 | private readonly SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup> _workItemsGroups = new SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup>(); | ||
290 | |||
291 | /// <summary> | ||
292 | /// A common object for all the work items int the STP | ||
293 | /// so we can mark them to cancel in O(1) | ||
294 | /// </summary> | ||
295 | private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup(); | ||
296 | |||
297 | /// <summary> | ||
298 | /// Windows STP performance counters | ||
299 | /// </summary> | ||
300 | private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance; | ||
301 | |||
302 | /// <summary> | ||
303 | /// Local STP performance counters | ||
304 | /// </summary> | ||
305 | private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; | ||
306 | |||
307 | |||
308 | #if (WINDOWS_PHONE) | ||
309 | private static readonly Dictionary<int, ThreadEntry> _threadEntries = new Dictionary<int, ThreadEntry>(); | ||
310 | #elif (_WINDOWS_CE) | ||
311 | private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); | ||
312 | #else | ||
313 | [ThreadStatic] | ||
314 | private static ThreadEntry _threadEntry; | ||
315 | |||
316 | #endif | ||
317 | |||
318 | /// <summary> | ||
319 | /// An event to call after a thread is created, but before | ||
320 | /// it's first use. | ||
321 | /// </summary> | ||
322 | private event ThreadInitializationHandler _onThreadInitialization; | ||
323 | |||
324 | /// <summary> | ||
325 | /// An event to call when a thread is about to exit, after | ||
326 | /// it is no longer belong to the pool. | ||
327 | /// </summary> | ||
328 | private event ThreadTerminationHandler _onThreadTermination; | ||
329 | |||
330 | #endregion | ||
331 | |||
332 | #region Per thread properties | ||
333 | |||
334 | /// <summary> | ||
335 | /// A reference to the current work item a thread from the thread pool | ||
336 | /// is executing. | ||
337 | /// </summary> | ||
338 | internal static ThreadEntry CurrentThreadEntry | ||
339 | { | ||
340 | #if (WINDOWS_PHONE) | ||
341 | get | ||
342 | { | ||
343 | lock(_threadEntries) | ||
344 | { | ||
345 | ThreadEntry threadEntry; | ||
346 | if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry)) | ||
347 | { | ||
348 | return threadEntry; | ||
349 | } | ||
350 | } | ||
351 | return null; | ||
352 | } | ||
353 | set | ||
354 | { | ||
355 | lock(_threadEntries) | ||
356 | { | ||
357 | _threadEntries[Thread.CurrentThread.ManagedThreadId] = value; | ||
358 | } | ||
359 | } | ||
360 | #elif (_WINDOWS_CE) | ||
361 | get | ||
362 | { | ||
363 | //Thread.CurrentThread.ManagedThreadId | ||
364 | return Thread.GetData(_threadEntrySlot) as ThreadEntry; | ||
365 | } | ||
366 | set | ||
367 | { | ||
368 | Thread.SetData(_threadEntrySlot, value); | ||
369 | } | ||
370 | #else | ||
371 | get | ||
372 | { | ||
373 | return _threadEntry; | ||
374 | } | ||
375 | set | ||
376 | { | ||
377 | _threadEntry = value; | ||
378 | } | ||
379 | #endif | ||
380 | } | ||
381 | #endregion | ||
382 | |||
383 | #region Construction and Finalization | ||
384 | |||
385 | /// <summary> | ||
386 | /// Constructor | ||
387 | /// </summary> | ||
388 | public SmartThreadPool() | ||
389 | { | ||
390 | _stpStartInfo = new STPStartInfo(); | ||
391 | Initialize(); | ||
392 | } | ||
393 | |||
394 | /// <summary> | ||
395 | /// Constructor | ||
396 | /// </summary> | ||
397 | /// <param name="idleTimeout">Idle timeout in milliseconds</param> | ||
398 | public SmartThreadPool(int idleTimeout) | ||
399 | { | ||
400 | _stpStartInfo = new STPStartInfo | ||
401 | { | ||
402 | IdleTimeout = idleTimeout, | ||
403 | }; | ||
404 | Initialize(); | ||
405 | } | ||
406 | |||
407 | /// <summary> | ||
408 | /// Constructor | ||
409 | /// </summary> | ||
410 | /// <param name="idleTimeout">Idle timeout in milliseconds</param> | ||
411 | /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> | ||
412 | public SmartThreadPool( | ||
413 | int idleTimeout, | ||
414 | int maxWorkerThreads) | ||
415 | { | ||
416 | _stpStartInfo = new STPStartInfo | ||
417 | { | ||
418 | IdleTimeout = idleTimeout, | ||
419 | MaxWorkerThreads = maxWorkerThreads, | ||
420 | }; | ||
421 | Initialize(); | ||
422 | } | ||
423 | |||
424 | /// <summary> | ||
425 | /// Constructor | ||
426 | /// </summary> | ||
427 | /// <param name="idleTimeout">Idle timeout in milliseconds</param> | ||
428 | /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> | ||
429 | /// <param name="minWorkerThreads">Lower limit of threads in the pool</param> | ||
430 | public SmartThreadPool( | ||
431 | int idleTimeout, | ||
432 | int maxWorkerThreads, | ||
433 | int minWorkerThreads) | ||
434 | { | ||
435 | _stpStartInfo = new STPStartInfo | ||
436 | { | ||
437 | IdleTimeout = idleTimeout, | ||
438 | MaxWorkerThreads = maxWorkerThreads, | ||
439 | MinWorkerThreads = minWorkerThreads, | ||
440 | }; | ||
441 | Initialize(); | ||
442 | } | ||
443 | |||
444 | /// <summary> | ||
445 | /// Constructor | ||
446 | /// </summary> | ||
447 | /// <param name="stpStartInfo">A SmartThreadPool configuration that overrides the default behavior</param> | ||
448 | public SmartThreadPool(STPStartInfo stpStartInfo) | ||
449 | { | ||
450 | _stpStartInfo = new STPStartInfo(stpStartInfo); | ||
451 | Initialize(); | ||
452 | } | ||
453 | |||
454 | private void Initialize() | ||
455 | { | ||
456 | Name = _stpStartInfo.ThreadPoolName; | ||
457 | ValidateSTPStartInfo(); | ||
458 | |||
459 | // _stpStartInfoRW stores a read/write copy of the STPStartInfo. | ||
460 | // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten | ||
461 | |||
462 | _isSuspended = _stpStartInfo.StartSuspended; | ||
463 | |||
464 | #if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) | ||
465 | if (null != _stpStartInfo.PerformanceCounterInstanceName) | ||
466 | { | ||
467 | throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); | ||
468 | } | ||
469 | #else | ||
470 | if (null != _stpStartInfo.PerformanceCounterInstanceName) | ||
471 | { | ||
472 | try | ||
473 | { | ||
474 | _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); | ||
475 | } | ||
476 | catch (Exception e) | ||
477 | { | ||
478 | Debug.WriteLine("Unable to create Performance Counters: " + e); | ||
479 | _windowsPCs = NullSTPInstancePerformanceCounters.Instance; | ||
480 | } | ||
481 | } | ||
482 | #endif | ||
483 | |||
484 | if (_stpStartInfo.EnableLocalPerformanceCounters) | ||
485 | { | ||
486 | _localPCs = new LocalSTPInstancePerformanceCounters(); | ||
487 | } | ||
488 | |||
489 | // If the STP is not started suspended then start the threads. | ||
490 | if (!_isSuspended) | ||
491 | { | ||
492 | StartOptimalNumberOfThreads(); | ||
493 | } | ||
494 | } | ||
495 | |||
496 | private void StartOptimalNumberOfThreads() | ||
497 | { | ||
498 | int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); | ||
499 | threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); | ||
500 | threadsCount -= _workerThreads.Count; | ||
501 | if (threadsCount > 0) | ||
502 | { | ||
503 | StartThreads(threadsCount); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | private void ValidateSTPStartInfo() | ||
508 | { | ||
509 | if (_stpStartInfo.MinWorkerThreads < 0) | ||
510 | { | ||
511 | throw new ArgumentOutOfRangeException( | ||
512 | "MinWorkerThreads", "MinWorkerThreads cannot be negative"); | ||
513 | } | ||
514 | |||
515 | if (_stpStartInfo.MaxWorkerThreads <= 0) | ||
516 | { | ||
517 | throw new ArgumentOutOfRangeException( | ||
518 | "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); | ||
519 | } | ||
520 | |||
521 | if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) | ||
522 | { | ||
523 | throw new ArgumentOutOfRangeException( | ||
524 | "MinWorkerThreads, maxWorkerThreads", | ||
525 | "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | private static void ValidateCallback(Delegate callback) | ||
530 | { | ||
531 | if(callback.GetInvocationList().Length > 1) | ||
532 | { | ||
533 | throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); | ||
534 | } | ||
535 | } | ||
536 | |||
537 | #endregion | ||
538 | |||
539 | #region Thread Processing | ||
540 | |||
541 | /// <summary> | ||
542 | /// Waits on the queue for a work item, shutdown, or timeout. | ||
543 | /// </summary> | ||
544 | /// <returns> | ||
545 | /// Returns the WaitingCallback or null in case of timeout or shutdown. | ||
546 | /// </returns> | ||
547 | private WorkItem Dequeue() | ||
548 | { | ||
549 | WorkItem workItem = | ||
550 | _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); | ||
551 | |||
552 | return workItem; | ||
553 | } | ||
554 | |||
555 | /// <summary> | ||
556 | /// Put a new work item in the queue | ||
557 | /// </summary> | ||
558 | /// <param name="workItem">A work item to queue</param> | ||
559 | internal override void Enqueue(WorkItem workItem) | ||
560 | { | ||
561 | // Make sure the workItem is not null | ||
562 | Debug.Assert(null != workItem); | ||
563 | |||
564 | IncrementWorkItemsCount(); | ||
565 | |||
566 | workItem.CanceledSmartThreadPool = _canceledSmartThreadPool; | ||
567 | _workItemsQueue.EnqueueWorkItem(workItem); | ||
568 | workItem.WorkItemIsQueued(); | ||
569 | |||
570 | // If all the threads are busy then try to create a new one | ||
571 | if (_currentWorkItemsCount > _workerThreads.Count) | ||
572 | { | ||
573 | StartThreads(1); | ||
574 | } | ||
575 | } | ||
576 | |||
577 | private void IncrementWorkItemsCount() | ||
578 | { | ||
579 | _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); | ||
580 | _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); | ||
581 | |||
582 | int count = Interlocked.Increment(ref _currentWorkItemsCount); | ||
583 | //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); | ||
584 | if (count == 1) | ||
585 | { | ||
586 | IsIdle = false; | ||
587 | _isIdleWaitHandle.Reset(); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | private void DecrementWorkItemsCount() | ||
592 | { | ||
593 | int count = Interlocked.Decrement(ref _currentWorkItemsCount); | ||
594 | //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); | ||
595 | if (count == 0) | ||
596 | { | ||
597 | IsIdle = true; | ||
598 | _isIdleWaitHandle.Set(); | ||
599 | } | ||
600 | |||
601 | Interlocked.Increment(ref _workItemsProcessed); | ||
602 | |||
603 | if (!_shutdown) | ||
604 | { | ||
605 | // The counter counts even if the work item was cancelled | ||
606 | _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); | ||
607 | _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); | ||
608 | } | ||
609 | |||
610 | } | ||
611 | |||
612 | internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) | ||
613 | { | ||
614 | _workItemsGroups[workItemsGroup] = workItemsGroup; | ||
615 | } | ||
616 | |||
617 | internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) | ||
618 | { | ||
619 | if (_workItemsGroups.Contains(workItemsGroup)) | ||
620 | { | ||
621 | _workItemsGroups.Remove(workItemsGroup); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | /// <summary> | ||
626 | /// Inform that the current thread is about to quit or quiting. | ||
627 | /// The same thread may call this method more than once. | ||
628 | /// </summary> | ||
629 | private void InformCompleted() | ||
630 | { | ||
631 | // There is no need to lock the two methods together | ||
632 | // since only the current thread removes itself | ||
633 | // and the _workerThreads is a synchronized dictionary | ||
634 | if (_workerThreads.Contains(Thread.CurrentThread)) | ||
635 | { | ||
636 | _workerThreads.Remove(Thread.CurrentThread); | ||
637 | _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); | ||
638 | _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | /// <summary> | ||
643 | /// Starts new threads | ||
644 | /// </summary> | ||
645 | /// <param name="threadsCount">The number of threads to start</param> | ||
646 | private void StartThreads(int threadsCount) | ||
647 | { | ||
648 | if (_isSuspended) | ||
649 | { | ||
650 | return; | ||
651 | } | ||
652 | |||
653 | lock(_workerThreads.SyncRoot) | ||
654 | { | ||
655 | // Don't start threads on shut down | ||
656 | if (_shutdown) | ||
657 | { | ||
658 | return; | ||
659 | } | ||
660 | |||
661 | for(int i = 0; i < threadsCount; ++i) | ||
662 | { | ||
663 | // Don't create more threads then the upper limit | ||
664 | if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) | ||
665 | { | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | // Create a new thread | ||
670 | |||
671 | #if (_SILVERLIGHT) || (WINDOWS_PHONE) | ||
672 | Thread workerThread = new Thread(ProcessQueuedItems); | ||
673 | #else | ||
674 | Thread workerThread = | ||
675 | _stpStartInfo.MaxStackSize.HasValue | ||
676 | ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value) | ||
677 | : new Thread(ProcessQueuedItems); | ||
678 | #endif | ||
679 | // Configure the new thread and start it | ||
680 | workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; | ||
681 | |||
682 | #if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) | ||
683 | if (_stpStartInfo.ApartmentState != ApartmentState.Unknown) | ||
684 | { | ||
685 | workerThread.SetApartmentState(_stpStartInfo.ApartmentState); | ||
686 | } | ||
687 | #endif | ||
688 | |||
689 | #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
690 | workerThread.Priority = _stpStartInfo.ThreadPriority; | ||
691 | #endif | ||
692 | workerThread.Name = string.Format("STP:{0}:{1}", Name, _threadCounter); | ||
693 | workerThread.Start(); | ||
694 | |||
695 | ++_threadCounter; | ||
696 | |||
697 | // Add it to the dictionary and update its creation time. | ||
698 | _workerThreads[workerThread] = new ThreadEntry(this); | ||
699 | |||
700 | _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); | ||
701 | _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); | ||
702 | } | ||
703 | } | ||
704 | } | ||
705 | |||
706 | /// <summary> | ||
707 | /// A worker thread method that processes work items from the work items queue. | ||
708 | /// </summary> | ||
709 | private void ProcessQueuedItems() | ||
710 | { | ||
711 | // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks | ||
712 | // of the dictionary. | ||
713 | CurrentThreadEntry = _workerThreads[Thread.CurrentThread]; | ||
714 | |||
715 | FireOnThreadInitialization(); | ||
716 | |||
717 | try | ||
718 | { | ||
719 | bool bInUseWorkerThreadsWasIncremented = false; | ||
720 | |||
721 | // Process until shutdown. | ||
722 | while(!_shutdown) | ||
723 | { | ||
724 | // Update the last time this thread was seen alive. | ||
725 | // It's good for debugging. | ||
726 | CurrentThreadEntry.IAmAlive(); | ||
727 | |||
728 | // The following block handles the when the MaxWorkerThreads has been | ||
729 | // incremented by the user at run-time. | ||
730 | // Double lock for quit. | ||
731 | if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) | ||
732 | { | ||
733 | lock (_workerThreads.SyncRoot) | ||
734 | { | ||
735 | if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) | ||
736 | { | ||
737 | // Inform that the thread is quiting and then quit. | ||
738 | // This method must be called within this lock or else | ||
739 | // more threads will quit and the thread pool will go | ||
740 | // below the lower limit. | ||
741 | InformCompleted(); | ||
742 | break; | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | |||
747 | // Wait for a work item, shutdown, or timeout | ||
748 | WorkItem workItem = Dequeue(); | ||
749 | |||
750 | // Update the last time this thread was seen alive. | ||
751 | // It's good for debugging. | ||
752 | CurrentThreadEntry.IAmAlive(); | ||
753 | |||
754 | // On timeout or shut down. | ||
755 | if (null == workItem) | ||
756 | { | ||
757 | // Double lock for quit. | ||
758 | if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) | ||
759 | { | ||
760 | lock(_workerThreads.SyncRoot) | ||
761 | { | ||
762 | if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) | ||
763 | { | ||
764 | // Inform that the thread is quiting and then quit. | ||
765 | // This method must be called within this lock or else | ||
766 | // more threads will quit and the thread pool will go | ||
767 | // below the lower limit. | ||
768 | InformCompleted(); | ||
769 | break; | ||
770 | } | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | // If we didn't quit then skip to the next iteration. | ||
776 | if (null == workItem) | ||
777 | { | ||
778 | continue; | ||
779 | } | ||
780 | |||
781 | try | ||
782 | { | ||
783 | // Initialize the value to false | ||
784 | bInUseWorkerThreadsWasIncremented = false; | ||
785 | |||
786 | // Set the Current Work Item of the thread. | ||
787 | // Store the Current Work Item before the workItem.StartingWorkItem() is called, | ||
788 | // so WorkItem.Cancel can work when the work item is between InQueue and InProgress | ||
789 | // states. | ||
790 | // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() | ||
791 | // (work item is in InQueue state) then workItem.StartingWorkItem() will return false. | ||
792 | // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then | ||
793 | // (work item is in InProgress state) then the thread will be aborted | ||
794 | CurrentThreadEntry.CurrentWorkItem = workItem; | ||
795 | |||
796 | // Change the state of the work item to 'in progress' if possible. | ||
797 | // We do it here so if the work item has been canceled we won't | ||
798 | // increment the _inUseWorkerThreads. | ||
799 | // The cancel mechanism doesn't delete items from the queue, | ||
800 | // it marks the work item as canceled, and when the work item | ||
801 | // is dequeued, we just skip it. | ||
802 | // If the post execute of work item is set to always or to | ||
803 | // call when the work item is canceled then the StartingWorkItem() | ||
804 | // will return true, so the post execute can run. | ||
805 | if (!workItem.StartingWorkItem()) | ||
806 | { | ||
807 | continue; | ||
808 | } | ||
809 | |||
810 | // Execute the callback. Make sure to accurately | ||
811 | // record how many callbacks are currently executing. | ||
812 | int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); | ||
813 | _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); | ||
814 | _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); | ||
815 | |||
816 | // Mark that the _inUseWorkerThreads incremented, so in the finally{} | ||
817 | // statement we will decrement it correctly. | ||
818 | bInUseWorkerThreadsWasIncremented = true; | ||
819 | |||
820 | workItem.FireWorkItemStarted(); | ||
821 | |||
822 | ExecuteWorkItem(workItem); | ||
823 | } | ||
824 | catch(Exception ex) | ||
825 | { | ||
826 | ex.GetHashCode(); | ||
827 | // Do nothing | ||
828 | } | ||
829 | finally | ||
830 | { | ||
831 | workItem.DisposeOfState(); | ||
832 | |||
833 | // Set the CurrentWorkItem to null, since we | ||
834 | // no longer run user's code. | ||
835 | CurrentThreadEntry.CurrentWorkItem = null; | ||
836 | |||
837 | // Decrement the _inUseWorkerThreads only if we had | ||
838 | // incremented it. Note the cancelled work items don't | ||
839 | // increment _inUseWorkerThreads. | ||
840 | if (bInUseWorkerThreadsWasIncremented) | ||
841 | { | ||
842 | int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); | ||
843 | _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); | ||
844 | _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); | ||
845 | } | ||
846 | |||
847 | // Notify that the work item has been completed. | ||
848 | // WorkItemsGroup may enqueue their next work item. | ||
849 | workItem.FireWorkItemCompleted(); | ||
850 | |||
851 | // Decrement the number of work items here so the idle | ||
852 | // ManualResetEvent won't fluctuate. | ||
853 | DecrementWorkItemsCount(); | ||
854 | } | ||
855 | } | ||
856 | } | ||
857 | catch(ThreadAbortException tae) | ||
858 | { | ||
859 | tae.GetHashCode(); | ||
860 | // Handle the abort exception gracfully. | ||
861 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
862 | Thread.ResetAbort(); | ||
863 | #endif | ||
864 | } | ||
865 | catch(Exception e) | ||
866 | { | ||
867 | Debug.Assert(null != e); | ||
868 | } | ||
869 | finally | ||
870 | { | ||
871 | InformCompleted(); | ||
872 | FireOnThreadTermination(); | ||
873 | } | ||
874 | } | ||
875 | |||
876 | private void ExecuteWorkItem(WorkItem workItem) | ||
877 | { | ||
878 | _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); | ||
879 | _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); | ||
880 | try | ||
881 | { | ||
882 | workItem.Execute(); | ||
883 | } | ||
884 | finally | ||
885 | { | ||
886 | _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); | ||
887 | _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); | ||
888 | } | ||
889 | } | ||
890 | |||
891 | |||
892 | #endregion | ||
893 | |||
894 | #region Public Methods | ||
895 | |||
896 | private void ValidateWaitForIdle() | ||
897 | { | ||
898 | if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this) | ||
899 | { | ||
900 | throw new NotSupportedException( | ||
901 | "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); | ||
902 | } | ||
903 | } | ||
904 | |||
905 | internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) | ||
906 | { | ||
907 | if (null == CurrentThreadEntry) | ||
908 | { | ||
909 | return; | ||
910 | } | ||
911 | |||
912 | WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; | ||
913 | ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); | ||
914 | if ((null != workItemsGroup) && | ||
915 | (null != workItem) && | ||
916 | CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) | ||
917 | { | ||
918 | throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); | ||
919 | } | ||
920 | } | ||
921 | |||
922 | [MethodImpl(MethodImplOptions.NoInlining)] | ||
923 | private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) | ||
924 | { | ||
925 | if ((null != workItemsGroup) && | ||
926 | (null != workItem) && | ||
927 | workItem.WasQueuedBy(workItemsGroup)) | ||
928 | { | ||
929 | throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | /// <summary> | ||
934 | /// Force the SmartThreadPool to shutdown | ||
935 | /// </summary> | ||
936 | public void Shutdown() | ||
937 | { | ||
938 | Shutdown(true, 0); | ||
939 | } | ||
940 | |||
941 | /// <summary> | ||
942 | /// Force the SmartThreadPool to shutdown with timeout | ||
943 | /// </summary> | ||
944 | public void Shutdown(bool forceAbort, TimeSpan timeout) | ||
945 | { | ||
946 | Shutdown(forceAbort, (int)timeout.TotalMilliseconds); | ||
947 | } | ||
948 | |||
949 | /// <summary> | ||
950 | /// Empties the queue of work items and abort the threads in the pool. | ||
951 | /// </summary> | ||
952 | public void Shutdown(bool forceAbort, int millisecondsTimeout) | ||
953 | { | ||
954 | ValidateNotDisposed(); | ||
955 | |||
956 | ISTPInstancePerformanceCounters pcs = _windowsPCs; | ||
957 | |||
958 | if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) | ||
959 | { | ||
960 | // Set the _pcs to "null" to stop updating the performance | ||
961 | // counters | ||
962 | _windowsPCs = NullSTPInstancePerformanceCounters.Instance; | ||
963 | |||
964 | pcs.Dispose(); | ||
965 | } | ||
966 | |||
967 | Thread [] threads; | ||
968 | lock(_workerThreads.SyncRoot) | ||
969 | { | ||
970 | // Shutdown the work items queue | ||
971 | _workItemsQueue.Dispose(); | ||
972 | |||
973 | // Signal the threads to exit | ||
974 | _shutdown = true; | ||
975 | _shuttingDownEvent.Set(); | ||
976 | |||
977 | // Make a copy of the threads' references in the pool | ||
978 | threads = new Thread [_workerThreads.Count]; | ||
979 | _workerThreads.Keys.CopyTo(threads, 0); | ||
980 | } | ||
981 | |||
982 | int millisecondsLeft = millisecondsTimeout; | ||
983 | Stopwatch stopwatch = Stopwatch.StartNew(); | ||
984 | //DateTime start = DateTime.UtcNow; | ||
985 | bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); | ||
986 | bool timeout = false; | ||
987 | |||
988 | // Each iteration we update the time left for the timeout. | ||
989 | foreach(Thread thread in threads) | ||
990 | { | ||
991 | // Join don't work with negative numbers | ||
992 | if (!waitInfinitely && (millisecondsLeft < 0)) | ||
993 | { | ||
994 | timeout = true; | ||
995 | break; | ||
996 | } | ||
997 | |||
998 | // Wait for the thread to terminate | ||
999 | bool success = thread.Join(millisecondsLeft); | ||
1000 | if(!success) | ||
1001 | { | ||
1002 | timeout = true; | ||
1003 | break; | ||
1004 | } | ||
1005 | |||
1006 | if(!waitInfinitely) | ||
1007 | { | ||
1008 | // Update the time left to wait | ||
1009 | //TimeSpan ts = DateTime.UtcNow - start; | ||
1010 | millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | if (timeout && forceAbort) | ||
1015 | { | ||
1016 | // Abort the threads in the pool | ||
1017 | foreach(Thread thread in threads) | ||
1018 | { | ||
1019 | |||
1020 | if ((thread != null) | ||
1021 | #if !(_WINDOWS_CE) | ||
1022 | && thread.IsAlive | ||
1023 | #endif | ||
1024 | ) | ||
1025 | { | ||
1026 | try | ||
1027 | { | ||
1028 | thread.Abort(); // Shutdown | ||
1029 | } | ||
1030 | catch(SecurityException e) | ||
1031 | { | ||
1032 | e.GetHashCode(); | ||
1033 | } | ||
1034 | catch(ThreadStateException ex) | ||
1035 | { | ||
1036 | ex.GetHashCode(); | ||
1037 | // In case the thread has been terminated | ||
1038 | // after the check if it is alive. | ||
1039 | } | ||
1040 | } | ||
1041 | } | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | /// <summary> | ||
1046 | /// Wait for all work items to complete | ||
1047 | /// </summary> | ||
1048 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1049 | /// <returns> | ||
1050 | /// true when every work item in workItemResults has completed; otherwise false. | ||
1051 | /// </returns> | ||
1052 | public static bool WaitAll( | ||
1053 | IWaitableResult [] waitableResults) | ||
1054 | { | ||
1055 | return WaitAll(waitableResults, Timeout.Infinite, true); | ||
1056 | } | ||
1057 | |||
1058 | /// <summary> | ||
1059 | /// Wait for all work items to complete | ||
1060 | /// </summary> | ||
1061 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1062 | /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> | ||
1063 | /// <param name="exitContext"> | ||
1064 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1065 | /// </param> | ||
1066 | /// <returns> | ||
1067 | /// true when every work item in workItemResults has completed; otherwise false. | ||
1068 | /// </returns> | ||
1069 | public static bool WaitAll( | ||
1070 | IWaitableResult [] waitableResults, | ||
1071 | TimeSpan timeout, | ||
1072 | bool exitContext) | ||
1073 | { | ||
1074 | return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); | ||
1075 | } | ||
1076 | |||
1077 | /// <summary> | ||
1078 | /// Wait for all work items to complete | ||
1079 | /// </summary> | ||
1080 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1081 | /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> | ||
1082 | /// <param name="exitContext"> | ||
1083 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1084 | /// </param> | ||
1085 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | ||
1086 | /// <returns> | ||
1087 | /// true when every work item in workItemResults has completed; otherwise false. | ||
1088 | /// </returns> | ||
1089 | public static bool WaitAll( | ||
1090 | IWaitableResult[] waitableResults, | ||
1091 | TimeSpan timeout, | ||
1092 | bool exitContext, | ||
1093 | WaitHandle cancelWaitHandle) | ||
1094 | { | ||
1095 | return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); | ||
1096 | } | ||
1097 | |||
1098 | /// <summary> | ||
1099 | /// Wait for all work items to complete | ||
1100 | /// </summary> | ||
1101 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1102 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | ||
1103 | /// <param name="exitContext"> | ||
1104 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1105 | /// </param> | ||
1106 | /// <returns> | ||
1107 | /// true when every work item in workItemResults has completed; otherwise false. | ||
1108 | /// </returns> | ||
1109 | public static bool WaitAll( | ||
1110 | IWaitableResult [] waitableResults, | ||
1111 | int millisecondsTimeout, | ||
1112 | bool exitContext) | ||
1113 | { | ||
1114 | return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); | ||
1115 | } | ||
1116 | |||
1117 | /// <summary> | ||
1118 | /// Wait for all work items to complete | ||
1119 | /// </summary> | ||
1120 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1121 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | ||
1122 | /// <param name="exitContext"> | ||
1123 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1124 | /// </param> | ||
1125 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | ||
1126 | /// <returns> | ||
1127 | /// true when every work item in workItemResults has completed; otherwise false. | ||
1128 | /// </returns> | ||
1129 | public static bool WaitAll( | ||
1130 | IWaitableResult[] waitableResults, | ||
1131 | int millisecondsTimeout, | ||
1132 | bool exitContext, | ||
1133 | WaitHandle cancelWaitHandle) | ||
1134 | { | ||
1135 | return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | /// <summary> | ||
1140 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | ||
1141 | /// </summary> | ||
1142 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1143 | /// <returns> | ||
1144 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. | ||
1145 | /// </returns> | ||
1146 | public static int WaitAny( | ||
1147 | IWaitableResult [] waitableResults) | ||
1148 | { | ||
1149 | return WaitAny(waitableResults, Timeout.Infinite, true); | ||
1150 | } | ||
1151 | |||
1152 | /// <summary> | ||
1153 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | ||
1154 | /// </summary> | ||
1155 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1156 | /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> | ||
1157 | /// <param name="exitContext"> | ||
1158 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1159 | /// </param> | ||
1160 | /// <returns> | ||
1161 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. | ||
1162 | /// </returns> | ||
1163 | public static int WaitAny( | ||
1164 | IWaitableResult[] waitableResults, | ||
1165 | TimeSpan timeout, | ||
1166 | bool exitContext) | ||
1167 | { | ||
1168 | return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext); | ||
1169 | } | ||
1170 | |||
1171 | /// <summary> | ||
1172 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | ||
1173 | /// </summary> | ||
1174 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1175 | /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> | ||
1176 | /// <param name="exitContext"> | ||
1177 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1178 | /// </param> | ||
1179 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | ||
1180 | /// <returns> | ||
1181 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. | ||
1182 | /// </returns> | ||
1183 | public static int WaitAny( | ||
1184 | IWaitableResult [] waitableResults, | ||
1185 | TimeSpan timeout, | ||
1186 | bool exitContext, | ||
1187 | WaitHandle cancelWaitHandle) | ||
1188 | { | ||
1189 | return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); | ||
1190 | } | ||
1191 | |||
1192 | /// <summary> | ||
1193 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | ||
1194 | /// </summary> | ||
1195 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1196 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | ||
1197 | /// <param name="exitContext"> | ||
1198 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1199 | /// </param> | ||
1200 | /// <returns> | ||
1201 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. | ||
1202 | /// </returns> | ||
1203 | public static int WaitAny( | ||
1204 | IWaitableResult [] waitableResults, | ||
1205 | int millisecondsTimeout, | ||
1206 | bool exitContext) | ||
1207 | { | ||
1208 | return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); | ||
1209 | } | ||
1210 | |||
1211 | /// <summary> | ||
1212 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | ||
1213 | /// </summary> | ||
1214 | /// <param name="waitableResults">Array of work item result objects</param> | ||
1215 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | ||
1216 | /// <param name="exitContext"> | ||
1217 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
1218 | /// </param> | ||
1219 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | ||
1220 | /// <returns> | ||
1221 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. | ||
1222 | /// </returns> | ||
1223 | public static int WaitAny( | ||
1224 | IWaitableResult [] waitableResults, | ||
1225 | int millisecondsTimeout, | ||
1226 | bool exitContext, | ||
1227 | WaitHandle cancelWaitHandle) | ||
1228 | { | ||
1229 | return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); | ||
1230 | } | ||
1231 | |||
1232 | /// <summary> | ||
1233 | /// Creates a new WorkItemsGroup. | ||
1234 | /// </summary> | ||
1235 | /// <param name="concurrency">The number of work items that can be run concurrently</param> | ||
1236 | /// <returns>A reference to the WorkItemsGroup</returns> | ||
1237 | public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) | ||
1238 | { | ||
1239 | IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); | ||
1240 | return workItemsGroup; | ||
1241 | } | ||
1242 | |||
1243 | /// <summary> | ||
1244 | /// Creates a new WorkItemsGroup. | ||
1245 | /// </summary> | ||
1246 | /// <param name="concurrency">The number of work items that can be run concurrently</param> | ||
1247 | /// <param name="wigStartInfo">A WorkItemsGroup configuration that overrides the default behavior</param> | ||
1248 | /// <returns>A reference to the WorkItemsGroup</returns> | ||
1249 | public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) | ||
1250 | { | ||
1251 | IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); | ||
1252 | return workItemsGroup; | ||
1253 | } | ||
1254 | |||
1255 | #region Fire Thread's Events | ||
1256 | |||
1257 | private void FireOnThreadInitialization() | ||
1258 | { | ||
1259 | if (null != _onThreadInitialization) | ||
1260 | { | ||
1261 | foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList()) | ||
1262 | { | ||
1263 | try | ||
1264 | { | ||
1265 | tih(); | ||
1266 | } | ||
1267 | catch (Exception e) | ||
1268 | { | ||
1269 | e.GetHashCode(); | ||
1270 | Debug.Assert(false); | ||
1271 | throw; | ||
1272 | } | ||
1273 | } | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | private void FireOnThreadTermination() | ||
1278 | { | ||
1279 | if (null != _onThreadTermination) | ||
1280 | { | ||
1281 | foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList()) | ||
1282 | { | ||
1283 | try | ||
1284 | { | ||
1285 | tth(); | ||
1286 | } | ||
1287 | catch (Exception e) | ||
1288 | { | ||
1289 | e.GetHashCode(); | ||
1290 | Debug.Assert(false); | ||
1291 | throw; | ||
1292 | } | ||
1293 | } | ||
1294 | } | ||
1295 | } | ||
1296 | |||
1297 | #endregion | ||
1298 | |||
1299 | /// <summary> | ||
1300 | /// This event is fired when a thread is created. | ||
1301 | /// Use it to initialize a thread before the work items use it. | ||
1302 | /// </summary> | ||
1303 | public event ThreadInitializationHandler OnThreadInitialization | ||
1304 | { | ||
1305 | add { _onThreadInitialization += value; } | ||
1306 | remove { _onThreadInitialization -= value; } | ||
1307 | } | ||
1308 | |||
1309 | /// <summary> | ||
1310 | /// This event is fired when a thread is terminating. | ||
1311 | /// Use it for cleanup. | ||
1312 | /// </summary> | ||
1313 | public event ThreadTerminationHandler OnThreadTermination | ||
1314 | { | ||
1315 | add { _onThreadTermination += value; } | ||
1316 | remove { _onThreadTermination -= value; } | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig) | ||
1321 | { | ||
1322 | foreach (ThreadEntry threadEntry in _workerThreads.Values) | ||
1323 | { | ||
1324 | WorkItem workItem = threadEntry.CurrentWorkItem; | ||
1325 | if (null != workItem && | ||
1326 | workItem.WasQueuedBy(wig) && | ||
1327 | !workItem.IsCanceled) | ||
1328 | { | ||
1329 | threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); | ||
1330 | } | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | |||
1335 | |||
1336 | #endregion | ||
1337 | |||
1338 | #region Properties | ||
1339 | |||
1340 | /// <summary> | ||
1341 | /// Get/Set the lower limit of threads in the pool. | ||
1342 | /// </summary> | ||
1343 | public int MinThreads | ||
1344 | { | ||
1345 | get | ||
1346 | { | ||
1347 | ValidateNotDisposed(); | ||
1348 | return _stpStartInfo.MinWorkerThreads; | ||
1349 | } | ||
1350 | set | ||
1351 | { | ||
1352 | Debug.Assert(value >= 0); | ||
1353 | Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads); | ||
1354 | if (_stpStartInfo.MaxWorkerThreads < value) | ||
1355 | { | ||
1356 | _stpStartInfo.MaxWorkerThreads = value; | ||
1357 | } | ||
1358 | _stpStartInfo.MinWorkerThreads = value; | ||
1359 | StartOptimalNumberOfThreads(); | ||
1360 | } | ||
1361 | } | ||
1362 | |||
1363 | /// <summary> | ||
1364 | /// Get/Set the upper limit of threads in the pool. | ||
1365 | /// </summary> | ||
1366 | public int MaxThreads | ||
1367 | { | ||
1368 | get | ||
1369 | { | ||
1370 | ValidateNotDisposed(); | ||
1371 | return _stpStartInfo.MaxWorkerThreads; | ||
1372 | } | ||
1373 | |||
1374 | set | ||
1375 | { | ||
1376 | Debug.Assert(value > 0); | ||
1377 | Debug.Assert(value >= _stpStartInfo.MinWorkerThreads); | ||
1378 | if (_stpStartInfo.MinWorkerThreads > value) | ||
1379 | { | ||
1380 | _stpStartInfo.MinWorkerThreads = value; | ||
1381 | } | ||
1382 | _stpStartInfo.MaxWorkerThreads = value; | ||
1383 | StartOptimalNumberOfThreads(); | ||
1384 | } | ||
1385 | } | ||
1386 | /// <summary> | ||
1387 | /// Get the number of threads in the thread pool. | ||
1388 | /// Should be between the lower and the upper limits. | ||
1389 | /// </summary> | ||
1390 | public int ActiveThreads | ||
1391 | { | ||
1392 | get | ||
1393 | { | ||
1394 | ValidateNotDisposed(); | ||
1395 | return _workerThreads.Count; | ||
1396 | } | ||
1397 | } | ||
1398 | |||
1399 | /// <summary> | ||
1400 | /// Get the number of busy (not idle) threads in the thread pool. | ||
1401 | /// </summary> | ||
1402 | public int InUseThreads | ||
1403 | { | ||
1404 | get | ||
1405 | { | ||
1406 | ValidateNotDisposed(); | ||
1407 | return _inUseWorkerThreads; | ||
1408 | } | ||
1409 | } | ||
1410 | |||
1411 | /// <summary> | ||
1412 | /// Returns true if the current running work item has been cancelled. | ||
1413 | /// Must be used within the work item's callback method. | ||
1414 | /// The work item should sample this value in order to know if it | ||
1415 | /// needs to quit before its completion. | ||
1416 | /// </summary> | ||
1417 | public static bool IsWorkItemCanceled | ||
1418 | { | ||
1419 | get | ||
1420 | { | ||
1421 | return CurrentThreadEntry.CurrentWorkItem.IsCanceled; | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | /// <summary> | ||
1426 | /// Checks if the work item has been cancelled, and if yes then abort the thread. | ||
1427 | /// Can be used with Cancel and timeout | ||
1428 | /// </summary> | ||
1429 | public static void AbortOnWorkItemCancel() | ||
1430 | { | ||
1431 | if (IsWorkItemCanceled) | ||
1432 | { | ||
1433 | Thread.CurrentThread.Abort(); | ||
1434 | } | ||
1435 | } | ||
1436 | |||
1437 | /// <summary> | ||
1438 | /// Thread Pool start information (readonly) | ||
1439 | /// </summary> | ||
1440 | public STPStartInfo STPStartInfo | ||
1441 | { | ||
1442 | get | ||
1443 | { | ||
1444 | return _stpStartInfo.AsReadOnly(); | ||
1445 | } | ||
1446 | } | ||
1447 | |||
1448 | public bool IsShuttingdown | ||
1449 | { | ||
1450 | get { return _shutdown; } | ||
1451 | } | ||
1452 | |||
1453 | /// <summary> | ||
1454 | /// Return the local calculated performance counters | ||
1455 | /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true. | ||
1456 | /// </summary> | ||
1457 | public ISTPPerformanceCountersReader PerformanceCountersReader | ||
1458 | { | ||
1459 | get { return (ISTPPerformanceCountersReader)_localPCs; } | ||
1460 | } | ||
1461 | |||
1462 | #endregion | ||
1463 | |||
1464 | #region IDisposable Members | ||
1465 | |||
1466 | public void Dispose() | ||
1467 | { | ||
1468 | if (!_isDisposed) | ||
1469 | { | ||
1470 | if (!_shutdown) | ||
1471 | { | ||
1472 | Shutdown(); | ||
1473 | } | ||
1474 | |||
1475 | if (null != _shuttingDownEvent) | ||
1476 | { | ||
1477 | _shuttingDownEvent.Close(); | ||
1478 | _shuttingDownEvent = null; | ||
1479 | } | ||
1480 | _workerThreads.Clear(); | ||
1481 | |||
1482 | if (null != _isIdleWaitHandle) | ||
1483 | { | ||
1484 | _isIdleWaitHandle.Close(); | ||
1485 | _isIdleWaitHandle = null; | ||
1486 | } | ||
1487 | |||
1488 | if (_stpStartInfo.EnableLocalPerformanceCounters) | ||
1489 | _localPCs.Dispose(); | ||
1490 | |||
1491 | _isDisposed = true; | ||
1492 | } | ||
1493 | } | ||
1494 | |||
1495 | private void ValidateNotDisposed() | ||
1496 | { | ||
1497 | if(_isDisposed) | ||
1498 | { | ||
1499 | throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); | ||
1500 | } | ||
1501 | } | ||
1502 | #endregion | ||
1503 | |||
1504 | #region WorkItemsGroupBase Overrides | ||
1505 | |||
1506 | /// <summary> | ||
1507 | /// Get/Set the maximum number of work items that execute cocurrency on the thread pool | ||
1508 | /// </summary> | ||
1509 | public override int Concurrency | ||
1510 | { | ||
1511 | get { return MaxThreads; } | ||
1512 | set { MaxThreads = value; } | ||
1513 | } | ||
1514 | |||
1515 | /// <summary> | ||
1516 | /// Get the number of work items in the queue. | ||
1517 | /// </summary> | ||
1518 | public override int WaitingCallbacks | ||
1519 | { | ||
1520 | get | ||
1521 | { | ||
1522 | ValidateNotDisposed(); | ||
1523 | return _workItemsQueue.Count; | ||
1524 | } | ||
1525 | } | ||
1526 | |||
1527 | /// <summary> | ||
1528 | /// Get an array with all the state objects of the currently running items. | ||
1529 | /// The array represents a snap shot and impact performance. | ||
1530 | /// </summary> | ||
1531 | public override object[] GetStates() | ||
1532 | { | ||
1533 | object[] states = _workItemsQueue.GetStates(); | ||
1534 | return states; | ||
1535 | } | ||
1536 | |||
1537 | /// <summary> | ||
1538 | /// WorkItemsGroup start information (readonly) | ||
1539 | /// </summary> | ||
1540 | public override WIGStartInfo WIGStartInfo | ||
1541 | { | ||
1542 | get { return _stpStartInfo.AsReadOnly(); } | ||
1543 | } | ||
1544 | |||
1545 | /// <summary> | ||
1546 | /// Start the thread pool if it was started suspended. | ||
1547 | /// If it is already running, this method is ignored. | ||
1548 | /// </summary> | ||
1549 | public override void Start() | ||
1550 | { | ||
1551 | if (!_isSuspended) | ||
1552 | { | ||
1553 | return; | ||
1554 | } | ||
1555 | _isSuspended = false; | ||
1556 | |||
1557 | ICollection workItemsGroups = _workItemsGroups.Values; | ||
1558 | foreach (WorkItemsGroup workItemsGroup in workItemsGroups) | ||
1559 | { | ||
1560 | workItemsGroup.OnSTPIsStarting(); | ||
1561 | } | ||
1562 | |||
1563 | StartOptimalNumberOfThreads(); | ||
1564 | } | ||
1565 | |||
1566 | /// <summary> | ||
1567 | /// Cancel all work items using thread abortion | ||
1568 | /// </summary> | ||
1569 | /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param> | ||
1570 | public override void Cancel(bool abortExecution) | ||
1571 | { | ||
1572 | _canceledSmartThreadPool.IsCanceled = true; | ||
1573 | _canceledSmartThreadPool = new CanceledWorkItemsGroup(); | ||
1574 | |||
1575 | ICollection workItemsGroups = _workItemsGroups.Values; | ||
1576 | foreach (WorkItemsGroup workItemsGroup in workItemsGroups) | ||
1577 | { | ||
1578 | workItemsGroup.Cancel(abortExecution); | ||
1579 | } | ||
1580 | |||
1581 | if (abortExecution) | ||
1582 | { | ||
1583 | foreach (ThreadEntry threadEntry in _workerThreads.Values) | ||
1584 | { | ||
1585 | WorkItem workItem = threadEntry.CurrentWorkItem; | ||
1586 | if (null != workItem && | ||
1587 | threadEntry.AssociatedSmartThreadPool == this && | ||
1588 | !workItem.IsCanceled) | ||
1589 | { | ||
1590 | threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); | ||
1591 | } | ||
1592 | } | ||
1593 | } | ||
1594 | } | ||
1595 | |||
1596 | /// <summary> | ||
1597 | /// Wait for the thread pool to be idle | ||
1598 | /// </summary> | ||
1599 | public override bool WaitForIdle(int millisecondsTimeout) | ||
1600 | { | ||
1601 | ValidateWaitForIdle(); | ||
1602 | return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); | ||
1603 | } | ||
1604 | |||
1605 | /// <summary> | ||
1606 | /// This event is fired when all work items are completed. | ||
1607 | /// (When IsIdle changes to true) | ||
1608 | /// This event only work on WorkItemsGroup. On SmartThreadPool | ||
1609 | /// it throws the NotImplementedException. | ||
1610 | /// </summary> | ||
1611 | public override event WorkItemsGroupIdleHandler OnIdle | ||
1612 | { | ||
1613 | add | ||
1614 | { | ||
1615 | throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); | ||
1616 | //_onIdle += value; | ||
1617 | } | ||
1618 | remove | ||
1619 | { | ||
1620 | throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); | ||
1621 | //_onIdle -= value; | ||
1622 | } | ||
1623 | } | ||
1624 | |||
1625 | internal override void PreQueueWorkItem() | ||
1626 | { | ||
1627 | ValidateNotDisposed(); | ||
1628 | } | ||
1629 | |||
1630 | #endregion | ||
1631 | |||
1632 | #region Join, Choice, Pipe, etc. | ||
1633 | |||
1634 | /// <summary> | ||
1635 | /// Executes all actions in parallel. | ||
1636 | /// Returns when they all finish. | ||
1637 | /// </summary> | ||
1638 | /// <param name="actions">Actions to execute</param> | ||
1639 | public void Join(IEnumerable<Action> actions) | ||
1640 | { | ||
1641 | WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; | ||
1642 | IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); | ||
1643 | foreach (Action action in actions) | ||
1644 | { | ||
1645 | workItemsGroup.QueueWorkItem(action); | ||
1646 | } | ||
1647 | workItemsGroup.Start(); | ||
1648 | workItemsGroup.WaitForIdle(); | ||
1649 | } | ||
1650 | |||
1651 | /// <summary> | ||
1652 | /// Executes all actions in parallel. | ||
1653 | /// Returns when they all finish. | ||
1654 | /// </summary> | ||
1655 | /// <param name="actions">Actions to execute</param> | ||
1656 | public void Join(params Action[] actions) | ||
1657 | { | ||
1658 | Join((IEnumerable<Action>)actions); | ||
1659 | } | ||
1660 | |||
1661 | private class ChoiceIndex | ||
1662 | { | ||
1663 | public int _index = -1; | ||
1664 | } | ||
1665 | |||
1666 | /// <summary> | ||
1667 | /// Executes all actions in parallel | ||
1668 | /// Returns when the first one completes | ||
1669 | /// </summary> | ||
1670 | /// <param name="actions">Actions to execute</param> | ||
1671 | public int Choice(IEnumerable<Action> actions) | ||
1672 | { | ||
1673 | WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; | ||
1674 | IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); | ||
1675 | |||
1676 | ManualResetEvent anActionCompleted = new ManualResetEvent(false); | ||
1677 | |||
1678 | ChoiceIndex choiceIndex = new ChoiceIndex(); | ||
1679 | |||
1680 | int i = 0; | ||
1681 | foreach (Action action in actions) | ||
1682 | { | ||
1683 | Action act = action; | ||
1684 | int value = i; | ||
1685 | workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); | ||
1686 | ++i; | ||
1687 | } | ||
1688 | workItemsGroup.Start(); | ||
1689 | anActionCompleted.WaitOne(); | ||
1690 | anActionCompleted.Dispose(); | ||
1691 | |||
1692 | return choiceIndex._index; | ||
1693 | } | ||
1694 | |||
1695 | /// <summary> | ||
1696 | /// Executes all actions in parallel | ||
1697 | /// Returns when the first one completes | ||
1698 | /// </summary> | ||
1699 | /// <param name="actions">Actions to execute</param> | ||
1700 | public int Choice(params Action[] actions) | ||
1701 | { | ||
1702 | return Choice((IEnumerable<Action>)actions); | ||
1703 | } | ||
1704 | |||
1705 | /// <summary> | ||
1706 | /// Executes actions in sequence asynchronously. | ||
1707 | /// Returns immediately. | ||
1708 | /// </summary> | ||
1709 | /// <param name="pipeState">A state context that passes </param> | ||
1710 | /// <param name="actions">Actions to execute in the order they should run</param> | ||
1711 | public void Pipe<T>(T pipeState, IEnumerable<Action<T>> actions) | ||
1712 | { | ||
1713 | WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; | ||
1714 | IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo); | ||
1715 | foreach (Action<T> action in actions) | ||
1716 | { | ||
1717 | Action<T> act = action; | ||
1718 | workItemsGroup.QueueWorkItem(() => act(pipeState)); | ||
1719 | } | ||
1720 | workItemsGroup.Start(); | ||
1721 | workItemsGroup.WaitForIdle(); | ||
1722 | } | ||
1723 | |||
1724 | /// <summary> | ||
1725 | /// Executes actions in sequence asynchronously. | ||
1726 | /// Returns immediately. | ||
1727 | /// </summary> | ||
1728 | /// <param name="pipeState"></param> | ||
1729 | /// <param name="actions">Actions to execute in the order they should run</param> | ||
1730 | public void Pipe<T>(T pipeState, params Action<T>[] actions) | ||
1731 | { | ||
1732 | Pipe(pipeState, (IEnumerable<Action<T>>)actions); | ||
1733 | } | ||
1734 | #endregion | ||
1735 | } | ||
1736 | #endregion | ||
1737 | } | ||
diff --git a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs new file mode 100644 index 0000000..0cce19f --- /dev/null +++ b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs | |||
@@ -0,0 +1,89 @@ | |||
1 | using System.Collections.Generic; | ||
2 | |||
3 | namespace Amib.Threading.Internal | ||
4 | { | ||
5 | internal class SynchronizedDictionary<TKey, TValue> | ||
6 | { | ||
7 | private readonly Dictionary<TKey, TValue> _dictionary; | ||
8 | private readonly object _lock; | ||
9 | |||
10 | public SynchronizedDictionary() | ||
11 | { | ||
12 | _lock = new object(); | ||
13 | _dictionary = new Dictionary<TKey, TValue>(); | ||
14 | } | ||
15 | |||
16 | public int Count | ||
17 | { | ||
18 | get { return _dictionary.Count; } | ||
19 | } | ||
20 | |||
21 | public bool Contains(TKey key) | ||
22 | { | ||
23 | lock (_lock) | ||
24 | { | ||
25 | return _dictionary.ContainsKey(key); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | public void Remove(TKey key) | ||
30 | { | ||
31 | lock (_lock) | ||
32 | { | ||
33 | _dictionary.Remove(key); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | public object SyncRoot | ||
38 | { | ||
39 | get { return _lock; } | ||
40 | } | ||
41 | |||
42 | public TValue this[TKey key] | ||
43 | { | ||
44 | get | ||
45 | { | ||
46 | lock (_lock) | ||
47 | { | ||
48 | return _dictionary[key]; | ||
49 | } | ||
50 | } | ||
51 | set | ||
52 | { | ||
53 | lock (_lock) | ||
54 | { | ||
55 | _dictionary[key] = value; | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | public Dictionary<TKey, TValue>.KeyCollection Keys | ||
61 | { | ||
62 | get | ||
63 | { | ||
64 | lock (_lock) | ||
65 | { | ||
66 | return _dictionary.Keys; | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | public Dictionary<TKey, TValue>.ValueCollection Values | ||
72 | { | ||
73 | get | ||
74 | { | ||
75 | lock (_lock) | ||
76 | { | ||
77 | return _dictionary.Values; | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | public void Clear() | ||
82 | { | ||
83 | lock (_lock) | ||
84 | { | ||
85 | _dictionary.Clear(); | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WIGStartInfo.cs b/ThirdParty/SmartThreadPool/WIGStartInfo.cs new file mode 100644 index 0000000..756ac1f --- /dev/null +++ b/ThirdParty/SmartThreadPool/WIGStartInfo.cs | |||
@@ -0,0 +1,171 @@ | |||
1 | using System; | ||
2 | |||
3 | namespace Amib.Threading | ||
4 | { | ||
5 | /// <summary> | ||
6 | /// Summary description for WIGStartInfo. | ||
7 | /// </summary> | ||
8 | public class WIGStartInfo | ||
9 | { | ||
10 | private bool _useCallerCallContext; | ||
11 | private bool _useCallerHttpContext; | ||
12 | private bool _disposeOfStateObjects; | ||
13 | private CallToPostExecute _callToPostExecute; | ||
14 | private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; | ||
15 | private bool _startSuspended; | ||
16 | private WorkItemPriority _workItemPriority; | ||
17 | private bool _fillStateWithArgs; | ||
18 | |||
19 | protected bool _readOnly; | ||
20 | |||
21 | public WIGStartInfo() | ||
22 | { | ||
23 | _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; | ||
24 | _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; | ||
25 | _startSuspended = SmartThreadPool.DefaultStartSuspended; | ||
26 | _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; | ||
27 | _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; | ||
28 | _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; | ||
29 | _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; | ||
30 | _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; | ||
31 | } | ||
32 | |||
33 | public WIGStartInfo(WIGStartInfo wigStartInfo) | ||
34 | { | ||
35 | _useCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
36 | _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
37 | _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
38 | _callToPostExecute = wigStartInfo.CallToPostExecute; | ||
39 | _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; | ||
40 | _workItemPriority = wigStartInfo.WorkItemPriority; | ||
41 | _startSuspended = wigStartInfo.StartSuspended; | ||
42 | _fillStateWithArgs = wigStartInfo.FillStateWithArgs; | ||
43 | } | ||
44 | |||
45 | protected void ThrowIfReadOnly() | ||
46 | { | ||
47 | if (_readOnly) | ||
48 | { | ||
49 | throw new NotSupportedException("This is a readonly instance and set is not supported"); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /// <summary> | ||
54 | /// Get/Set if to use the caller's security context | ||
55 | /// </summary> | ||
56 | public virtual bool UseCallerCallContext | ||
57 | { | ||
58 | get { return _useCallerCallContext; } | ||
59 | set | ||
60 | { | ||
61 | ThrowIfReadOnly(); | ||
62 | _useCallerCallContext = value; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | |||
67 | /// <summary> | ||
68 | /// Get/Set if to use the caller's HTTP context | ||
69 | /// </summary> | ||
70 | public virtual bool UseCallerHttpContext | ||
71 | { | ||
72 | get { return _useCallerHttpContext; } | ||
73 | set | ||
74 | { | ||
75 | ThrowIfReadOnly(); | ||
76 | _useCallerHttpContext = value; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | |||
81 | /// <summary> | ||
82 | /// Get/Set if to dispose of the state object of a work item | ||
83 | /// </summary> | ||
84 | public virtual bool DisposeOfStateObjects | ||
85 | { | ||
86 | get { return _disposeOfStateObjects; } | ||
87 | set | ||
88 | { | ||
89 | ThrowIfReadOnly(); | ||
90 | _disposeOfStateObjects = value; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | |||
95 | /// <summary> | ||
96 | /// Get/Set the run the post execute options | ||
97 | /// </summary> | ||
98 | public virtual CallToPostExecute CallToPostExecute | ||
99 | { | ||
100 | get { return _callToPostExecute; } | ||
101 | set | ||
102 | { | ||
103 | ThrowIfReadOnly(); | ||
104 | _callToPostExecute = value; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | /// <summary> | ||
110 | /// Get/Set the default post execute callback | ||
111 | /// </summary> | ||
112 | public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback | ||
113 | { | ||
114 | get { return _postExecuteWorkItemCallback; } | ||
115 | set | ||
116 | { | ||
117 | ThrowIfReadOnly(); | ||
118 | _postExecuteWorkItemCallback = value; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | |||
123 | /// <summary> | ||
124 | /// Get/Set if the work items execution should be suspended until the Start() | ||
125 | /// method is called. | ||
126 | /// </summary> | ||
127 | public virtual bool StartSuspended | ||
128 | { | ||
129 | get { return _startSuspended; } | ||
130 | set | ||
131 | { | ||
132 | ThrowIfReadOnly(); | ||
133 | _startSuspended = value; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | |||
138 | /// <summary> | ||
139 | /// Get/Set the default priority that a work item gets when it is enqueued | ||
140 | /// </summary> | ||
141 | public virtual WorkItemPriority WorkItemPriority | ||
142 | { | ||
143 | get { return _workItemPriority; } | ||
144 | set { _workItemPriority = value; } | ||
145 | } | ||
146 | |||
147 | /// <summary> | ||
148 | /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the | ||
149 | /// arguments as an object array into the state of the work item. | ||
150 | /// The arguments can be access later by IWorkItemResult.State. | ||
151 | /// </summary> | ||
152 | public virtual bool FillStateWithArgs | ||
153 | { | ||
154 | get { return _fillStateWithArgs; } | ||
155 | set | ||
156 | { | ||
157 | ThrowIfReadOnly(); | ||
158 | _fillStateWithArgs = value; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /// <summary> | ||
163 | /// Get a readonly version of this WIGStartInfo | ||
164 | /// </summary> | ||
165 | /// <returns>Returns a readonly reference to this WIGStartInfoRO</returns> | ||
166 | public WIGStartInfo AsReadOnly() | ||
167 | { | ||
168 | return new WIGStartInfo(this) { _readOnly = true }; | ||
169 | } | ||
170 | } | ||
171 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs new file mode 100644 index 0000000..435a14b --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs | |||
@@ -0,0 +1,190 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Threading; | ||
5 | |||
6 | namespace Amib.Threading.Internal | ||
7 | { | ||
8 | public partial class WorkItem | ||
9 | { | ||
10 | #region WorkItemResult class | ||
11 | |||
12 | private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult | ||
13 | { | ||
14 | /// <summary> | ||
15 | /// A back reference to the work item | ||
16 | /// </summary> | ||
17 | private readonly WorkItem _workItem; | ||
18 | |||
19 | public WorkItemResult(WorkItem workItem) | ||
20 | { | ||
21 | _workItem = workItem; | ||
22 | } | ||
23 | |||
24 | internal WorkItem GetWorkItem() | ||
25 | { | ||
26 | return _workItem; | ||
27 | } | ||
28 | |||
29 | #region IWorkItemResult Members | ||
30 | |||
31 | public bool IsCompleted | ||
32 | { | ||
33 | get | ||
34 | { | ||
35 | return _workItem.IsCompleted; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | public bool IsCanceled | ||
40 | { | ||
41 | get | ||
42 | { | ||
43 | return _workItem.IsCanceled; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | public object GetResult() | ||
48 | { | ||
49 | return _workItem.GetResult(Timeout.Infinite, true, null); | ||
50 | } | ||
51 | |||
52 | public object GetResult(int millisecondsTimeout, bool exitContext) | ||
53 | { | ||
54 | return _workItem.GetResult(millisecondsTimeout, exitContext, null); | ||
55 | } | ||
56 | |||
57 | public object GetResult(TimeSpan timeout, bool exitContext) | ||
58 | { | ||
59 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); | ||
60 | } | ||
61 | |||
62 | public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) | ||
63 | { | ||
64 | return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); | ||
65 | } | ||
66 | |||
67 | public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) | ||
68 | { | ||
69 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); | ||
70 | } | ||
71 | |||
72 | public object GetResult(out Exception e) | ||
73 | { | ||
74 | return _workItem.GetResult(Timeout.Infinite, true, null, out e); | ||
75 | } | ||
76 | |||
77 | public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) | ||
78 | { | ||
79 | return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); | ||
80 | } | ||
81 | |||
82 | public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) | ||
83 | { | ||
84 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); | ||
85 | } | ||
86 | |||
87 | public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) | ||
88 | { | ||
89 | return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); | ||
90 | } | ||
91 | |||
92 | public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) | ||
93 | { | ||
94 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); | ||
95 | } | ||
96 | |||
97 | public bool Cancel() | ||
98 | { | ||
99 | return Cancel(false); | ||
100 | } | ||
101 | |||
102 | public bool Cancel(bool abortExecution) | ||
103 | { | ||
104 | return _workItem.Cancel(abortExecution); | ||
105 | } | ||
106 | |||
107 | public object State | ||
108 | { | ||
109 | get | ||
110 | { | ||
111 | return _workItem._state; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | public WorkItemPriority WorkItemPriority | ||
116 | { | ||
117 | get | ||
118 | { | ||
119 | return _workItem._workItemInfo.WorkItemPriority; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /// <summary> | ||
124 | /// Return the result, same as GetResult() | ||
125 | /// </summary> | ||
126 | public object Result | ||
127 | { | ||
128 | get { return GetResult(); } | ||
129 | } | ||
130 | |||
131 | /// <summary> | ||
132 | /// Returns the exception if occured otherwise returns null. | ||
133 | /// This value is valid only after the work item completed, | ||
134 | /// before that it is always null. | ||
135 | /// </summary> | ||
136 | public object Exception | ||
137 | { | ||
138 | get { return _workItem._exception; } | ||
139 | } | ||
140 | |||
141 | #endregion | ||
142 | |||
143 | #region IInternalWorkItemResult Members | ||
144 | |||
145 | public event WorkItemStateCallback OnWorkItemStarted | ||
146 | { | ||
147 | add | ||
148 | { | ||
149 | _workItem.OnWorkItemStarted += value; | ||
150 | } | ||
151 | remove | ||
152 | { | ||
153 | _workItem.OnWorkItemStarted -= value; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | |||
158 | public event WorkItemStateCallback OnWorkItemCompleted | ||
159 | { | ||
160 | add | ||
161 | { | ||
162 | _workItem.OnWorkItemCompleted += value; | ||
163 | } | ||
164 | remove | ||
165 | { | ||
166 | _workItem.OnWorkItemCompleted -= value; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | #endregion | ||
171 | |||
172 | #region IInternalWorkItemResult Members | ||
173 | |||
174 | public IWorkItemResult GetWorkItemResult() | ||
175 | { | ||
176 | return this; | ||
177 | } | ||
178 | |||
179 | public IWorkItemResult<TResult> GetWorkItemResultT<TResult>() | ||
180 | { | ||
181 | return new WorkItemResultTWrapper<TResult>(this); | ||
182 | } | ||
183 | |||
184 | #endregion | ||
185 | } | ||
186 | |||
187 | #endregion | ||
188 | |||
189 | } | ||
190 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs new file mode 100644 index 0000000..edb8ac0 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItem.cs | |||
@@ -0,0 +1,1002 @@ | |||
1 | using System; | ||
2 | using System.Threading; | ||
3 | using System.Diagnostics; | ||
4 | |||
5 | namespace Amib.Threading.Internal | ||
6 | { | ||
7 | /// <summary> | ||
8 | /// Holds a callback delegate and the state for that delegate. | ||
9 | /// </summary> | ||
10 | public partial class WorkItem : IHasWorkItemPriority | ||
11 | { | ||
12 | #region WorkItemState enum | ||
13 | |||
14 | /// <summary> | ||
15 | /// Indicates the state of the work item in the thread pool | ||
16 | /// </summary> | ||
17 | private enum WorkItemState | ||
18 | { | ||
19 | InQueue = 0, // Nexts: InProgress, Canceled | ||
20 | InProgress = 1, // Nexts: Completed, Canceled | ||
21 | Completed = 2, // Stays Completed | ||
22 | Canceled = 3, // Stays Canceled | ||
23 | } | ||
24 | |||
25 | private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState) | ||
26 | { | ||
27 | bool valid = false; | ||
28 | |||
29 | switch (currentState) | ||
30 | { | ||
31 | case WorkItemState.InQueue: | ||
32 | valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState); | ||
33 | break; | ||
34 | case WorkItemState.InProgress: | ||
35 | valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState); | ||
36 | break; | ||
37 | case WorkItemState.Completed: | ||
38 | case WorkItemState.Canceled: | ||
39 | // Cannot be changed | ||
40 | break; | ||
41 | default: | ||
42 | // Unknown state | ||
43 | Debug.Assert(false); | ||
44 | break; | ||
45 | } | ||
46 | |||
47 | return valid; | ||
48 | } | ||
49 | |||
50 | #endregion | ||
51 | |||
52 | #region Fields | ||
53 | |||
54 | /// <summary> | ||
55 | /// Callback delegate for the callback. | ||
56 | /// </summary> | ||
57 | private readonly WorkItemCallback _callback; | ||
58 | |||
59 | /// <summary> | ||
60 | /// State with which to call the callback delegate. | ||
61 | /// </summary> | ||
62 | private object _state; | ||
63 | |||
64 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
65 | /// <summary> | ||
66 | /// Stores the caller's context | ||
67 | /// </summary> | ||
68 | private readonly CallerThreadContext _callerContext; | ||
69 | #endif | ||
70 | /// <summary> | ||
71 | /// Holds the result of the mehtod | ||
72 | /// </summary> | ||
73 | private object _result; | ||
74 | |||
75 | /// <summary> | ||
76 | /// Hold the exception if the method threw it | ||
77 | /// </summary> | ||
78 | private Exception _exception; | ||
79 | |||
80 | /// <summary> | ||
81 | /// Hold the state of the work item | ||
82 | /// </summary> | ||
83 | private WorkItemState _workItemState; | ||
84 | |||
85 | /// <summary> | ||
86 | /// A ManualResetEvent to indicate that the result is ready | ||
87 | /// </summary> | ||
88 | private ManualResetEvent _workItemCompleted; | ||
89 | |||
90 | /// <summary> | ||
91 | /// A reference count to the _workItemCompleted. | ||
92 | /// When it reaches to zero _workItemCompleted is Closed | ||
93 | /// </summary> | ||
94 | private int _workItemCompletedRefCount; | ||
95 | |||
96 | /// <summary> | ||
97 | /// Represents the result state of the work item | ||
98 | /// </summary> | ||
99 | private readonly WorkItemResult _workItemResult; | ||
100 | |||
101 | /// <summary> | ||
102 | /// Work item info | ||
103 | /// </summary> | ||
104 | private readonly WorkItemInfo _workItemInfo; | ||
105 | |||
106 | /// <summary> | ||
107 | /// Called when the WorkItem starts | ||
108 | /// </summary> | ||
109 | private event WorkItemStateCallback _workItemStartedEvent; | ||
110 | |||
111 | /// <summary> | ||
112 | /// Called when the WorkItem completes | ||
113 | /// </summary> | ||
114 | private event WorkItemStateCallback _workItemCompletedEvent; | ||
115 | |||
116 | /// <summary> | ||
117 | /// A reference to an object that indicates whatever the | ||
118 | /// WorkItemsGroup has been canceled | ||
119 | /// </summary> | ||
120 | private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; | ||
121 | |||
122 | /// <summary> | ||
123 | /// A reference to an object that indicates whatever the | ||
124 | /// SmartThreadPool has been canceled | ||
125 | /// </summary> | ||
126 | private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; | ||
127 | |||
128 | /// <summary> | ||
129 | /// The work item group this work item belong to. | ||
130 | /// </summary> | ||
131 | private readonly IWorkItemsGroup _workItemsGroup; | ||
132 | |||
133 | /// <summary> | ||
134 | /// The thread that executes this workitem. | ||
135 | /// This field is available for the period when the work item is executed, before and after it is null. | ||
136 | /// </summary> | ||
137 | private Thread _executingThread; | ||
138 | |||
139 | /// <summary> | ||
140 | /// The absulote time when the work item will be timeout | ||
141 | /// </summary> | ||
142 | private long _expirationTime; | ||
143 | |||
144 | #region Performance Counter fields | ||
145 | |||
146 | |||
147 | |||
148 | |||
149 | /// <summary> | ||
150 | /// Stores how long the work item waited on the stp queue | ||
151 | /// </summary> | ||
152 | private Stopwatch _waitingOnQueueStopwatch; | ||
153 | |||
154 | /// <summary> | ||
155 | /// Stores how much time it took the work item to execute after it went out of the queue | ||
156 | /// </summary> | ||
157 | private Stopwatch _processingStopwatch; | ||
158 | |||
159 | #endregion | ||
160 | |||
161 | #endregion | ||
162 | |||
163 | #region Properties | ||
164 | |||
165 | public TimeSpan WaitingTime | ||
166 | { | ||
167 | get | ||
168 | { | ||
169 | return _waitingOnQueueStopwatch.Elapsed; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | public TimeSpan ProcessTime | ||
174 | { | ||
175 | get | ||
176 | { | ||
177 | return _processingStopwatch.Elapsed; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | internal WorkItemInfo WorkItemInfo | ||
182 | { | ||
183 | get | ||
184 | { | ||
185 | return _workItemInfo; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | #endregion | ||
190 | |||
191 | #region Construction | ||
192 | |||
193 | /// <summary> | ||
194 | /// Initialize the callback holding object. | ||
195 | /// </summary> | ||
196 | /// <param name="workItemsGroup">The workItemGroup of the workitem</param> | ||
197 | /// <param name="workItemInfo">The WorkItemInfo of te workitem</param> | ||
198 | /// <param name="callback">Callback delegate for the callback.</param> | ||
199 | /// <param name="state">State with which to call the callback delegate.</param> | ||
200 | /// | ||
201 | /// We assume that the WorkItem object is created within the thread | ||
202 | /// that meant to run the callback | ||
203 | public WorkItem( | ||
204 | IWorkItemsGroup workItemsGroup, | ||
205 | WorkItemInfo workItemInfo, | ||
206 | WorkItemCallback callback, | ||
207 | object state) | ||
208 | { | ||
209 | _workItemsGroup = workItemsGroup; | ||
210 | _workItemInfo = workItemInfo; | ||
211 | |||
212 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
213 | if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext) | ||
214 | { | ||
215 | _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext); | ||
216 | } | ||
217 | #endif | ||
218 | |||
219 | _callback = callback; | ||
220 | _state = state; | ||
221 | _workItemResult = new WorkItemResult(this); | ||
222 | Initialize(); | ||
223 | } | ||
224 | |||
225 | internal void Initialize() | ||
226 | { | ||
227 | // The _workItemState is changed directly instead of using the SetWorkItemState | ||
228 | // method since we don't want to go throught IsValidStateTransition. | ||
229 | _workItemState = WorkItemState.InQueue; | ||
230 | |||
231 | _workItemCompleted = null; | ||
232 | _workItemCompletedRefCount = 0; | ||
233 | _waitingOnQueueStopwatch = new Stopwatch(); | ||
234 | _processingStopwatch = new Stopwatch(); | ||
235 | _expirationTime = | ||
236 | _workItemInfo.Timeout > 0 ? | ||
237 | DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond : | ||
238 | long.MaxValue; | ||
239 | } | ||
240 | |||
241 | internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup) | ||
242 | { | ||
243 | return (workItemsGroup == _workItemsGroup); | ||
244 | } | ||
245 | |||
246 | |||
247 | #endregion | ||
248 | |||
249 | #region Methods | ||
250 | |||
251 | internal CanceledWorkItemsGroup CanceledWorkItemsGroup | ||
252 | { | ||
253 | get { return _canceledWorkItemsGroup; } | ||
254 | set { _canceledWorkItemsGroup = value; } | ||
255 | } | ||
256 | |||
257 | internal CanceledWorkItemsGroup CanceledSmartThreadPool | ||
258 | { | ||
259 | get { return _canceledSmartThreadPool; } | ||
260 | set { _canceledSmartThreadPool = value; } | ||
261 | } | ||
262 | |||
263 | /// <summary> | ||
264 | /// Change the state of the work item to in progress if it wasn't canceled. | ||
265 | /// </summary> | ||
266 | /// <returns> | ||
267 | /// Return true on success or false in case the work item was canceled. | ||
268 | /// If the work item needs to run a post execute then the method will return true. | ||
269 | /// </returns> | ||
270 | public bool StartingWorkItem() | ||
271 | { | ||
272 | _waitingOnQueueStopwatch.Stop(); | ||
273 | _processingStopwatch.Start(); | ||
274 | |||
275 | lock (this) | ||
276 | { | ||
277 | if (IsCanceled) | ||
278 | { | ||
279 | bool result = false; | ||
280 | if ((_workItemInfo.PostExecuteWorkItemCallback != null) && | ||
281 | ((_workItemInfo.CallToPostExecute & CallToPostExecute.WhenWorkItemCanceled) == CallToPostExecute.WhenWorkItemCanceled)) | ||
282 | { | ||
283 | result = true; | ||
284 | } | ||
285 | |||
286 | return result; | ||
287 | } | ||
288 | |||
289 | Debug.Assert(WorkItemState.InQueue == GetWorkItemState()); | ||
290 | |||
291 | // No need for a lock yet, only after the state has changed to InProgress | ||
292 | _executingThread = Thread.CurrentThread; | ||
293 | |||
294 | SetWorkItemState(WorkItemState.InProgress); | ||
295 | } | ||
296 | |||
297 | return true; | ||
298 | } | ||
299 | |||
300 | /// <summary> | ||
301 | /// Execute the work item and the post execute | ||
302 | /// </summary> | ||
303 | public void Execute() | ||
304 | { | ||
305 | CallToPostExecute currentCallToPostExecute = 0; | ||
306 | |||
307 | // Execute the work item if we are in the correct state | ||
308 | switch (GetWorkItemState()) | ||
309 | { | ||
310 | case WorkItemState.InProgress: | ||
311 | currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled; | ||
312 | ExecuteWorkItem(); | ||
313 | break; | ||
314 | case WorkItemState.Canceled: | ||
315 | currentCallToPostExecute |= CallToPostExecute.WhenWorkItemCanceled; | ||
316 | break; | ||
317 | default: | ||
318 | Debug.Assert(false); | ||
319 | throw new NotSupportedException(); | ||
320 | } | ||
321 | |||
322 | // Run the post execute as needed | ||
323 | if ((currentCallToPostExecute & _workItemInfo.CallToPostExecute) != 0) | ||
324 | { | ||
325 | PostExecute(); | ||
326 | } | ||
327 | |||
328 | _processingStopwatch.Stop(); | ||
329 | } | ||
330 | |||
331 | internal void FireWorkItemCompleted() | ||
332 | { | ||
333 | try | ||
334 | { | ||
335 | if (null != _workItemCompletedEvent) | ||
336 | { | ||
337 | _workItemCompletedEvent(this); | ||
338 | } | ||
339 | } | ||
340 | catch // Suppress exceptions | ||
341 | { } | ||
342 | } | ||
343 | |||
344 | internal void FireWorkItemStarted() | ||
345 | { | ||
346 | try | ||
347 | { | ||
348 | if (null != _workItemStartedEvent) | ||
349 | { | ||
350 | _workItemStartedEvent(this); | ||
351 | } | ||
352 | } | ||
353 | catch // Suppress exceptions | ||
354 | { } | ||
355 | } | ||
356 | |||
357 | /// <summary> | ||
358 | /// Execute the work item | ||
359 | /// </summary> | ||
360 | private void ExecuteWorkItem() | ||
361 | { | ||
362 | |||
363 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
364 | CallerThreadContext ctc = null; | ||
365 | if (null != _callerContext) | ||
366 | { | ||
367 | ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext); | ||
368 | CallerThreadContext.Apply(_callerContext); | ||
369 | } | ||
370 | #endif | ||
371 | |||
372 | Exception exception = null; | ||
373 | object result = null; | ||
374 | |||
375 | try | ||
376 | { | ||
377 | try | ||
378 | { | ||
379 | result = _callback(_state); | ||
380 | } | ||
381 | catch (Exception e) | ||
382 | { | ||
383 | // Save the exception so we can rethrow it later | ||
384 | exception = e; | ||
385 | } | ||
386 | |||
387 | // Remove the value of the execution thread, so it will be impossible to cancel the work item, | ||
388 | // since it is already completed. | ||
389 | // Cancelling a work item that already completed may cause the abortion of the next work item!!! | ||
390 | Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); | ||
391 | |||
392 | if (null == executionThread) | ||
393 | { | ||
394 | // Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException | ||
395 | Thread.Sleep(60 * 1000); | ||
396 | |||
397 | // If after 1 minute this thread was not aborted then let it continue working. | ||
398 | } | ||
399 | } | ||
400 | // We must treat the ThreadAbortException or else it will be stored in the exception variable | ||
401 | catch (ThreadAbortException tae) | ||
402 | { | ||
403 | tae.GetHashCode(); | ||
404 | // Check if the work item was cancelled | ||
405 | // If we got a ThreadAbortException and the STP is not shutting down, it means the | ||
406 | // work items was cancelled. | ||
407 | if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown) | ||
408 | { | ||
409 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
410 | Thread.ResetAbort(); | ||
411 | #endif | ||
412 | } | ||
413 | } | ||
414 | |||
415 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
416 | if (null != _callerContext) | ||
417 | { | ||
418 | CallerThreadContext.Apply(ctc); | ||
419 | } | ||
420 | #endif | ||
421 | |||
422 | if (!SmartThreadPool.IsWorkItemCanceled) | ||
423 | { | ||
424 | SetResult(result, exception); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /// <summary> | ||
429 | /// Runs the post execute callback | ||
430 | /// </summary> | ||
431 | private void PostExecute() | ||
432 | { | ||
433 | if (null != _workItemInfo.PostExecuteWorkItemCallback) | ||
434 | { | ||
435 | try | ||
436 | { | ||
437 | _workItemInfo.PostExecuteWorkItemCallback(_workItemResult); | ||
438 | } | ||
439 | catch (Exception e) | ||
440 | { | ||
441 | Debug.Assert(null != e); | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | |||
446 | /// <summary> | ||
447 | /// Set the result of the work item to return | ||
448 | /// </summary> | ||
449 | /// <param name="result">The result of the work item</param> | ||
450 | /// <param name="exception">The exception that was throw while the workitem executed, null | ||
451 | /// if there was no exception.</param> | ||
452 | internal void SetResult(object result, Exception exception) | ||
453 | { | ||
454 | _result = result; | ||
455 | _exception = exception; | ||
456 | SignalComplete(false); | ||
457 | } | ||
458 | |||
459 | /// <summary> | ||
460 | /// Returns the work item result | ||
461 | /// </summary> | ||
462 | /// <returns>The work item result</returns> | ||
463 | internal IWorkItemResult GetWorkItemResult() | ||
464 | { | ||
465 | return _workItemResult; | ||
466 | } | ||
467 | |||
468 | /// <summary> | ||
469 | /// Wait for all work items to complete | ||
470 | /// </summary> | ||
471 | /// <param name="waitableResults">Array of work item result objects</param> | ||
472 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | ||
473 | /// <param name="exitContext"> | ||
474 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
475 | /// </param> | ||
476 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | ||
477 | /// <returns> | ||
478 | /// true when every work item in waitableResults has completed; otherwise false. | ||
479 | /// </returns> | ||
480 | internal static bool WaitAll( | ||
481 | IWaitableResult[] waitableResults, | ||
482 | int millisecondsTimeout, | ||
483 | bool exitContext, | ||
484 | WaitHandle cancelWaitHandle) | ||
485 | { | ||
486 | if (0 == waitableResults.Length) | ||
487 | { | ||
488 | return true; | ||
489 | } | ||
490 | |||
491 | bool success; | ||
492 | WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length]; | ||
493 | GetWaitHandles(waitableResults, waitHandles); | ||
494 | |||
495 | if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) | ||
496 | { | ||
497 | success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | success = true; | ||
502 | int millisecondsLeft = millisecondsTimeout; | ||
503 | Stopwatch stopwatch = Stopwatch.StartNew(); | ||
504 | |||
505 | WaitHandle[] whs; | ||
506 | if (null != cancelWaitHandle) | ||
507 | { | ||
508 | whs = new WaitHandle[] { null, cancelWaitHandle }; | ||
509 | } | ||
510 | else | ||
511 | { | ||
512 | whs = new WaitHandle[] { null }; | ||
513 | } | ||
514 | |||
515 | bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); | ||
516 | // Iterate over the wait handles and wait for each one to complete. | ||
517 | // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle | ||
518 | // won't affect it. | ||
519 | // Each iteration we update the time left for the timeout. | ||
520 | for (int i = 0; i < waitableResults.Length; ++i) | ||
521 | { | ||
522 | // WaitAny don't work with negative numbers | ||
523 | if (!waitInfinitely && (millisecondsLeft < 0)) | ||
524 | { | ||
525 | success = false; | ||
526 | break; | ||
527 | } | ||
528 | |||
529 | whs[0] = waitHandles[i]; | ||
530 | int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext); | ||
531 | if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result)) | ||
532 | { | ||
533 | success = false; | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | if (!waitInfinitely) | ||
538 | { | ||
539 | // Update the time left to wait | ||
540 | millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | // Release the wait handles | ||
545 | ReleaseWaitHandles(waitableResults); | ||
546 | |||
547 | return success; | ||
548 | } | ||
549 | |||
550 | /// <summary> | ||
551 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | ||
552 | /// </summary> | ||
553 | /// <param name="waitableResults">Array of work item result objects</param> | ||
554 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | ||
555 | /// <param name="exitContext"> | ||
556 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | ||
557 | /// </param> | ||
558 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | ||
559 | /// <returns> | ||
560 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. | ||
561 | /// </returns> | ||
562 | internal static int WaitAny( | ||
563 | IWaitableResult[] waitableResults, | ||
564 | int millisecondsTimeout, | ||
565 | bool exitContext, | ||
566 | WaitHandle cancelWaitHandle) | ||
567 | { | ||
568 | WaitHandle[] waitHandles; | ||
569 | |||
570 | if (null != cancelWaitHandle) | ||
571 | { | ||
572 | waitHandles = new WaitHandle[waitableResults.Length + 1]; | ||
573 | GetWaitHandles(waitableResults, waitHandles); | ||
574 | waitHandles[waitableResults.Length] = cancelWaitHandle; | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | waitHandles = new WaitHandle[waitableResults.Length]; | ||
579 | GetWaitHandles(waitableResults, waitHandles); | ||
580 | } | ||
581 | |||
582 | int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); | ||
583 | |||
584 | // Treat cancel as timeout | ||
585 | if (null != cancelWaitHandle) | ||
586 | { | ||
587 | if (result == waitableResults.Length) | ||
588 | { | ||
589 | result = STPEventWaitHandle.WaitTimeout; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | ReleaseWaitHandles(waitableResults); | ||
594 | |||
595 | return result; | ||
596 | } | ||
597 | |||
598 | /// <summary> | ||
599 | /// Fill an array of wait handles with the work items wait handles. | ||
600 | /// </summary> | ||
601 | /// <param name="waitableResults">An array of work item results</param> | ||
602 | /// <param name="waitHandles">An array of wait handles to fill</param> | ||
603 | private static void GetWaitHandles( | ||
604 | IWaitableResult[] waitableResults, | ||
605 | WaitHandle[] waitHandles) | ||
606 | { | ||
607 | for (int i = 0; i < waitableResults.Length; ++i) | ||
608 | { | ||
609 | WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult; | ||
610 | Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects"); | ||
611 | |||
612 | waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | /// <summary> | ||
617 | /// Release the work items' wait handles | ||
618 | /// </summary> | ||
619 | /// <param name="waitableResults">An array of work item results</param> | ||
620 | private static void ReleaseWaitHandles(IWaitableResult[] waitableResults) | ||
621 | { | ||
622 | for (int i = 0; i < waitableResults.Length; ++i) | ||
623 | { | ||
624 | WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult(); | ||
625 | |||
626 | wir.GetWorkItem().ReleaseWaitHandle(); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | #endregion | ||
631 | |||
632 | #region Private Members | ||
633 | |||
634 | private WorkItemState GetWorkItemState() | ||
635 | { | ||
636 | lock (this) | ||
637 | { | ||
638 | if (WorkItemState.Completed == _workItemState) | ||
639 | { | ||
640 | return _workItemState; | ||
641 | } | ||
642 | |||
643 | long nowTicks = DateTime.UtcNow.Ticks; | ||
644 | |||
645 | if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime) | ||
646 | { | ||
647 | _workItemState = WorkItemState.Canceled; | ||
648 | } | ||
649 | |||
650 | if (WorkItemState.InProgress == _workItemState) | ||
651 | { | ||
652 | return _workItemState; | ||
653 | } | ||
654 | |||
655 | if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled) | ||
656 | { | ||
657 | return WorkItemState.Canceled; | ||
658 | } | ||
659 | |||
660 | return _workItemState; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | |||
665 | /// <summary> | ||
666 | /// Sets the work item's state | ||
667 | /// </summary> | ||
668 | /// <param name="workItemState">The state to set the work item to</param> | ||
669 | private void SetWorkItemState(WorkItemState workItemState) | ||
670 | { | ||
671 | lock (this) | ||
672 | { | ||
673 | if (IsValidStatesTransition(_workItemState, workItemState)) | ||
674 | { | ||
675 | _workItemState = workItemState; | ||
676 | } | ||
677 | } | ||
678 | } | ||
679 | |||
680 | /// <summary> | ||
681 | /// Signals that work item has been completed or canceled | ||
682 | /// </summary> | ||
683 | /// <param name="canceled">Indicates that the work item has been canceled</param> | ||
684 | private void SignalComplete(bool canceled) | ||
685 | { | ||
686 | SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed); | ||
687 | lock (this) | ||
688 | { | ||
689 | // If someone is waiting then signal. | ||
690 | if (null != _workItemCompleted) | ||
691 | { | ||
692 | _workItemCompleted.Set(); | ||
693 | } | ||
694 | } | ||
695 | } | ||
696 | |||
697 | internal void WorkItemIsQueued() | ||
698 | { | ||
699 | _waitingOnQueueStopwatch.Start(); | ||
700 | } | ||
701 | |||
702 | #endregion | ||
703 | |||
704 | #region Members exposed by WorkItemResult | ||
705 | |||
706 | /// <summary> | ||
707 | /// Cancel the work item if it didn't start running yet. | ||
708 | /// </summary> | ||
709 | /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> | ||
710 | private bool Cancel(bool abortExecution) | ||
711 | { | ||
712 | #if (_WINDOWS_CE) | ||
713 | if(abortExecution) | ||
714 | { | ||
715 | throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature"); | ||
716 | } | ||
717 | #endif | ||
718 | bool success = false; | ||
719 | bool signalComplete = false; | ||
720 | |||
721 | lock (this) | ||
722 | { | ||
723 | switch (GetWorkItemState()) | ||
724 | { | ||
725 | case WorkItemState.Canceled: | ||
726 | //Debug.WriteLine("Work item already canceled"); | ||
727 | if (abortExecution) | ||
728 | { | ||
729 | Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); | ||
730 | if (null != executionThread) | ||
731 | { | ||
732 | executionThread.Abort(); // "Cancel" | ||
733 | // No need to signalComplete, because we already cancelled this work item | ||
734 | // so it already signaled its completion. | ||
735 | //signalComplete = true; | ||
736 | } | ||
737 | } | ||
738 | success = true; | ||
739 | break; | ||
740 | case WorkItemState.Completed: | ||
741 | //Debug.WriteLine("Work item cannot be canceled"); | ||
742 | break; | ||
743 | case WorkItemState.InProgress: | ||
744 | if (abortExecution) | ||
745 | { | ||
746 | Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); | ||
747 | if (null != executionThread) | ||
748 | { | ||
749 | executionThread.Abort(); // "Cancel" | ||
750 | success = true; | ||
751 | signalComplete = true; | ||
752 | } | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | // ************************** | ||
757 | // Stock SmartThreadPool 2.2.3 sets these to true and relies on the thread to check the | ||
758 | // WorkItem cancellation status. However, OpenSimulator uses a different mechanism to notify | ||
759 | // scripts of co-operative termination and the abort code also relies on this method | ||
760 | // returning false in order to implement a small wait. | ||
761 | // | ||
762 | // Therefore, as was the case previously with STP, we will not signal successful cancellation | ||
763 | // here. It's possible that OpenSimulator code could be changed in the future to remove | ||
764 | // the need for this change. | ||
765 | // ************************** | ||
766 | success = false; | ||
767 | signalComplete = false; | ||
768 | } | ||
769 | break; | ||
770 | case WorkItemState.InQueue: | ||
771 | // Signal to the wait for completion that the work | ||
772 | // item has been completed (canceled). There is no | ||
773 | // reason to wait for it to get out of the queue | ||
774 | signalComplete = true; | ||
775 | //Debug.WriteLine("Work item canceled"); | ||
776 | success = true; | ||
777 | break; | ||
778 | } | ||
779 | |||
780 | if (signalComplete) | ||
781 | { | ||
782 | SignalComplete(true); | ||
783 | } | ||
784 | } | ||
785 | return success; | ||
786 | } | ||
787 | |||
788 | /// <summary> | ||
789 | /// Get the result of the work item. | ||
790 | /// If the work item didn't run yet then the caller waits for the result, timeout, or cancel. | ||
791 | /// In case of error the method throws and exception | ||
792 | /// </summary> | ||
793 | /// <returns>The result of the work item</returns> | ||
794 | private object GetResult( | ||
795 | int millisecondsTimeout, | ||
796 | bool exitContext, | ||
797 | WaitHandle cancelWaitHandle) | ||
798 | { | ||
799 | Exception e; | ||
800 | object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); | ||
801 | if (null != e) | ||
802 | { | ||
803 | throw new WorkItemResultException("The work item caused an excpetion, see the inner exception for details", e); | ||
804 | } | ||
805 | return result; | ||
806 | } | ||
807 | |||
808 | /// <summary> | ||
809 | /// Get the result of the work item. | ||
810 | /// If the work item didn't run yet then the caller waits for the result, timeout, or cancel. | ||
811 | /// In case of error the e argument is filled with the exception | ||
812 | /// </summary> | ||
813 | /// <returns>The result of the work item</returns> | ||
814 | private object GetResult( | ||
815 | int millisecondsTimeout, | ||
816 | bool exitContext, | ||
817 | WaitHandle cancelWaitHandle, | ||
818 | out Exception e) | ||
819 | { | ||
820 | e = null; | ||
821 | |||
822 | // Check for cancel | ||
823 | if (WorkItemState.Canceled == GetWorkItemState()) | ||
824 | { | ||
825 | throw new WorkItemCancelException("Work item canceled"); | ||
826 | } | ||
827 | |||
828 | // Check for completion | ||
829 | if (IsCompleted) | ||
830 | { | ||
831 | e = _exception; | ||
832 | return _result; | ||
833 | } | ||
834 | |||
835 | // If no cancelWaitHandle is provided | ||
836 | if (null == cancelWaitHandle) | ||
837 | { | ||
838 | WaitHandle wh = GetWaitHandle(); | ||
839 | |||
840 | bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext); | ||
841 | |||
842 | ReleaseWaitHandle(); | ||
843 | |||
844 | if (timeout) | ||
845 | { | ||
846 | throw new WorkItemTimeoutException("Work item timeout"); | ||
847 | } | ||
848 | } | ||
849 | else | ||
850 | { | ||
851 | WaitHandle wh = GetWaitHandle(); | ||
852 | int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); | ||
853 | ReleaseWaitHandle(); | ||
854 | |||
855 | switch (result) | ||
856 | { | ||
857 | case 0: | ||
858 | // The work item signaled | ||
859 | // Note that the signal could be also as a result of canceling the | ||
860 | // work item (not the get result) | ||
861 | break; | ||
862 | case 1: | ||
863 | case STPEventWaitHandle.WaitTimeout: | ||
864 | throw new WorkItemTimeoutException("Work item timeout"); | ||
865 | default: | ||
866 | Debug.Assert(false); | ||
867 | break; | ||
868 | |||
869 | } | ||
870 | } | ||
871 | |||
872 | // Check for cancel | ||
873 | if (WorkItemState.Canceled == GetWorkItemState()) | ||
874 | { | ||
875 | throw new WorkItemCancelException("Work item canceled"); | ||
876 | } | ||
877 | |||
878 | Debug.Assert(IsCompleted); | ||
879 | |||
880 | e = _exception; | ||
881 | |||
882 | // Return the result | ||
883 | return _result; | ||
884 | } | ||
885 | |||
886 | /// <summary> | ||
887 | /// A wait handle to wait for completion, cancel, or timeout | ||
888 | /// </summary> | ||
889 | private WaitHandle GetWaitHandle() | ||
890 | { | ||
891 | lock (this) | ||
892 | { | ||
893 | if (null == _workItemCompleted) | ||
894 | { | ||
895 | _workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted); | ||
896 | } | ||
897 | ++_workItemCompletedRefCount; | ||
898 | } | ||
899 | return _workItemCompleted; | ||
900 | } | ||
901 | |||
902 | private void ReleaseWaitHandle() | ||
903 | { | ||
904 | lock (this) | ||
905 | { | ||
906 | if (null != _workItemCompleted) | ||
907 | { | ||
908 | --_workItemCompletedRefCount; | ||
909 | if (0 == _workItemCompletedRefCount) | ||
910 | { | ||
911 | _workItemCompleted.Close(); | ||
912 | _workItemCompleted = null; | ||
913 | } | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | /// <summary> | ||
919 | /// Returns true when the work item has completed or canceled | ||
920 | /// </summary> | ||
921 | private bool IsCompleted | ||
922 | { | ||
923 | get | ||
924 | { | ||
925 | lock (this) | ||
926 | { | ||
927 | WorkItemState workItemState = GetWorkItemState(); | ||
928 | return ((workItemState == WorkItemState.Completed) || | ||
929 | (workItemState == WorkItemState.Canceled)); | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | |||
934 | /// <summary> | ||
935 | /// Returns true when the work item has canceled | ||
936 | /// </summary> | ||
937 | public bool IsCanceled | ||
938 | { | ||
939 | get | ||
940 | { | ||
941 | lock (this) | ||
942 | { | ||
943 | return (GetWorkItemState() == WorkItemState.Canceled); | ||
944 | } | ||
945 | } | ||
946 | } | ||
947 | |||
948 | #endregion | ||
949 | |||
950 | #region IHasWorkItemPriority Members | ||
951 | |||
952 | /// <summary> | ||
953 | /// Returns the priority of the work item | ||
954 | /// </summary> | ||
955 | public WorkItemPriority WorkItemPriority | ||
956 | { | ||
957 | get | ||
958 | { | ||
959 | return _workItemInfo.WorkItemPriority; | ||
960 | } | ||
961 | } | ||
962 | |||
963 | #endregion | ||
964 | |||
965 | internal event WorkItemStateCallback OnWorkItemStarted | ||
966 | { | ||
967 | add | ||
968 | { | ||
969 | _workItemStartedEvent += value; | ||
970 | } | ||
971 | remove | ||
972 | { | ||
973 | _workItemStartedEvent -= value; | ||
974 | } | ||
975 | } | ||
976 | |||
977 | internal event WorkItemStateCallback OnWorkItemCompleted | ||
978 | { | ||
979 | add | ||
980 | { | ||
981 | _workItemCompletedEvent += value; | ||
982 | } | ||
983 | remove | ||
984 | { | ||
985 | _workItemCompletedEvent -= value; | ||
986 | } | ||
987 | } | ||
988 | |||
989 | public void DisposeOfState() | ||
990 | { | ||
991 | if (_workItemInfo.DisposeOfStateObjects) | ||
992 | { | ||
993 | IDisposable disp = _state as IDisposable; | ||
994 | if (null != disp) | ||
995 | { | ||
996 | disp.Dispose(); | ||
997 | _state = null; | ||
998 | } | ||
999 | } | ||
1000 | } | ||
1001 | } | ||
1002 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs new file mode 100644 index 0000000..471eb20 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs | |||
@@ -0,0 +1,343 @@ | |||
1 | using System; | ||
2 | |||
3 | namespace Amib.Threading.Internal | ||
4 | { | ||
5 | #region WorkItemFactory class | ||
6 | |||
7 | public class WorkItemFactory | ||
8 | { | ||
9 | /// <summary> | ||
10 | /// Create a new work item | ||
11 | /// </summary> | ||
12 | /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param> | ||
13 | /// <param name="wigStartInfo">Work item group start information</param> | ||
14 | /// <param name="callback">A callback to execute</param> | ||
15 | /// <returns>Returns a work item</returns> | ||
16 | public static WorkItem CreateWorkItem( | ||
17 | IWorkItemsGroup workItemsGroup, | ||
18 | WIGStartInfo wigStartInfo, | ||
19 | WorkItemCallback callback) | ||
20 | { | ||
21 | return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); | ||
22 | } | ||
23 | |||
24 | /// <summary> | ||
25 | /// Create a new work item | ||
26 | /// </summary> | ||
27 | /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param> | ||
28 | /// <param name="wigStartInfo">Work item group start information</param> | ||
29 | /// <param name="callback">A callback to execute</param> | ||
30 | /// <param name="workItemPriority">The priority of the work item</param> | ||
31 | /// <returns>Returns a work item</returns> | ||
32 | public static WorkItem CreateWorkItem( | ||
33 | IWorkItemsGroup workItemsGroup, | ||
34 | WIGStartInfo wigStartInfo, | ||
35 | WorkItemCallback callback, | ||
36 | WorkItemPriority workItemPriority) | ||
37 | { | ||
38 | return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); | ||
39 | } | ||
40 | |||
41 | /// <summary> | ||
42 | /// Create a new work item | ||
43 | /// </summary> | ||
44 | /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param> | ||
45 | /// <param name="wigStartInfo">Work item group start information</param> | ||
46 | /// <param name="workItemInfo">Work item info</param> | ||
47 | /// <param name="callback">A callback to execute</param> | ||
48 | /// <returns>Returns a work item</returns> | ||
49 | public static WorkItem CreateWorkItem( | ||
50 | IWorkItemsGroup workItemsGroup, | ||
51 | WIGStartInfo wigStartInfo, | ||
52 | WorkItemInfo workItemInfo, | ||
53 | WorkItemCallback callback) | ||
54 | { | ||
55 | return CreateWorkItem( | ||
56 | workItemsGroup, | ||
57 | wigStartInfo, | ||
58 | workItemInfo, | ||
59 | callback, | ||
60 | null); | ||
61 | } | ||
62 | |||
63 | /// <summary> | ||
64 | /// Create a new work item | ||
65 | /// </summary> | ||
66 | /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param> | ||
67 | /// <param name="wigStartInfo">Work item group start information</param> | ||
68 | /// <param name="callback">A callback to execute</param> | ||
69 | /// <param name="state"> | ||
70 | /// The context object of the work item. Used for passing arguments to the work item. | ||
71 | /// </param> | ||
72 | /// <returns>Returns a work item</returns> | ||
73 | public static WorkItem CreateWorkItem( | ||
74 | IWorkItemsGroup workItemsGroup, | ||
75 | WIGStartInfo wigStartInfo, | ||
76 | WorkItemCallback callback, | ||
77 | object state) | ||
78 | { | ||
79 | ValidateCallback(callback); | ||
80 | |||
81 | WorkItemInfo workItemInfo = new WorkItemInfo(); | ||
82 | workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
83 | workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
84 | workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; | ||
85 | workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; | ||
86 | workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
87 | workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; | ||
88 | |||
89 | WorkItem workItem = new WorkItem( | ||
90 | workItemsGroup, | ||
91 | workItemInfo, | ||
92 | callback, | ||
93 | state); | ||
94 | return workItem; | ||
95 | } | ||
96 | |||
97 | /// <summary> | ||
98 | /// Create a new work item | ||
99 | /// </summary> | ||
100 | /// <param name="workItemsGroup">The work items group</param> | ||
101 | /// <param name="wigStartInfo">Work item group start information</param> | ||
102 | /// <param name="callback">A callback to execute</param> | ||
103 | /// <param name="state"> | ||
104 | /// The context object of the work item. Used for passing arguments to the work item. | ||
105 | /// </param> | ||
106 | /// <param name="workItemPriority">The work item priority</param> | ||
107 | /// <returns>Returns a work item</returns> | ||
108 | public static WorkItem CreateWorkItem( | ||
109 | IWorkItemsGroup workItemsGroup, | ||
110 | WIGStartInfo wigStartInfo, | ||
111 | WorkItemCallback callback, | ||
112 | object state, | ||
113 | WorkItemPriority workItemPriority) | ||
114 | { | ||
115 | ValidateCallback(callback); | ||
116 | |||
117 | WorkItemInfo workItemInfo = new WorkItemInfo(); | ||
118 | workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
119 | workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
120 | workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; | ||
121 | workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; | ||
122 | workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
123 | workItemInfo.WorkItemPriority = workItemPriority; | ||
124 | |||
125 | WorkItem workItem = new WorkItem( | ||
126 | workItemsGroup, | ||
127 | workItemInfo, | ||
128 | callback, | ||
129 | state); | ||
130 | |||
131 | return workItem; | ||
132 | } | ||
133 | |||
134 | /// <summary> | ||
135 | /// Create a new work item | ||
136 | /// </summary> | ||
137 | /// <param name="workItemsGroup">The work items group</param> | ||
138 | /// <param name="wigStartInfo">Work item group start information</param> | ||
139 | /// <param name="workItemInfo">Work item information</param> | ||
140 | /// <param name="callback">A callback to execute</param> | ||
141 | /// <param name="state"> | ||
142 | /// The context object of the work item. Used for passing arguments to the work item. | ||
143 | /// </param> | ||
144 | /// <returns>Returns a work item</returns> | ||
145 | public static WorkItem CreateWorkItem( | ||
146 | IWorkItemsGroup workItemsGroup, | ||
147 | WIGStartInfo wigStartInfo, | ||
148 | WorkItemInfo workItemInfo, | ||
149 | WorkItemCallback callback, | ||
150 | object state) | ||
151 | { | ||
152 | ValidateCallback(callback); | ||
153 | ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); | ||
154 | |||
155 | WorkItem workItem = new WorkItem( | ||
156 | workItemsGroup, | ||
157 | new WorkItemInfo(workItemInfo), | ||
158 | callback, | ||
159 | state); | ||
160 | |||
161 | return workItem; | ||
162 | } | ||
163 | |||
164 | /// <summary> | ||
165 | /// Create a new work item | ||
166 | /// </summary> | ||
167 | /// <param name="workItemsGroup">The work items group</param> | ||
168 | /// <param name="wigStartInfo">Work item group start information</param> | ||
169 | /// <param name="callback">A callback to execute</param> | ||
170 | /// <param name="state"> | ||
171 | /// The context object of the work item. Used for passing arguments to the work item. | ||
172 | /// </param> | ||
173 | /// <param name="postExecuteWorkItemCallback"> | ||
174 | /// A delegate to call after the callback completion | ||
175 | /// </param> | ||
176 | /// <returns>Returns a work item</returns> | ||
177 | public static WorkItem CreateWorkItem( | ||
178 | IWorkItemsGroup workItemsGroup, | ||
179 | WIGStartInfo wigStartInfo, | ||
180 | WorkItemCallback callback, | ||
181 | object state, | ||
182 | PostExecuteWorkItemCallback postExecuteWorkItemCallback) | ||
183 | { | ||
184 | ValidateCallback(callback); | ||
185 | ValidateCallback(postExecuteWorkItemCallback); | ||
186 | |||
187 | WorkItemInfo workItemInfo = new WorkItemInfo(); | ||
188 | workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
189 | workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
190 | workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; | ||
191 | workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; | ||
192 | workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
193 | workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; | ||
194 | |||
195 | WorkItem workItem = new WorkItem( | ||
196 | workItemsGroup, | ||
197 | workItemInfo, | ||
198 | callback, | ||
199 | state); | ||
200 | |||
201 | return workItem; | ||
202 | } | ||
203 | |||
204 | /// <summary> | ||
205 | /// Create a new work item | ||
206 | /// </summary> | ||
207 | /// <param name="workItemsGroup">The work items group</param> | ||
208 | /// <param name="wigStartInfo">Work item group start information</param> | ||
209 | /// <param name="callback">A callback to execute</param> | ||
210 | /// <param name="state"> | ||
211 | /// The context object of the work item. Used for passing arguments to the work item. | ||
212 | /// </param> | ||
213 | /// <param name="postExecuteWorkItemCallback"> | ||
214 | /// A delegate to call after the callback completion | ||
215 | /// </param> | ||
216 | /// <param name="workItemPriority">The work item priority</param> | ||
217 | /// <returns>Returns a work item</returns> | ||
218 | public static WorkItem CreateWorkItem( | ||
219 | IWorkItemsGroup workItemsGroup, | ||
220 | WIGStartInfo wigStartInfo, | ||
221 | WorkItemCallback callback, | ||
222 | object state, | ||
223 | PostExecuteWorkItemCallback postExecuteWorkItemCallback, | ||
224 | WorkItemPriority workItemPriority) | ||
225 | { | ||
226 | ValidateCallback(callback); | ||
227 | ValidateCallback(postExecuteWorkItemCallback); | ||
228 | |||
229 | WorkItemInfo workItemInfo = new WorkItemInfo(); | ||
230 | workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
231 | workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
232 | workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; | ||
233 | workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; | ||
234 | workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
235 | workItemInfo.WorkItemPriority = workItemPriority; | ||
236 | |||
237 | WorkItem workItem = new WorkItem( | ||
238 | workItemsGroup, | ||
239 | workItemInfo, | ||
240 | callback, | ||
241 | state); | ||
242 | |||
243 | return workItem; | ||
244 | } | ||
245 | |||
246 | /// <summary> | ||
247 | /// Create a new work item | ||
248 | /// </summary> | ||
249 | /// <param name="workItemsGroup">The work items group</param> | ||
250 | /// <param name="wigStartInfo">Work item group start information</param> | ||
251 | /// <param name="callback">A callback to execute</param> | ||
252 | /// <param name="state"> | ||
253 | /// The context object of the work item. Used for passing arguments to the work item. | ||
254 | /// </param> | ||
255 | /// <param name="postExecuteWorkItemCallback"> | ||
256 | /// A delegate to call after the callback completion | ||
257 | /// </param> | ||
258 | /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> | ||
259 | /// <returns>Returns a work item</returns> | ||
260 | public static WorkItem CreateWorkItem( | ||
261 | IWorkItemsGroup workItemsGroup, | ||
262 | WIGStartInfo wigStartInfo, | ||
263 | WorkItemCallback callback, | ||
264 | object state, | ||
265 | PostExecuteWorkItemCallback postExecuteWorkItemCallback, | ||
266 | CallToPostExecute callToPostExecute) | ||
267 | { | ||
268 | ValidateCallback(callback); | ||
269 | ValidateCallback(postExecuteWorkItemCallback); | ||
270 | |||
271 | WorkItemInfo workItemInfo = new WorkItemInfo(); | ||
272 | workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
273 | workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
274 | workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; | ||
275 | workItemInfo.CallToPostExecute = callToPostExecute; | ||
276 | workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
277 | workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; | ||
278 | |||
279 | WorkItem workItem = new WorkItem( | ||
280 | workItemsGroup, | ||
281 | workItemInfo, | ||
282 | callback, | ||
283 | state); | ||
284 | |||
285 | return workItem; | ||
286 | } | ||
287 | |||
288 | /// <summary> | ||
289 | /// Create a new work item | ||
290 | /// </summary> | ||
291 | /// <param name="workItemsGroup">The work items group</param> | ||
292 | /// <param name="wigStartInfo">Work item group start information</param> | ||
293 | /// <param name="callback">A callback to execute</param> | ||
294 | /// <param name="state"> | ||
295 | /// The context object of the work item. Used for passing arguments to the work item. | ||
296 | /// </param> | ||
297 | /// <param name="postExecuteWorkItemCallback"> | ||
298 | /// A delegate to call after the callback completion | ||
299 | /// </param> | ||
300 | /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> | ||
301 | /// <param name="workItemPriority">The work item priority</param> | ||
302 | /// <returns>Returns a work item</returns> | ||
303 | public static WorkItem CreateWorkItem( | ||
304 | IWorkItemsGroup workItemsGroup, | ||
305 | WIGStartInfo wigStartInfo, | ||
306 | WorkItemCallback callback, | ||
307 | object state, | ||
308 | PostExecuteWorkItemCallback postExecuteWorkItemCallback, | ||
309 | CallToPostExecute callToPostExecute, | ||
310 | WorkItemPriority workItemPriority) | ||
311 | { | ||
312 | |||
313 | ValidateCallback(callback); | ||
314 | ValidateCallback(postExecuteWorkItemCallback); | ||
315 | |||
316 | WorkItemInfo workItemInfo = new WorkItemInfo(); | ||
317 | workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; | ||
318 | workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; | ||
319 | workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; | ||
320 | workItemInfo.CallToPostExecute = callToPostExecute; | ||
321 | workItemInfo.WorkItemPriority = workItemPriority; | ||
322 | workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; | ||
323 | |||
324 | WorkItem workItem = new WorkItem( | ||
325 | workItemsGroup, | ||
326 | workItemInfo, | ||
327 | callback, | ||
328 | state); | ||
329 | |||
330 | return workItem; | ||
331 | } | ||
332 | |||
333 | private static void ValidateCallback(Delegate callback) | ||
334 | { | ||
335 | if (callback != null && callback.GetInvocationList().Length > 1) | ||
336 | { | ||
337 | throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | |||
342 | #endregion | ||
343 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs new file mode 100644 index 0000000..5be82a2 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs | |||
@@ -0,0 +1,69 @@ | |||
1 | namespace Amib.Threading | ||
2 | { | ||
3 | #region WorkItemInfo class | ||
4 | |||
5 | /// <summary> | ||
6 | /// Summary description for WorkItemInfo. | ||
7 | /// </summary> | ||
8 | public class WorkItemInfo | ||
9 | { | ||
10 | public WorkItemInfo() | ||
11 | { | ||
12 | UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; | ||
13 | UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; | ||
14 | DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; | ||
15 | CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; | ||
16 | PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; | ||
17 | WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; | ||
18 | } | ||
19 | |||
20 | public WorkItemInfo(WorkItemInfo workItemInfo) | ||
21 | { | ||
22 | UseCallerCallContext = workItemInfo.UseCallerCallContext; | ||
23 | UseCallerHttpContext = workItemInfo.UseCallerHttpContext; | ||
24 | DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; | ||
25 | CallToPostExecute = workItemInfo.CallToPostExecute; | ||
26 | PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; | ||
27 | WorkItemPriority = workItemInfo.WorkItemPriority; | ||
28 | Timeout = workItemInfo.Timeout; | ||
29 | } | ||
30 | |||
31 | /// <summary> | ||
32 | /// Get/Set if to use the caller's security context | ||
33 | /// </summary> | ||
34 | public bool UseCallerCallContext { get; set; } | ||
35 | |||
36 | /// <summary> | ||
37 | /// Get/Set if to use the caller's HTTP context | ||
38 | /// </summary> | ||
39 | public bool UseCallerHttpContext { get; set; } | ||
40 | |||
41 | /// <summary> | ||
42 | /// Get/Set if to dispose of the state object of a work item | ||
43 | /// </summary> | ||
44 | public bool DisposeOfStateObjects { get; set; } | ||
45 | |||
46 | /// <summary> | ||
47 | /// Get/Set the run the post execute options | ||
48 | /// </summary> | ||
49 | public CallToPostExecute CallToPostExecute { get; set; } | ||
50 | |||
51 | /// <summary> | ||
52 | /// Get/Set the post execute callback | ||
53 | /// </summary> | ||
54 | public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } | ||
55 | |||
56 | /// <summary> | ||
57 | /// Get/Set the work item's priority | ||
58 | /// </summary> | ||
59 | public WorkItemPriority WorkItemPriority { get; set; } | ||
60 | |||
61 | /// <summary> | ||
62 | /// Get/Set the work item's timout in milliseconds. | ||
63 | /// This is a passive timout. When the timout expires the work item won't be actively aborted! | ||
64 | /// </summary> | ||
65 | public long Timeout { get; set; } | ||
66 | } | ||
67 | |||
68 | #endregion | ||
69 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs new file mode 100644 index 0000000..d1eff95 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs | |||
@@ -0,0 +1,128 @@ | |||
1 | using System; | ||
2 | using System.Threading; | ||
3 | |||
4 | namespace Amib.Threading.Internal | ||
5 | { | ||
6 | #region WorkItemResultTWrapper class | ||
7 | |||
8 | internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult | ||
9 | { | ||
10 | private readonly IWorkItemResult _workItemResult; | ||
11 | |||
12 | public WorkItemResultTWrapper(IWorkItemResult workItemResult) | ||
13 | { | ||
14 | _workItemResult = workItemResult; | ||
15 | } | ||
16 | |||
17 | #region IWorkItemResult<TResult> Members | ||
18 | |||
19 | public TResult GetResult() | ||
20 | { | ||
21 | return (TResult)_workItemResult.GetResult(); | ||
22 | } | ||
23 | |||
24 | public TResult GetResult(int millisecondsTimeout, bool exitContext) | ||
25 | { | ||
26 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); | ||
27 | } | ||
28 | |||
29 | public TResult GetResult(TimeSpan timeout, bool exitContext) | ||
30 | { | ||
31 | return (TResult)_workItemResult.GetResult(timeout, exitContext); | ||
32 | } | ||
33 | |||
34 | public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) | ||
35 | { | ||
36 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); | ||
37 | } | ||
38 | |||
39 | public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) | ||
40 | { | ||
41 | return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); | ||
42 | } | ||
43 | |||
44 | public TResult GetResult(out Exception e) | ||
45 | { | ||
46 | return (TResult)_workItemResult.GetResult(out e); | ||
47 | } | ||
48 | |||
49 | public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) | ||
50 | { | ||
51 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); | ||
52 | } | ||
53 | |||
54 | public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) | ||
55 | { | ||
56 | return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); | ||
57 | } | ||
58 | |||
59 | public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) | ||
60 | { | ||
61 | return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); | ||
62 | } | ||
63 | |||
64 | public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) | ||
65 | { | ||
66 | return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); | ||
67 | } | ||
68 | |||
69 | public bool IsCompleted | ||
70 | { | ||
71 | get { return _workItemResult.IsCompleted; } | ||
72 | } | ||
73 | |||
74 | public bool IsCanceled | ||
75 | { | ||
76 | get { return _workItemResult.IsCanceled; } | ||
77 | } | ||
78 | |||
79 | public object State | ||
80 | { | ||
81 | get { return _workItemResult.State; } | ||
82 | } | ||
83 | |||
84 | public bool Cancel() | ||
85 | { | ||
86 | return _workItemResult.Cancel(); | ||
87 | } | ||
88 | |||
89 | public bool Cancel(bool abortExecution) | ||
90 | { | ||
91 | return _workItemResult.Cancel(abortExecution); | ||
92 | } | ||
93 | |||
94 | public WorkItemPriority WorkItemPriority | ||
95 | { | ||
96 | get { return _workItemResult.WorkItemPriority; } | ||
97 | } | ||
98 | |||
99 | public TResult Result | ||
100 | { | ||
101 | get { return (TResult)_workItemResult.Result; } | ||
102 | } | ||
103 | |||
104 | public object Exception | ||
105 | { | ||
106 | get { return (TResult)_workItemResult.Exception; } | ||
107 | } | ||
108 | |||
109 | #region IInternalWorkItemResult Members | ||
110 | |||
111 | public IWorkItemResult GetWorkItemResult() | ||
112 | { | ||
113 | return _workItemResult.GetWorkItemResult(); | ||
114 | } | ||
115 | |||
116 | public IWorkItemResult<TRes> GetWorkItemResultT<TRes>() | ||
117 | { | ||
118 | return (IWorkItemResult<TRes>)this; | ||
119 | } | ||
120 | |||
121 | #endregion | ||
122 | |||
123 | #endregion | ||
124 | } | ||
125 | |||
126 | #endregion | ||
127 | |||
128 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs new file mode 100644 index 0000000..d429bc6 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs | |||
@@ -0,0 +1,361 @@ | |||
1 | using System; | ||
2 | using System.Threading; | ||
3 | using System.Runtime.CompilerServices; | ||
4 | using System.Diagnostics; | ||
5 | |||
6 | namespace Amib.Threading.Internal | ||
7 | { | ||
8 | |||
9 | #region WorkItemsGroup class | ||
10 | |||
11 | /// <summary> | ||
12 | /// Summary description for WorkItemsGroup. | ||
13 | /// </summary> | ||
14 | public class WorkItemsGroup : WorkItemsGroupBase | ||
15 | { | ||
16 | #region Private members | ||
17 | |||
18 | private readonly object _lock = new object(); | ||
19 | |||
20 | /// <summary> | ||
21 | /// A reference to the SmartThreadPool instance that created this | ||
22 | /// WorkItemsGroup. | ||
23 | /// </summary> | ||
24 | private readonly SmartThreadPool _stp; | ||
25 | |||
26 | /// <summary> | ||
27 | /// The OnIdle event | ||
28 | /// </summary> | ||
29 | private event WorkItemsGroupIdleHandler _onIdle; | ||
30 | |||
31 | /// <summary> | ||
32 | /// A flag to indicate if the Work Items Group is now suspended. | ||
33 | /// </summary> | ||
34 | private bool _isSuspended; | ||
35 | |||
36 | /// <summary> | ||
37 | /// Defines how many work items of this WorkItemsGroup can run at once. | ||
38 | /// </summary> | ||
39 | private int _concurrency; | ||
40 | |||
41 | /// <summary> | ||
42 | /// Priority queue to hold work items before they are passed | ||
43 | /// to the SmartThreadPool. | ||
44 | /// </summary> | ||
45 | private readonly PriorityQueue _workItemsQueue; | ||
46 | |||
47 | /// <summary> | ||
48 | /// Indicate how many work items are waiting in the SmartThreadPool | ||
49 | /// queue. | ||
50 | /// This value is used to apply the concurrency. | ||
51 | /// </summary> | ||
52 | private int _workItemsInStpQueue; | ||
53 | |||
54 | /// <summary> | ||
55 | /// Indicate how many work items are currently running in the SmartThreadPool. | ||
56 | /// This value is used with the Cancel, to calculate if we can send new | ||
57 | /// work items to the STP. | ||
58 | /// </summary> | ||
59 | private int _workItemsExecutingInStp = 0; | ||
60 | |||
61 | /// <summary> | ||
62 | /// WorkItemsGroup start information | ||
63 | /// </summary> | ||
64 | private readonly WIGStartInfo _workItemsGroupStartInfo; | ||
65 | |||
66 | /// <summary> | ||
67 | /// Signaled when all of the WorkItemsGroup's work item completed. | ||
68 | /// </summary> | ||
69 | //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); | ||
70 | private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); | ||
71 | |||
72 | /// <summary> | ||
73 | /// A common object for all the work items that this work items group | ||
74 | /// generate so we can mark them to cancel in O(1) | ||
75 | /// </summary> | ||
76 | private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); | ||
77 | |||
78 | #endregion | ||
79 | |||
80 | #region Construction | ||
81 | |||
82 | public WorkItemsGroup( | ||
83 | SmartThreadPool stp, | ||
84 | int concurrency, | ||
85 | WIGStartInfo wigStartInfo) | ||
86 | { | ||
87 | if (concurrency <= 0) | ||
88 | { | ||
89 | throw new ArgumentOutOfRangeException( | ||
90 | "concurrency", | ||
91 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
92 | concurrency, | ||
93 | #endif | ||
94 | "concurrency must be greater than zero"); | ||
95 | } | ||
96 | _stp = stp; | ||
97 | _concurrency = concurrency; | ||
98 | _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly(); | ||
99 | _workItemsQueue = new PriorityQueue(); | ||
100 | Name = "WorkItemsGroup"; | ||
101 | |||
102 | // The _workItemsInStpQueue gets the number of currently executing work items, | ||
103 | // because once a work item is executing, it cannot be cancelled. | ||
104 | _workItemsInStpQueue = _workItemsExecutingInStp; | ||
105 | |||
106 | _isSuspended = _workItemsGroupStartInfo.StartSuspended; | ||
107 | } | ||
108 | |||
109 | #endregion | ||
110 | |||
111 | #region WorkItemsGroupBase Overrides | ||
112 | |||
113 | public override int Concurrency | ||
114 | { | ||
115 | get { return _concurrency; } | ||
116 | set | ||
117 | { | ||
118 | Debug.Assert(value > 0); | ||
119 | |||
120 | int diff = value - _concurrency; | ||
121 | _concurrency = value; | ||
122 | if (diff > 0) | ||
123 | { | ||
124 | EnqueueToSTPNextNWorkItem(diff); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | public override int WaitingCallbacks | ||
130 | { | ||
131 | get { return _workItemsQueue.Count; } | ||
132 | } | ||
133 | |||
134 | public override object[] GetStates() | ||
135 | { | ||
136 | lock (_lock) | ||
137 | { | ||
138 | object[] states = new object[_workItemsQueue.Count]; | ||
139 | int i = 0; | ||
140 | foreach (WorkItem workItem in _workItemsQueue) | ||
141 | { | ||
142 | states[i] = workItem.GetWorkItemResult().State; | ||
143 | ++i; | ||
144 | } | ||
145 | return states; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /// <summary> | ||
150 | /// WorkItemsGroup start information | ||
151 | /// </summary> | ||
152 | public override WIGStartInfo WIGStartInfo | ||
153 | { | ||
154 | get { return _workItemsGroupStartInfo; } | ||
155 | } | ||
156 | |||
157 | /// <summary> | ||
158 | /// Start the Work Items Group if it was started suspended | ||
159 | /// </summary> | ||
160 | public override void Start() | ||
161 | { | ||
162 | // If the Work Items Group already started then quit | ||
163 | if (!_isSuspended) | ||
164 | { | ||
165 | return; | ||
166 | } | ||
167 | _isSuspended = false; | ||
168 | |||
169 | EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); | ||
170 | } | ||
171 | |||
172 | public override void Cancel(bool abortExecution) | ||
173 | { | ||
174 | lock (_lock) | ||
175 | { | ||
176 | _canceledWorkItemsGroup.IsCanceled = true; | ||
177 | _workItemsQueue.Clear(); | ||
178 | _workItemsInStpQueue = 0; | ||
179 | _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); | ||
180 | } | ||
181 | |||
182 | if (abortExecution) | ||
183 | { | ||
184 | _stp.CancelAbortWorkItemsGroup(this); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /// <summary> | ||
189 | /// Wait for the thread pool to be idle | ||
190 | /// </summary> | ||
191 | public override bool WaitForIdle(int millisecondsTimeout) | ||
192 | { | ||
193 | SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this); | ||
194 | return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); | ||
195 | } | ||
196 | |||
197 | public override event WorkItemsGroupIdleHandler OnIdle | ||
198 | { | ||
199 | add { _onIdle += value; } | ||
200 | remove { _onIdle -= value; } | ||
201 | } | ||
202 | |||
203 | #endregion | ||
204 | |||
205 | #region Private methods | ||
206 | |||
207 | private void RegisterToWorkItemCompletion(IWorkItemResult wir) | ||
208 | { | ||
209 | IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir; | ||
210 | iwir.OnWorkItemStarted += OnWorkItemStartedCallback; | ||
211 | iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback; | ||
212 | } | ||
213 | |||
214 | public void OnSTPIsStarting() | ||
215 | { | ||
216 | if (_isSuspended) | ||
217 | { | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | EnqueueToSTPNextNWorkItem(_concurrency); | ||
222 | } | ||
223 | |||
224 | public void EnqueueToSTPNextNWorkItem(int count) | ||
225 | { | ||
226 | for (int i = 0; i < count; ++i) | ||
227 | { | ||
228 | EnqueueToSTPNextWorkItem(null, false); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | private object FireOnIdle(object state) | ||
233 | { | ||
234 | FireOnIdleImpl(_onIdle); | ||
235 | return null; | ||
236 | } | ||
237 | |||
238 | [MethodImpl(MethodImplOptions.NoInlining)] | ||
239 | private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) | ||
240 | { | ||
241 | if(null == onIdle) | ||
242 | { | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | Delegate[] delegates = onIdle.GetInvocationList(); | ||
247 | foreach(WorkItemsGroupIdleHandler eh in delegates) | ||
248 | { | ||
249 | try | ||
250 | { | ||
251 | eh(this); | ||
252 | } | ||
253 | catch { } // Suppress exceptions | ||
254 | } | ||
255 | } | ||
256 | |||
257 | private void OnWorkItemStartedCallback(WorkItem workItem) | ||
258 | { | ||
259 | lock(_lock) | ||
260 | { | ||
261 | ++_workItemsExecutingInStp; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | private void OnWorkItemCompletedCallback(WorkItem workItem) | ||
266 | { | ||
267 | EnqueueToSTPNextWorkItem(null, true); | ||
268 | } | ||
269 | |||
270 | internal override void Enqueue(WorkItem workItem) | ||
271 | { | ||
272 | EnqueueToSTPNextWorkItem(workItem); | ||
273 | } | ||
274 | |||
275 | private void EnqueueToSTPNextWorkItem(WorkItem workItem) | ||
276 | { | ||
277 | EnqueueToSTPNextWorkItem(workItem, false); | ||
278 | } | ||
279 | |||
280 | private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) | ||
281 | { | ||
282 | lock(_lock) | ||
283 | { | ||
284 | // Got here from OnWorkItemCompletedCallback() | ||
285 | if (decrementWorkItemsInStpQueue) | ||
286 | { | ||
287 | --_workItemsInStpQueue; | ||
288 | |||
289 | if(_workItemsInStpQueue < 0) | ||
290 | { | ||
291 | _workItemsInStpQueue = 0; | ||
292 | } | ||
293 | |||
294 | --_workItemsExecutingInStp; | ||
295 | |||
296 | if(_workItemsExecutingInStp < 0) | ||
297 | { | ||
298 | _workItemsExecutingInStp = 0; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | // If the work item is not null then enqueue it | ||
303 | if (null != workItem) | ||
304 | { | ||
305 | workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; | ||
306 | |||
307 | RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); | ||
308 | _workItemsQueue.Enqueue(workItem); | ||
309 | //_stp.IncrementWorkItemsCount(); | ||
310 | |||
311 | if ((1 == _workItemsQueue.Count) && | ||
312 | (0 == _workItemsInStpQueue)) | ||
313 | { | ||
314 | _stp.RegisterWorkItemsGroup(this); | ||
315 | IsIdle = false; | ||
316 | _isIdleWaitHandle.Reset(); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | // If the work items queue of the group is empty than quit | ||
321 | if (0 == _workItemsQueue.Count) | ||
322 | { | ||
323 | if (0 == _workItemsInStpQueue) | ||
324 | { | ||
325 | _stp.UnregisterWorkItemsGroup(this); | ||
326 | IsIdle = true; | ||
327 | _isIdleWaitHandle.Set(); | ||
328 | if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0) | ||
329 | { | ||
330 | _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle)); | ||
331 | } | ||
332 | } | ||
333 | return; | ||
334 | } | ||
335 | |||
336 | if (!_isSuspended) | ||
337 | { | ||
338 | if (_workItemsInStpQueue < _concurrency) | ||
339 | { | ||
340 | WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; | ||
341 | try | ||
342 | { | ||
343 | _stp.Enqueue(nextWorkItem); | ||
344 | } | ||
345 | catch (ObjectDisposedException e) | ||
346 | { | ||
347 | e.GetHashCode(); | ||
348 | // The STP has been shutdown | ||
349 | } | ||
350 | |||
351 | ++_workItemsInStpQueue; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | |||
357 | #endregion | ||
358 | } | ||
359 | |||
360 | #endregion | ||
361 | } | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs new file mode 100644 index 0000000..3a5dcc6 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs | |||
@@ -0,0 +1,471 @@ | |||
1 | using System; | ||
2 | using System.Threading; | ||
3 | |||
4 | namespace Amib.Threading.Internal | ||
5 | { | ||
6 | public abstract class WorkItemsGroupBase : IWorkItemsGroup | ||
7 | { | ||
8 | #region Private Fields | ||
9 | |||
10 | /// <summary> | ||
11 | /// Contains the name of this instance of SmartThreadPool. | ||
12 | /// Can be changed by the user. | ||
13 | /// </summary> | ||
14 | private string _name = "WorkItemsGroupBase"; | ||
15 | |||
16 | public WorkItemsGroupBase() | ||
17 | { | ||
18 | IsIdle = true; | ||
19 | } | ||
20 | |||
21 | #endregion | ||
22 | |||
23 | #region IWorkItemsGroup Members | ||
24 | |||
25 | #region Public Methods | ||
26 | |||
27 | /// <summary> | ||
28 | /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance | ||
29 | /// </summary> | ||
30 | public string Name | ||
31 | { | ||
32 | get { return _name; } | ||
33 | set { _name = value; } | ||
34 | } | ||
35 | |||
36 | #endregion | ||
37 | |||
38 | #region Abstract Methods | ||
39 | |||
40 | public abstract int Concurrency { get; set; } | ||
41 | public abstract int WaitingCallbacks { get; } | ||
42 | public abstract object[] GetStates(); | ||
43 | public abstract WIGStartInfo WIGStartInfo { get; } | ||
44 | public abstract void Start(); | ||
45 | public abstract void Cancel(bool abortExecution); | ||
46 | public abstract bool WaitForIdle(int millisecondsTimeout); | ||
47 | public abstract event WorkItemsGroupIdleHandler OnIdle; | ||
48 | |||
49 | internal abstract void Enqueue(WorkItem workItem); | ||
50 | internal virtual void PreQueueWorkItem() { } | ||
51 | |||
52 | #endregion | ||
53 | |||
54 | #region Common Base Methods | ||
55 | |||
56 | /// <summary> | ||
57 | /// Cancel all the work items. | ||
58 | /// Same as Cancel(false) | ||
59 | /// </summary> | ||
60 | public virtual void Cancel() | ||
61 | { | ||
62 | Cancel(false); | ||
63 | } | ||
64 | |||
65 | /// <summary> | ||
66 | /// Wait for the SmartThreadPool/WorkItemsGroup to be idle | ||
67 | /// </summary> | ||
68 | public void WaitForIdle() | ||
69 | { | ||
70 | WaitForIdle(Timeout.Infinite); | ||
71 | } | ||
72 | |||
73 | /// <summary> | ||
74 | /// Wait for the SmartThreadPool/WorkItemsGroup to be idle | ||
75 | /// </summary> | ||
76 | public bool WaitForIdle(TimeSpan timeout) | ||
77 | { | ||
78 | return WaitForIdle((int)timeout.TotalMilliseconds); | ||
79 | } | ||
80 | |||
81 | /// <summary> | ||
82 | /// IsIdle is true when there are no work items running or queued. | ||
83 | /// </summary> | ||
84 | public bool IsIdle { get; protected set; } | ||
85 | |||
86 | #endregion | ||
87 | |||
88 | #region QueueWorkItem | ||
89 | |||
90 | /// <summary> | ||
91 | /// Queue a work item | ||
92 | /// </summary> | ||
93 | /// <param name="callback">A callback to execute</param> | ||
94 | /// <returns>Returns a work item result</returns> | ||
95 | public IWorkItemResult QueueWorkItem(WorkItemCallback callback) | ||
96 | { | ||
97 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback); | ||
98 | Enqueue(workItem); | ||
99 | return workItem.GetWorkItemResult(); | ||
100 | } | ||
101 | |||
102 | /// <summary> | ||
103 | /// Queue a work item | ||
104 | /// </summary> | ||
105 | /// <param name="callback">A callback to execute</param> | ||
106 | /// <param name="workItemPriority">The priority of the work item</param> | ||
107 | /// <returns>Returns a work item result</returns> | ||
108 | public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) | ||
109 | { | ||
110 | PreQueueWorkItem(); | ||
111 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority); | ||
112 | Enqueue(workItem); | ||
113 | return workItem.GetWorkItemResult(); | ||
114 | } | ||
115 | |||
116 | /// <summary> | ||
117 | /// Queue a work item | ||
118 | /// </summary> | ||
119 | /// <param name="workItemInfo">Work item info</param> | ||
120 | /// <param name="callback">A callback to execute</param> | ||
121 | /// <returns>Returns a work item result</returns> | ||
122 | public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) | ||
123 | { | ||
124 | PreQueueWorkItem(); | ||
125 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback); | ||
126 | Enqueue(workItem); | ||
127 | return workItem.GetWorkItemResult(); | ||
128 | } | ||
129 | |||
130 | /// <summary> | ||
131 | /// Queue a work item | ||
132 | /// </summary> | ||
133 | /// <param name="callback">A callback to execute</param> | ||
134 | /// <param name="state"> | ||
135 | /// The context object of the work item. Used for passing arguments to the work item. | ||
136 | /// </param> | ||
137 | /// <returns>Returns a work item result</returns> | ||
138 | public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) | ||
139 | { | ||
140 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state); | ||
141 | Enqueue(workItem); | ||
142 | return workItem.GetWorkItemResult(); | ||
143 | } | ||
144 | |||
145 | /// <summary> | ||
146 | /// Queue a work item | ||
147 | /// </summary> | ||
148 | /// <param name="callback">A callback to execute</param> | ||
149 | /// <param name="state"> | ||
150 | /// The context object of the work item. Used for passing arguments to the work item. | ||
151 | /// </param> | ||
152 | /// <param name="workItemPriority">The work item priority</param> | ||
153 | /// <returns>Returns a work item result</returns> | ||
154 | public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) | ||
155 | { | ||
156 | PreQueueWorkItem(); | ||
157 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority); | ||
158 | Enqueue(workItem); | ||
159 | return workItem.GetWorkItemResult(); | ||
160 | } | ||
161 | |||
162 | /// <summary> | ||
163 | /// Queue a work item | ||
164 | /// </summary> | ||
165 | /// <param name="workItemInfo">Work item information</param> | ||
166 | /// <param name="callback">A callback to execute</param> | ||
167 | /// <param name="state"> | ||
168 | /// The context object of the work item. Used for passing arguments to the work item. | ||
169 | /// </param> | ||
170 | /// <returns>Returns a work item result</returns> | ||
171 | public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) | ||
172 | { | ||
173 | PreQueueWorkItem(); | ||
174 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state); | ||
175 | Enqueue(workItem); | ||
176 | return workItem.GetWorkItemResult(); | ||
177 | } | ||
178 | |||
179 | /// <summary> | ||
180 | /// Queue a work item | ||
181 | /// </summary> | ||
182 | /// <param name="callback">A callback to execute</param> | ||
183 | /// <param name="state"> | ||
184 | /// The context object of the work item. Used for passing arguments to the work item. | ||
185 | /// </param> | ||
186 | /// <param name="postExecuteWorkItemCallback"> | ||
187 | /// A delegate to call after the callback completion | ||
188 | /// </param> | ||
189 | /// <returns>Returns a work item result</returns> | ||
190 | public IWorkItemResult QueueWorkItem( | ||
191 | WorkItemCallback callback, | ||
192 | object state, | ||
193 | PostExecuteWorkItemCallback postExecuteWorkItemCallback) | ||
194 | { | ||
195 | PreQueueWorkItem(); | ||
196 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback); | ||
197 | Enqueue(workItem); | ||
198 | return workItem.GetWorkItemResult(); | ||
199 | } | ||
200 | |||
201 | /// <summary> | ||
202 | /// Queue a work item | ||
203 | /// </summary> | ||
204 | /// <param name="callback">A callback to execute</param> | ||
205 | /// <param name="state"> | ||
206 | /// The context object of the work item. Used for passing arguments to the work item. | ||
207 | /// </param> | ||
208 | /// <param name="postExecuteWorkItemCallback"> | ||
209 | /// A delegate to call after the callback completion | ||
210 | /// </param> | ||
211 | /// <param name="workItemPriority">The work item priority</param> | ||
212 | /// <returns>Returns a work item result</returns> | ||
213 | public IWorkItemResult QueueWorkItem( | ||
214 | WorkItemCallback callback, | ||
215 | object state, | ||
216 | PostExecuteWorkItemCallback postExecuteWorkItemCallback, | ||
217 | WorkItemPriority workItemPriority) | ||
218 | { | ||
219 | PreQueueWorkItem(); | ||
220 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); | ||
221 | Enqueue(workItem); | ||
222 | return workItem.GetWorkItemResult(); | ||
223 | } | ||
224 | |||
225 | /// <summary> | ||
226 | /// Queue a work item | ||
227 | /// </summary> | ||
228 | /// <param name="callback">A callback to execute</param> | ||
229 | /// <param name="state"> | ||
230 | /// The context object of the work item. Used for passing arguments to the work item. | ||
231 | /// </param> | ||
232 | /// <param name="postExecuteWorkItemCallback"> | ||
233 | /// A delegate to call after the callback completion | ||
234 | /// </param> | ||
235 | /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> | ||
236 | /// <returns>Returns a work item result</returns> | ||
237 | public IWorkItemResult QueueWorkItem( | ||
238 | WorkItemCallback callback, | ||
239 | object state, | ||
240 | PostExecuteWorkItemCallback postExecuteWorkItemCallback, | ||
241 | CallToPostExecute callToPostExecute) | ||
242 | { | ||
243 | PreQueueWorkItem(); | ||
244 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); | ||
245 | Enqueue(workItem); | ||
246 | return workItem.GetWorkItemResult(); | ||
247 | } | ||
248 | |||
249 | /// <summary> | ||
250 | /// Queue a work item | ||
251 | /// </summary> | ||
252 | /// <param name="callback">A callback to execute</param> | ||
253 | /// <param name="state"> | ||
254 | /// The context object of the work item. Used for passing arguments to the work item. | ||
255 | /// </param> | ||
256 | /// <param name="postExecuteWorkItemCallback"> | ||
257 | /// A delegate to call after the callback completion | ||
258 | /// </param> | ||
259 | /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> | ||
260 | /// <param name="workItemPriority">The work item priority</param> | ||
261 | /// <returns>Returns a work item result</returns> | ||
262 | public IWorkItemResult QueueWorkItem( | ||
263 | WorkItemCallback callback, | ||
264 | object state, | ||
265 | PostExecuteWorkItemCallback postExecuteWorkItemCallback, | ||
266 | CallToPostExecute callToPostExecute, | ||
267 | WorkItemPriority workItemPriority) | ||
268 | { | ||
269 | PreQueueWorkItem(); | ||
270 | WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); | ||
271 | Enqueue(workItem); | ||
272 | return workItem.GetWorkItemResult(); | ||
273 | } | ||
274 | |||
275 | #endregion | ||
276 | |||
277 | #region QueueWorkItem(Action<...>) | ||
278 | |||
279 | public IWorkItemResult QueueWorkItem(Action action) | ||
280 | { | ||
281 | return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority); | ||
282 | } | ||
283 | |||
284 | public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority) | ||
285 | { | ||
286 | PreQueueWorkItem (); | ||
287 | WorkItem workItem = WorkItemFactory.CreateWorkItem ( | ||
288 | this, | ||
289 | WIGStartInfo, | ||
290 | delegate | ||
291 | { | ||
292 | action.Invoke (); | ||
293 | return null; | ||
294 | }, priority); | ||
295 | Enqueue (workItem); | ||
296 | return workItem.GetWorkItemResult (); | ||
297 | } | ||
298 | |||
299 | public IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg) | ||
300 | { | ||
301 | return QueueWorkItem<T> (action, arg, SmartThreadPool.DefaultWorkItemPriority); | ||
302 | } | ||
303 | |||
304 | public IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority) | ||
305 | { | ||
306 | PreQueueWorkItem (); | ||
307 | WorkItem workItem = WorkItemFactory.CreateWorkItem ( | ||
308 | this, | ||
309 | WIGStartInfo, | ||
310 | state => | ||
311 | { | ||
312 | action.Invoke (arg); | ||
313 | return null; | ||
314 | }, | ||
315 | WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority); | ||
316 | Enqueue (workItem); | ||
317 | return workItem.GetWorkItemResult (); | ||
318 | } | ||
319 | |||
320 | public IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2) | ||
321 | { | ||
322 | return QueueWorkItem<T1, T2> (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority); | ||
323 | } | ||
324 | |||
325 | public IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority) | ||
326 | { | ||
327 | PreQueueWorkItem (); | ||
328 | WorkItem workItem = WorkItemFactory.CreateWorkItem ( | ||
329 | this, | ||
330 | WIGStartInfo, | ||
331 | state => | ||
332 | { | ||
333 | action.Invoke (arg1, arg2); | ||
334 | return null; | ||
335 | }, | ||
336 | WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority); | ||
337 | Enqueue (workItem); | ||
338 | return workItem.GetWorkItemResult (); | ||
339 | } | ||
340 | |||
341 | public IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3) | ||
342 | { | ||
343 | return QueueWorkItem<T1, T2, T3> (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority); | ||
344 | ; | ||
345 | } | ||
346 | |||
347 | public IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority) | ||
348 | { | ||
349 | PreQueueWorkItem (); | ||
350 | WorkItem workItem = WorkItemFactory.CreateWorkItem ( | ||
351 | this, | ||
352 | WIGStartInfo, | ||
353 | state => | ||
354 | { | ||
355 | action.Invoke (arg1, arg2, arg3); | ||
356 | return null; | ||
357 | }, | ||
358 | WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority); | ||
359 | Enqueue (workItem); | ||
360 | return workItem.GetWorkItemResult (); | ||
361 | } | ||
362 | |||
363 | public IWorkItemResult QueueWorkItem<T1, T2, T3, T4>( | ||
364 | Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4) | ||
365 | { | ||
366 | return QueueWorkItem<T1, T2, T3, T4> (action, arg1, arg2, arg3, arg4, | ||
367 | SmartThreadPool.DefaultWorkItemPriority); | ||
368 | } | ||
369 | |||
370 | public IWorkItemResult QueueWorkItem<T1, T2, T3, T4> ( | ||
371 | Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority) | ||
372 | { | ||
373 | PreQueueWorkItem (); | ||
374 | WorkItem workItem = WorkItemFactory.CreateWorkItem ( | ||
375 | this, | ||
376 | WIGStartInfo, | ||
377 | state => | ||
378 | { | ||
379 | action.Invoke (arg1, arg2, arg3, arg4); | ||
380 | return null; | ||
381 | }, | ||
382 | WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority); | ||
383 | Enqueue (workItem); | ||
384 | return workItem.GetWorkItemResult (); | ||
385 | } | ||
386 | |||
387 | #endregion | ||
388 | |||
389 | #region QueueWorkItem(Func<...>) | ||
390 | |||
391 | public IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func) | ||
392 | { | ||
393 | PreQueueWorkItem(); | ||
394 | WorkItem workItem = WorkItemFactory.CreateWorkItem( | ||
395 | this, | ||
396 | WIGStartInfo, | ||
397 | state => | ||
398 | { | ||
399 | return func.Invoke(); | ||
400 | }); | ||
401 | Enqueue(workItem); | ||
402 | return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult()); | ||
403 | } | ||
404 | |||
405 | public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg) | ||
406 | { | ||
407 | PreQueueWorkItem(); | ||
408 | WorkItem workItem = WorkItemFactory.CreateWorkItem( | ||
409 | this, | ||
410 | WIGStartInfo, | ||
411 | state => | ||
412 | { | ||
413 | return func.Invoke(arg); | ||
414 | }, | ||
415 | WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null); | ||
416 | Enqueue(workItem); | ||
417 | return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult()); | ||
418 | } | ||
419 | |||
420 | public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2) | ||
421 | { | ||
422 | PreQueueWorkItem(); | ||
423 | WorkItem workItem = WorkItemFactory.CreateWorkItem( | ||
424 | this, | ||
425 | WIGStartInfo, | ||
426 | state => | ||
427 | { | ||
428 | return func.Invoke(arg1, arg2); | ||
429 | }, | ||
430 | WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null); | ||
431 | Enqueue(workItem); | ||
432 | return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult()); | ||
433 | } | ||
434 | |||
435 | public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>( | ||
436 | Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3) | ||
437 | { | ||
438 | PreQueueWorkItem(); | ||
439 | WorkItem workItem = WorkItemFactory.CreateWorkItem( | ||
440 | this, | ||
441 | WIGStartInfo, | ||
442 | state => | ||
443 | { | ||
444 | return func.Invoke(arg1, arg2, arg3); | ||
445 | }, | ||
446 | WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null); | ||
447 | Enqueue(workItem); | ||
448 | return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult()); | ||
449 | } | ||
450 | |||
451 | public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>( | ||
452 | Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) | ||
453 | { | ||
454 | PreQueueWorkItem(); | ||
455 | WorkItem workItem = WorkItemFactory.CreateWorkItem( | ||
456 | this, | ||
457 | WIGStartInfo, | ||
458 | state => | ||
459 | { | ||
460 | return func.Invoke(arg1, arg2, arg3, arg4); | ||
461 | }, | ||
462 | WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null); | ||
463 | Enqueue(workItem); | ||
464 | return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult()); | ||
465 | } | ||
466 | |||
467 | #endregion | ||
468 | |||
469 | #endregion | ||
470 | } | ||
471 | } \ No newline at end of file | ||
diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs new file mode 100644 index 0000000..21403a0 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs | |||
@@ -0,0 +1,646 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Threading; | ||
4 | |||
5 | namespace Amib.Threading.Internal | ||
6 | { | ||
7 | #region WorkItemsQueue class | ||
8 | |||
9 | /// <summary> | ||
10 | /// WorkItemsQueue class. | ||
11 | /// </summary> | ||
12 | public class WorkItemsQueue : IDisposable | ||
13 | { | ||
14 | #region Member variables | ||
15 | |||
16 | /// <summary> | ||
17 | /// Waiters queue (implemented as stack). | ||
18 | /// </summary> | ||
19 | private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); | ||
20 | |||
21 | /// <summary> | ||
22 | /// Waiters count | ||
23 | /// </summary> | ||
24 | private int _waitersCount = 0; | ||
25 | |||
26 | /// <summary> | ||
27 | /// Work items queue | ||
28 | /// </summary> | ||
29 | private readonly PriorityQueue _workItems = new PriorityQueue(); | ||
30 | |||
31 | /// <summary> | ||
32 | /// Indicate that work items are allowed to be queued | ||
33 | /// </summary> | ||
34 | private bool _isWorkItemsQueueActive = true; | ||
35 | |||
36 | |||
37 | #if (WINDOWS_PHONE) | ||
38 | private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>(); | ||
39 | #elif (_WINDOWS_CE) | ||
40 | private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); | ||
41 | #else | ||
42 | |||
43 | [ThreadStatic] | ||
44 | private static WaiterEntry _waiterEntry; | ||
45 | #endif | ||
46 | |||
47 | |||
48 | /// <summary> | ||
49 | /// Each thread in the thread pool keeps its own waiter entry. | ||
50 | /// </summary> | ||
51 | private static WaiterEntry CurrentWaiterEntry | ||
52 | { | ||
53 | #if (WINDOWS_PHONE) | ||
54 | get | ||
55 | { | ||
56 | lock (_waiterEntries) | ||
57 | { | ||
58 | WaiterEntry waiterEntry; | ||
59 | if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry)) | ||
60 | { | ||
61 | return waiterEntry; | ||
62 | } | ||
63 | } | ||
64 | return null; | ||
65 | } | ||
66 | set | ||
67 | { | ||
68 | lock (_waiterEntries) | ||
69 | { | ||
70 | _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value; | ||
71 | } | ||
72 | } | ||
73 | #elif (_WINDOWS_CE) | ||
74 | get | ||
75 | { | ||
76 | return Thread.GetData(_waiterEntrySlot) as WaiterEntry; | ||
77 | } | ||
78 | set | ||
79 | { | ||
80 | Thread.SetData(_waiterEntrySlot, value); | ||
81 | } | ||
82 | #else | ||
83 | get | ||
84 | { | ||
85 | return _waiterEntry; | ||
86 | } | ||
87 | set | ||
88 | { | ||
89 | _waiterEntry = value; | ||
90 | } | ||
91 | #endif | ||
92 | } | ||
93 | |||
94 | /// <summary> | ||
95 | /// A flag that indicates if the WorkItemsQueue has been disposed. | ||
96 | /// </summary> | ||
97 | private bool _isDisposed = false; | ||
98 | |||
99 | #endregion | ||
100 | |||
101 | #region Public properties | ||
102 | |||
103 | /// <summary> | ||
104 | /// Returns the current number of work items in the queue | ||
105 | /// </summary> | ||
106 | public int Count | ||
107 | { | ||
108 | get | ||
109 | { | ||
110 | return _workItems.Count; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | /// <summary> | ||
115 | /// Returns the current number of waiters | ||
116 | /// </summary> | ||
117 | public int WaitersCount | ||
118 | { | ||
119 | get | ||
120 | { | ||
121 | return _waitersCount; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | |||
126 | #endregion | ||
127 | |||
128 | #region Public methods | ||
129 | |||
130 | /// <summary> | ||
131 | /// Enqueue a work item to the queue. | ||
132 | /// </summary> | ||
133 | public bool EnqueueWorkItem(WorkItem workItem) | ||
134 | { | ||
135 | // A work item cannot be null, since null is used in the | ||
136 | // WaitForWorkItem() method to indicate timeout or cancel | ||
137 | if (null == workItem) | ||
138 | { | ||
139 | throw new ArgumentNullException("workItem" , "workItem cannot be null"); | ||
140 | } | ||
141 | |||
142 | bool enqueue = true; | ||
143 | |||
144 | // First check if there is a waiter waiting for work item. During | ||
145 | // the check, timed out waiters are ignored. If there is no | ||
146 | // waiter then the work item is queued. | ||
147 | lock(this) | ||
148 | { | ||
149 | ValidateNotDisposed(); | ||
150 | |||
151 | if (!_isWorkItemsQueueActive) | ||
152 | { | ||
153 | return false; | ||
154 | } | ||
155 | |||
156 | while(_waitersCount > 0) | ||
157 | { | ||
158 | // Dequeue a waiter. | ||
159 | WaiterEntry waiterEntry = PopWaiter(); | ||
160 | |||
161 | // Signal the waiter. On success break the loop | ||
162 | if (waiterEntry.Signal(workItem)) | ||
163 | { | ||
164 | enqueue = false; | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | if (enqueue) | ||
170 | { | ||
171 | // Enqueue the work item | ||
172 | _workItems.Enqueue(workItem); | ||
173 | } | ||
174 | } | ||
175 | return true; | ||
176 | } | ||
177 | |||
178 | |||
179 | /// <summary> | ||
180 | /// Waits for a work item or exits on timeout or cancel | ||
181 | /// </summary> | ||
182 | /// <param name="millisecondsTimeout">Timeout in milliseconds</param> | ||
183 | /// <param name="cancelEvent">Cancel wait handle</param> | ||
184 | /// <returns>Returns true if the resource was granted</returns> | ||
185 | public WorkItem DequeueWorkItem( | ||
186 | int millisecondsTimeout, | ||
187 | WaitHandle cancelEvent) | ||
188 | { | ||
189 | // This method cause the caller to wait for a work item. | ||
190 | // If there is at least one waiting work item then the | ||
191 | // method returns immidiately with it. | ||
192 | // | ||
193 | // If there are no waiting work items then the caller | ||
194 | // is queued between other waiters for a work item to arrive. | ||
195 | // | ||
196 | // If a work item didn't come within millisecondsTimeout or | ||
197 | // the user canceled the wait by signaling the cancelEvent | ||
198 | // then the method returns null to indicate that the caller | ||
199 | // didn't get a work item. | ||
200 | |||
201 | WaiterEntry waiterEntry; | ||
202 | WorkItem workItem = null; | ||
203 | lock (this) | ||
204 | { | ||
205 | ValidateNotDisposed(); | ||
206 | |||
207 | // If there are waiting work items then take one and return. | ||
208 | if (_workItems.Count > 0) | ||
209 | { | ||
210 | workItem = _workItems.Dequeue() as WorkItem; | ||
211 | return workItem; | ||
212 | } | ||
213 | |||
214 | // No waiting work items ... | ||
215 | |||
216 | // Get the waiter entry for the waiters queue | ||
217 | waiterEntry = GetThreadWaiterEntry(); | ||
218 | |||
219 | // Put the waiter with the other waiters | ||
220 | PushWaiter(waiterEntry); | ||
221 | } | ||
222 | |||
223 | // Prepare array of wait handle for the WaitHandle.WaitAny() | ||
224 | WaitHandle [] waitHandles = new WaitHandle[] { | ||
225 | waiterEntry.WaitHandle, | ||
226 | cancelEvent }; | ||
227 | |||
228 | // Wait for an available resource, cancel event, or timeout. | ||
229 | |||
230 | // During the wait we are supposes to exit the synchronization | ||
231 | // domain. (Placing true as the third argument of the WaitAny()) | ||
232 | // It just doesn't work, I don't know why, so I have two lock(this) | ||
233 | // statments instead of one. | ||
234 | |||
235 | int index = STPEventWaitHandle.WaitAny( | ||
236 | waitHandles, | ||
237 | millisecondsTimeout, | ||
238 | true); | ||
239 | |||
240 | lock(this) | ||
241 | { | ||
242 | // success is true if it got a work item. | ||
243 | bool success = (0 == index); | ||
244 | |||
245 | // The timeout variable is used only for readability. | ||
246 | // (We treat cancel as timeout) | ||
247 | bool timeout = !success; | ||
248 | |||
249 | // On timeout update the waiterEntry that it is timed out | ||
250 | if (timeout) | ||
251 | { | ||
252 | // The Timeout() fails if the waiter has already been signaled | ||
253 | timeout = waiterEntry.Timeout(); | ||
254 | |||
255 | // On timeout remove the waiter from the queue. | ||
256 | // Note that the complexity is O(1). | ||
257 | if(timeout) | ||
258 | { | ||
259 | RemoveWaiter(waiterEntry, false); | ||
260 | } | ||
261 | |||
262 | // Again readability | ||
263 | success = !timeout; | ||
264 | } | ||
265 | |||
266 | // On success return the work item | ||
267 | if (success) | ||
268 | { | ||
269 | workItem = waiterEntry.WorkItem; | ||
270 | |||
271 | if (null == workItem) | ||
272 | { | ||
273 | workItem = _workItems.Dequeue() as WorkItem; | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | // On failure return null. | ||
278 | return workItem; | ||
279 | } | ||
280 | |||
281 | /// <summary> | ||
282 | /// Cleanup the work items queue, hence no more work | ||
283 | /// items are allowed to be queue | ||
284 | /// </summary> | ||
285 | private void Cleanup() | ||
286 | { | ||
287 | lock(this) | ||
288 | { | ||
289 | // Deactivate only once | ||
290 | if (!_isWorkItemsQueueActive) | ||
291 | { | ||
292 | return; | ||
293 | } | ||
294 | |||
295 | // Don't queue more work items | ||
296 | _isWorkItemsQueueActive = false; | ||
297 | |||
298 | foreach(WorkItem workItem in _workItems) | ||
299 | { | ||
300 | workItem.DisposeOfState(); | ||
301 | } | ||
302 | |||
303 | // Clear the work items that are already queued | ||
304 | _workItems.Clear(); | ||
305 | |||
306 | // Note: | ||
307 | // I don't iterate over the queue and dispose of work items's states, | ||
308 | // since if a work item has a state object that is still in use in the | ||
309 | // application then I must not dispose it. | ||
310 | |||
311 | // Tell the waiters that they were timed out. | ||
312 | // It won't signal them to exit, but to ignore their | ||
313 | // next work item. | ||
314 | while(_waitersCount > 0) | ||
315 | { | ||
316 | WaiterEntry waiterEntry = PopWaiter(); | ||
317 | waiterEntry.Timeout(); | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | public object[] GetStates() | ||
323 | { | ||
324 | lock (this) | ||
325 | { | ||
326 | object[] states = new object[_workItems.Count]; | ||
327 | int i = 0; | ||
328 | foreach (WorkItem workItem in _workItems) | ||
329 | { | ||
330 | states[i] = workItem.GetWorkItemResult().State; | ||
331 | ++i; | ||
332 | } | ||
333 | return states; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | #endregion | ||
338 | |||
339 | #region Private methods | ||
340 | |||
341 | /// <summary> | ||
342 | /// Returns the WaiterEntry of the current thread | ||
343 | /// </summary> | ||
344 | /// <returns></returns> | ||
345 | /// In order to avoid creation and destuction of WaiterEntry | ||
346 | /// objects each thread has its own WaiterEntry object. | ||
347 | private static WaiterEntry GetThreadWaiterEntry() | ||
348 | { | ||
349 | if (null == CurrentWaiterEntry) | ||
350 | { | ||
351 | CurrentWaiterEntry = new WaiterEntry(); | ||
352 | } | ||
353 | CurrentWaiterEntry.Reset(); | ||
354 | return CurrentWaiterEntry; | ||
355 | } | ||
356 | |||
357 | #region Waiters stack methods | ||
358 | |||
359 | /// <summary> | ||
360 | /// Push a new waiter into the waiter's stack | ||
361 | /// </summary> | ||
362 | /// <param name="newWaiterEntry">A waiter to put in the stack</param> | ||
363 | public void PushWaiter(WaiterEntry newWaiterEntry) | ||
364 | { | ||
365 | // Remove the waiter if it is already in the stack and | ||
366 | // update waiter's count as needed | ||
367 | RemoveWaiter(newWaiterEntry, false); | ||
368 | |||
369 | // If the stack is empty then newWaiterEntry is the new head of the stack | ||
370 | if (null == _headWaiterEntry._nextWaiterEntry) | ||
371 | { | ||
372 | _headWaiterEntry._nextWaiterEntry = newWaiterEntry; | ||
373 | newWaiterEntry._prevWaiterEntry = _headWaiterEntry; | ||
374 | |||
375 | } | ||
376 | // If the stack is not empty then put newWaiterEntry as the new head | ||
377 | // of the stack. | ||
378 | else | ||
379 | { | ||
380 | // Save the old first waiter entry | ||
381 | WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; | ||
382 | |||
383 | // Update the links | ||
384 | _headWaiterEntry._nextWaiterEntry = newWaiterEntry; | ||
385 | newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; | ||
386 | newWaiterEntry._prevWaiterEntry = _headWaiterEntry; | ||
387 | oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; | ||
388 | } | ||
389 | |||
390 | // Increment the number of waiters | ||
391 | ++_waitersCount; | ||
392 | } | ||
393 | |||
394 | /// <summary> | ||
395 | /// Pop a waiter from the waiter's stack | ||
396 | /// </summary> | ||
397 | /// <returns>Returns the first waiter in the stack</returns> | ||
398 | private WaiterEntry PopWaiter() | ||
399 | { | ||
400 | // Store the current stack head | ||
401 | WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; | ||
402 | |||
403 | // Store the new stack head | ||
404 | WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; | ||
405 | |||
406 | // Update the old stack head list links and decrement the number | ||
407 | // waiters. | ||
408 | RemoveWaiter(oldFirstWaiterEntry, true); | ||
409 | |||
410 | // Update the new stack head | ||
411 | _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; | ||
412 | if (null != newHeadWaiterEntry) | ||
413 | { | ||
414 | newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; | ||
415 | } | ||
416 | |||
417 | // Return the old stack head | ||
418 | return oldFirstWaiterEntry; | ||
419 | } | ||
420 | |||
421 | /// <summary> | ||
422 | /// Remove a waiter from the stack | ||
423 | /// </summary> | ||
424 | /// <param name="waiterEntry">A waiter entry to remove</param> | ||
425 | /// <param name="popDecrement">If true the waiter count is always decremented</param> | ||
426 | private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) | ||
427 | { | ||
428 | // Store the prev entry in the list | ||
429 | WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; | ||
430 | |||
431 | // Store the next entry in the list | ||
432 | WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; | ||
433 | |||
434 | // A flag to indicate if we need to decrement the waiters count. | ||
435 | // If we got here from PopWaiter then we must decrement. | ||
436 | // If we got here from PushWaiter then we decrement only if | ||
437 | // the waiter was already in the stack. | ||
438 | bool decrementCounter = popDecrement; | ||
439 | |||
440 | // Null the waiter's entry links | ||
441 | waiterEntry._prevWaiterEntry = null; | ||
442 | waiterEntry._nextWaiterEntry = null; | ||
443 | |||
444 | // If the waiter entry had a prev link then update it. | ||
445 | // It also means that the waiter is already in the list and we | ||
446 | // need to decrement the waiters count. | ||
447 | if (null != prevWaiterEntry) | ||
448 | { | ||
449 | prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; | ||
450 | decrementCounter = true; | ||
451 | } | ||
452 | |||
453 | // If the waiter entry had a next link then update it. | ||
454 | // It also means that the waiter is already in the list and we | ||
455 | // need to decrement the waiters count. | ||
456 | if (null != nextWaiterEntry) | ||
457 | { | ||
458 | nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; | ||
459 | decrementCounter = true; | ||
460 | } | ||
461 | |||
462 | // Decrement the waiters count if needed | ||
463 | if (decrementCounter) | ||
464 | { | ||
465 | --_waitersCount; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | #endregion | ||
470 | |||
471 | #endregion | ||
472 | |||
473 | #region WaiterEntry class | ||
474 | |||
475 | // A waiter entry in the _waiters queue. | ||
476 | public sealed class WaiterEntry : IDisposable | ||
477 | { | ||
478 | #region Member variables | ||
479 | |||
480 | /// <summary> | ||
481 | /// Event to signal the waiter that it got the work item. | ||
482 | /// </summary> | ||
483 | //private AutoResetEvent _waitHandle = new AutoResetEvent(false); | ||
484 | private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); | ||
485 | |||
486 | /// <summary> | ||
487 | /// Flag to know if this waiter already quited from the queue | ||
488 | /// because of a timeout. | ||
489 | /// </summary> | ||
490 | private bool _isTimedout = false; | ||
491 | |||
492 | /// <summary> | ||
493 | /// Flag to know if the waiter was signaled and got a work item. | ||
494 | /// </summary> | ||
495 | private bool _isSignaled = false; | ||
496 | |||
497 | /// <summary> | ||
498 | /// A work item that passed directly to the waiter withou going | ||
499 | /// through the queue | ||
500 | /// </summary> | ||
501 | private WorkItem _workItem = null; | ||
502 | |||
503 | private bool _isDisposed = false; | ||
504 | |||
505 | // Linked list members | ||
506 | internal WaiterEntry _nextWaiterEntry = null; | ||
507 | internal WaiterEntry _prevWaiterEntry = null; | ||
508 | |||
509 | #endregion | ||
510 | |||
511 | #region Construction | ||
512 | |||
513 | public WaiterEntry() | ||
514 | { | ||
515 | Reset(); | ||
516 | } | ||
517 | |||
518 | #endregion | ||
519 | |||
520 | #region Public methods | ||
521 | |||
522 | public WaitHandle WaitHandle | ||
523 | { | ||
524 | get { return _waitHandle; } | ||
525 | } | ||
526 | |||
527 | public WorkItem WorkItem | ||
528 | { | ||
529 | get | ||
530 | { | ||
531 | return _workItem; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | /// <summary> | ||
536 | /// Signal the waiter that it got a work item. | ||
537 | /// </summary> | ||
538 | /// <returns>Return true on success</returns> | ||
539 | /// The method fails if Timeout() preceded its call | ||
540 | public bool Signal(WorkItem workItem) | ||
541 | { | ||
542 | lock(this) | ||
543 | { | ||
544 | if (!_isTimedout) | ||
545 | { | ||
546 | _workItem = workItem; | ||
547 | _isSignaled = true; | ||
548 | _waitHandle.Set(); | ||
549 | return true; | ||
550 | } | ||
551 | } | ||
552 | return false; | ||
553 | } | ||
554 | |||
555 | /// <summary> | ||
556 | /// Mark the wait entry that it has been timed out | ||
557 | /// </summary> | ||
558 | /// <returns>Return true on success</returns> | ||
559 | /// The method fails if Signal() preceded its call | ||
560 | public bool Timeout() | ||
561 | { | ||
562 | lock(this) | ||
563 | { | ||
564 | // Time out can happen only if the waiter wasn't marked as | ||
565 | // signaled | ||
566 | if (!_isSignaled) | ||
567 | { | ||
568 | // We don't remove the waiter from the queue, the DequeueWorkItem | ||
569 | // method skips _waiters that were timed out. | ||
570 | _isTimedout = true; | ||
571 | return true; | ||
572 | } | ||
573 | } | ||
574 | return false; | ||
575 | } | ||
576 | |||
577 | /// <summary> | ||
578 | /// Reset the wait entry so it can be used again | ||
579 | /// </summary> | ||
580 | public void Reset() | ||
581 | { | ||
582 | _workItem = null; | ||
583 | _isTimedout = false; | ||
584 | _isSignaled = false; | ||
585 | _waitHandle.Reset(); | ||
586 | } | ||
587 | |||
588 | /// <summary> | ||
589 | /// Free resources | ||
590 | /// </summary> | ||
591 | public void Close() | ||
592 | { | ||
593 | if (null != _waitHandle) | ||
594 | { | ||
595 | _waitHandle.Close(); | ||
596 | _waitHandle = null; | ||
597 | } | ||
598 | } | ||
599 | |||
600 | #endregion | ||
601 | |||
602 | #region IDisposable Members | ||
603 | |||
604 | public void Dispose() | ||
605 | { | ||
606 | lock (this) | ||
607 | { | ||
608 | if (!_isDisposed) | ||
609 | { | ||
610 | Close(); | ||
611 | } | ||
612 | _isDisposed = true; | ||
613 | } | ||
614 | } | ||
615 | |||
616 | #endregion | ||
617 | } | ||
618 | |||
619 | #endregion | ||
620 | |||
621 | #region IDisposable Members | ||
622 | |||
623 | public void Dispose() | ||
624 | { | ||
625 | if (!_isDisposed) | ||
626 | { | ||
627 | Cleanup(); | ||
628 | _headWaiterEntry.Close(); | ||
629 | } | ||
630 | _isDisposed = true; | ||
631 | } | ||
632 | |||
633 | private void ValidateNotDisposed() | ||
634 | { | ||
635 | if(_isDisposed) | ||
636 | { | ||
637 | throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | #endregion | ||
642 | } | ||
643 | |||
644 | #endregion | ||
645 | } | ||
646 | |||
diff --git a/ThirdPartyLicenses/Aurora-Sim.txt b/ThirdPartyLicenses/Aurora-Sim.txt new file mode 100644 index 0000000..162d552 --- /dev/null +++ b/ThirdPartyLicenses/Aurora-Sim.txt | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://aurora-sim.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the Aurora-Sim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
diff --git a/ThirdPartyLicenses/Axiom.txt b/ThirdPartyLicenses/Axiom.txt new file mode 100644 index 0000000..fe97db2 --- /dev/null +++ b/ThirdPartyLicenses/Axiom.txt | |||
@@ -0,0 +1,141 @@ | |||
1 | GNU LESSER GENERAL PUBLIC LICENSE | ||
2 | Version 2.1, February 1999 | ||
3 | |||
4 | |||
5 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. | ||
6 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
7 | Everyone is permitted to copy and distribute verbatim copies | ||
8 | of this license document, but changing it is not allowed. | ||
9 | |||
10 | [This is the first released version of the Lesser GPL. It also counts | ||
11 | as the successor of the GNU Library Public License, version 2, hence | ||
12 | the version number 2.1.] | ||
13 | |||
14 | Preamble | ||
15 | The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. | ||
16 | |||
17 | This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. | ||
18 | |||
19 | When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. | ||
20 | |||
21 | To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. | ||
22 | |||
23 | For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. | ||
24 | |||
25 | We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. | ||
26 | |||
27 | To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. | ||
28 | |||
29 | Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. | ||
30 | |||
31 | Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. | ||
32 | |||
33 | When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. | ||
34 | |||
35 | We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. | ||
36 | |||
37 | For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. | ||
38 | |||
39 | In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. | ||
40 | |||
41 | Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. | ||
42 | |||
43 | The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. | ||
44 | |||
45 | |||
46 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||
47 | 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". | ||
48 | |||
49 | A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. | ||
50 | |||
51 | The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) | ||
52 | |||
53 | "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. | ||
54 | |||
55 | Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. | ||
56 | |||
57 | 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. | ||
58 | |||
59 | You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. | ||
60 | |||
61 | 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: | ||
62 | |||
63 | |||
64 | a) The modified work must itself be a software library. | ||
65 | b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. | ||
66 | c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. | ||
67 | d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. | ||
68 | (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) | ||
69 | |||
70 | These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. | ||
71 | |||
72 | Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. | ||
73 | |||
74 | In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. | ||
75 | |||
76 | 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. | ||
77 | |||
78 | Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. | ||
79 | |||
80 | This option is useful when you wish to copy part of the code of the Library into a program that is not a library. | ||
81 | |||
82 | 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. | ||
83 | |||
84 | If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. | ||
85 | |||
86 | 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. | ||
87 | |||
88 | However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. | ||
89 | |||
90 | When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. | ||
91 | |||
92 | If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) | ||
93 | |||
94 | Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. | ||
95 | |||
96 | 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. | ||
97 | |||
98 | You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: | ||
99 | |||
100 | |||
101 | a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) | ||
102 | b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. | ||
103 | c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. | ||
104 | d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. | ||
105 | e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. | ||
106 | For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. | ||
107 | |||
108 | It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. | ||
109 | |||
110 | 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: | ||
111 | |||
112 | |||
113 | a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. | ||
114 | b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. | ||
115 | 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. | ||
116 | |||
117 | 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. | ||
118 | |||
119 | 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. | ||
120 | |||
121 | 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. | ||
122 | |||
123 | If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. | ||
124 | |||
125 | It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. | ||
126 | |||
127 | This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. | ||
128 | |||
129 | 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. | ||
130 | |||
131 | 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. | ||
132 | |||
133 | Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. | ||
134 | |||
135 | 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. | ||
136 | |||
137 | NO WARRANTY | ||
138 | |||
139 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||
140 | |||
141 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/BclExtras.txt b/ThirdPartyLicenses/BclExtras.txt new file mode 100644 index 0000000..a8a0292 --- /dev/null +++ b/ThirdPartyLicenses/BclExtras.txt | |||
@@ -0,0 +1,60 @@ | |||
1 | MICROSOFT PUBLIC LICENSE (Ms-PL) | ||
2 | |||
3 | This license governs use of the accompanying software. If you use the software, | ||
4 | you accept this license. If you do not accept the license, do not use the | ||
5 | software. | ||
6 | |||
7 | 1. Definitions | ||
8 | |||
9 | The terms "reproduce," "reproduction," "derivative works," and "distribution" | ||
10 | have the same meaning here as under U.S. copyright law. | ||
11 | |||
12 | A "contribution" is the original software, or any additions or changes to the | ||
13 | software. | ||
14 | |||
15 | A "contributor" is any person that distributes its contribution under this | ||
16 | license. | ||
17 | |||
18 | "Licensed patents" are a contributor's patent claims that read directly on its | ||
19 | contribution. | ||
20 | |||
21 | 2. Grant of Rights | ||
22 | |||
23 | (A) Copyright Grant- Subject to the terms of this license, including the license | ||
24 | conditions and limitations in section 3, each contributor grants you a | ||
25 | non-exclusive, worldwide, royalty-free copyright license to reproduce its | ||
26 | contribution, prepare derivative works of its contribution, and distribute its | ||
27 | contribution or any derivative works that you create. | ||
28 | |||
29 | (B) Patent Grant- Subject to the terms of this license, including the license | ||
30 | conditions and limitations in section 3, each contributor grants you a | ||
31 | non-exclusive, worldwide, royalty-free license under its licensed patents to | ||
32 | make, have made, use, sell, offer for sale, import, and/or otherwise dispose of | ||
33 | its contribution in the software or derivative works of the contribution in the | ||
34 | software. | ||
35 | |||
36 | 3. Conditions and Limitations | ||
37 | |||
38 | (A) No Trademark License- This license does not grant you rights to use any | ||
39 | contributors' name, logo, or trademarks. | ||
40 | |||
41 | (B) If you bring a patent claim against any contributor over patents that you | ||
42 | claim are infringed by the software, your patent license from such contributor | ||
43 | to the software ends automatically. | ||
44 | |||
45 | (C) If you distribute any portion of the software, you must retain all | ||
46 | copyright, patent, trademark, and attribution notices that are present in the | ||
47 | software. | ||
48 | |||
49 | (D) If you distribute any portion of the software in source code form, you may | ||
50 | do so only under this license by including a complete copy of this license with | ||
51 | your distribution. If you distribute any portion of the software in compiled or | ||
52 | object code form, you may only do so under a license that complies with this | ||
53 | license. | ||
54 | |||
55 | (E) The software is licensed "as-is." You bear the risk of using it. The | ||
56 | contributors give no express warranties, guarantees or conditions. You may have | ||
57 | additional consumer rights under your local laws which this license cannot | ||
58 | change. To the extent permitted under your local laws, the contributors exclude | ||
59 | the implied warranties of merchantability, fitness for a particular purpose and | ||
60 | non-infringement. | ||
diff --git a/ThirdPartyLicenses/Bullet for Xna (ModifiedBulletX).txt b/ThirdPartyLicenses/Bullet for Xna (ModifiedBulletX).txt new file mode 100644 index 0000000..a8ed924 --- /dev/null +++ b/ThirdPartyLicenses/Bullet for Xna (ModifiedBulletX).txt | |||
@@ -0,0 +1,19 @@ | |||
1 | Bullet for XNA Copyright (c) 2003-2007 Vsevolod Klementjev http://www.codeplex.com/xnadevru | ||
2 | Bullet original C++ version Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com | ||
3 | |||
4 | This software is provided 'as-is', without any express or implied | ||
5 | warranty. In no event will the authors be held liable for any damages | ||
6 | arising from the use of this software. | ||
7 | |||
8 | Permission is granted to anyone to use this software for any purpose, | ||
9 | including commercial applications, and to alter it and redistribute it | ||
10 | freely, subject to the following restrictions: | ||
11 | |||
12 | 1. The origin of this software must not be misrepresented; you must not | ||
13 | claim that you wrote the original software. If you use this software | ||
14 | in a product, an acknowledgment in the product documentation would be | ||
15 | appreciated but is not required. | ||
16 | 2. Altered source versions must be plainly marked as such, and must not be | ||
17 | misrepresented as being the original software. | ||
18 | 3. This notice may not be removed or altered from any source distribution. | ||
19 | \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/Bullet-XNA.txt b/ThirdPartyLicenses/Bullet-XNA.txt new file mode 100644 index 0000000..5d8899b --- /dev/null +++ b/ThirdPartyLicenses/Bullet-XNA.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * C# / XNA port of Bullet (c) 2011 Mark Neale <xexuxjy@hotmail.com> | ||
3 | * http://code.google.com/p/bullet-xna/ | ||
4 | * | ||
5 | * Bullet Continuous Collision Detection and Physics Library | ||
6 | * Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/ | ||
7 | * | ||
8 | * This software is provided 'as-is', without any express or implied warranty. | ||
9 | * In no event will the authors be held liable for any damages arising from | ||
10 | * the use of this software. | ||
11 | * | ||
12 | * Permission is granted to anyone to use this software for any purpose, | ||
13 | * including commercial applications, and to alter it and redistribute it | ||
14 | * freely, subject to the following restrictions: | ||
15 | * | ||
16 | * 1. The origin of this software must not be misrepresented; you must not | ||
17 | * claim that you wrote the original software. If you use this software | ||
18 | * in a product, an acknowledgment in the product documentation would be | ||
19 | * appreciated but is not required. | ||
20 | * 2. Altered source versions must be plainly marked as such, and must not be | ||
21 | * misrepresented as being the original software. | ||
22 | * 3. This notice may not be removed or altered from any source distribution. | ||
23 | */ \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/BulletLicense.txt b/ThirdPartyLicenses/BulletLicense.txt new file mode 100644 index 0000000..c3ec68c --- /dev/null +++ b/ThirdPartyLicenses/BulletLicense.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | ||
3 | |||
4 | This software is provided 'as-is', without any express or implied warranty. | ||
5 | In no event will the authors be held liable for any damages arising from the use of this software. | ||
6 | Permission is granted to anyone to use this software for any purpose, | ||
7 | including commercial applications, and to alter it and redistribute it freely, | ||
8 | subject to the following restrictions: | ||
9 | |||
10 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | ||
11 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | ||
12 | 3. This notice may not be removed or altered from any source distribution. | ||
13 | */ | ||
14 | |||
15 | |||
16 | Free for commercial use, but please mail bullet@erwincoumans.com to report projects, and join the forum at | ||
17 | www.continuousphysics.com/Bullet/phpBB2 | ||
diff --git a/ThirdPartyLicenses/C# Webserver.txt b/ThirdPartyLicenses/C# Webserver.txt new file mode 100644 index 0000000..b996891 --- /dev/null +++ b/ThirdPartyLicenses/C# Webserver.txt | |||
@@ -0,0 +1,71 @@ | |||
1 | Files: HttpServer_OpenSim.dll | ||
2 | |||
3 | Apache License | ||
4 | Version 2.0, January 2004 | ||
5 | http://www.apache.org/licenses/ | ||
6 | |||
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
8 | |||
9 | 1. Definitions. | ||
10 | |||
11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. | ||
12 | |||
13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. | ||
14 | |||
15 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. | ||
16 | |||
17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. | ||
18 | |||
19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. | ||
20 | |||
21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. | ||
22 | |||
23 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). | ||
24 | |||
25 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. | ||
26 | |||
27 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." | ||
28 | |||
29 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. | ||
30 | |||
31 | 2. Grant of Copyright License. | ||
32 | |||
33 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. | ||
34 | |||
35 | 3. Grant of Patent License. | ||
36 | |||
37 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. | ||
38 | |||
39 | 4. Redistribution. | ||
40 | |||
41 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: | ||
42 | |||
43 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and | ||
44 | |||
45 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and | ||
46 | |||
47 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and | ||
48 | |||
49 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. | ||
50 | |||
51 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. | ||
52 | |||
53 | 5. Submission of Contributions. | ||
54 | |||
55 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. | ||
56 | |||
57 | 6. Trademarks. | ||
58 | |||
59 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. | ||
60 | |||
61 | 7. Disclaimer of Warranty. | ||
62 | |||
63 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. | ||
64 | |||
65 | 8. Limitation of Liability. | ||
66 | |||
67 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. | ||
68 | |||
69 | 9. Accepting Warranty or Additional Liability. | ||
70 | |||
71 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/C5.txt b/ThirdPartyLicenses/C5.txt new file mode 100644 index 0000000..4c3a049 --- /dev/null +++ b/ThirdPartyLicenses/C5.txt | |||
@@ -0,0 +1,19 @@ | |||
1 | Copyright (c) 2003-2008 Niels Kokholm and Peter Sestoft. | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | of this software and associated documentation files (the "Software"), to deal | ||
5 | in the Software without restriction, including without limitation the rights | ||
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | copies of the Software, and to permit persons to whom the Software is | ||
8 | furnished to do so, subject to the following conditions: | ||
9 | |||
10 | The above copyright notice and this permission notice shall be included in | ||
11 | all copies or substantial portions of the Software. | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | SOFTWARE \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/CSCompilerTools.txt b/ThirdPartyLicenses/CSCompilerTools.txt new file mode 100644 index 0000000..c2567bd --- /dev/null +++ b/ThirdPartyLicenses/CSCompilerTools.txt | |||
@@ -0,0 +1,12 @@ | |||
1 | The LSL compiler is generated with "Compiler tools in C#" version 4.7[1] by Dr. Malcolm Crowe[2]. The code is used with permission by the author: | ||
2 | |||
3 | There is no problem with using the code in any way you like, as long as | ||
4 | somewhere you say that that is what you have done (in the source for | ||
5 | example). | ||
6 | And of course we disclaim all responsibility for any resulting | ||
7 | damage... | ||
8 | Best wishes | ||
9 | Malcolm Crowe | ||
10 | |||
11 | [1] http://cis.paisley.ac.uk/crow-ci0/CSTools47.zip | ||
12 | [2] http://cis.paisley.ac.uk/crow-ci0/ | ||
diff --git a/ThirdPartyLicenses/CSJ2K.txt b/ThirdPartyLicenses/CSJ2K.txt new file mode 100644 index 0000000..3032548 --- /dev/null +++ b/ThirdPartyLicenses/CSJ2K.txt | |||
@@ -0,0 +1,28 @@ | |||
1 | Copyright (c) 1999/2000 JJ2000 Partners. | ||
2 | |||
3 | This software module was originally developed by Raphaël Grosbois and | ||
4 | Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel | ||
5 | Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David | ||
6 | Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research | ||
7 | Centre France S.A) in the course of development of the JPEG2000 | ||
8 | standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This | ||
9 | software module is an implementation of a part of the JPEG 2000 | ||
10 | Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio | ||
11 | Systems AB and Canon Research Centre France S.A (collectively JJ2000 | ||
12 | Partners) agree not to assert against ISO/IEC and users of the JPEG | ||
13 | 2000 Standard (Users) any of their rights under the copyright, not | ||
14 | including other intellectual property rights, for this software module | ||
15 | with respect to the usage by ISO/IEC and Users of this software module | ||
16 | or modifications thereof for use in hardware or software products | ||
17 | claiming conformance to the JPEG 2000 Standard. Those intending to use | ||
18 | this software module in hardware or software products are advised that | ||
19 | their use may infringe existing patents. The original developers of | ||
20 | this software module, JJ2000 Partners and ISO/IEC assume no liability | ||
21 | for use of this software module or modifications thereof. No license | ||
22 | or right to this software module is granted for non JPEG 2000 Standard | ||
23 | conforming products. JJ2000 Partners have full right to use this | ||
24 | software module for his/her own purpose, assign or donate this | ||
25 | software module to any third party and to inhibit third parties from | ||
26 | using this software module for non JPEG 2000 Standard conforming | ||
27 | products. This copyright notice must be included in all copies or | ||
28 | derivative works of this software module. | ||
diff --git a/ThirdPartyLicenses/CircularBuffer.txt b/ThirdPartyLicenses/CircularBuffer.txt new file mode 100644 index 0000000..09c37d9 --- /dev/null +++ b/ThirdPartyLicenses/CircularBuffer.txt | |||
@@ -0,0 +1,16 @@ | |||
1 | Copyright (c) 2012, Alex Regueiro | ||
2 | All rights reserved. | ||
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the | ||
4 | following conditions are met: | ||
5 | |||
6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer | ||
8 | in the documentation and/or other materials provided with the distribution. | ||
9 | |||
10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, | ||
11 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
12 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | ||
13 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | ||
14 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
15 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
16 | POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/ConvexDecompositionDotNet.txt b/ThirdPartyLicenses/ConvexDecompositionDotNet.txt new file mode 100644 index 0000000..714ae89 --- /dev/null +++ b/ThirdPartyLicenses/ConvexDecompositionDotNet.txt | |||
@@ -0,0 +1,28 @@ | |||
1 | ConvexDecompositionDotNet | ||
2 | ------------------------- | ||
3 | |||
4 | The MIT License | ||
5 | |||
6 | Copyright (c) 2010 Intel Corporation. | ||
7 | All rights reserved. | ||
8 | |||
9 | Based on the convexdecomposition library from | ||
10 | <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
11 | |||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | of this software and associated documentation files (the "Software"), to deal | ||
14 | in the Software without restriction, including without limitation the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | copies of the Software, and to permit persons to whom the Software is | ||
17 | furnished to do so, subject to the following conditions: | ||
18 | |||
19 | The above copyright notice and this permission notice shall be included in | ||
20 | all copies or substantial portions of the Software. | ||
21 | |||
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | THE SOFTWARE. | ||
diff --git a/ThirdPartyLicenses/DefaultTerrain.txt b/ThirdPartyLicenses/DefaultTerrain.txt new file mode 100644 index 0000000..112beff --- /dev/null +++ b/ThirdPartyLicenses/DefaultTerrain.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | COPYRIGHT AND PERMISSION NOTICE | ||
2 | |||
3 | Second Life(TM) Viewer Artwork. Copyright (C) 2008 Linden Research, Inc. | ||
4 | |||
5 | Linden Research, Inc. ("Linden Lab") licenses the Second Life viewer | ||
6 | artwork and other works in the files distributed with this Notice under | ||
7 | the Creative Commons Attribution-Share Alike 3.0 License, available at | ||
8 | http://creativecommons.org/licenses/by-sa/3.0/legalcode. [^] For the license | ||
9 | summary, see http://creativecommons.org/licenses/by-sa/3.0/. | ||
10 | |||
11 | Notwithstanding the foregoing, all of Linden Lab's trademarks, including | ||
12 | but not limited to the Second Life brand name and Second Life Eye-in-Hand | ||
13 | logo, are subject to our trademark policy at | ||
14 | http://secondlife.com/corporate/trademark/. | ||
15 | |||
16 | If you distribute any copies or adaptations of the Second Life viewer | ||
17 | artwork or any other works in these files, you must include this Notice | ||
18 | and clearly identify any changes made to the original works. Include | ||
19 | this Notice and information where copyright notices are usually included, | ||
20 | for example, after your own copyright notice acknowledging your use of | ||
21 | the Second Life viewer artwork, in a text file distributed with your | ||
22 | program, in your application's About window, or on a credits page for | ||
23 | your work. | ||
diff --git a/ThirdPartyLicenses/DotNetOpenid.txt b/ThirdPartyLicenses/DotNetOpenid.txt new file mode 100644 index 0000000..6833494 --- /dev/null +++ b/ThirdPartyLicenses/DotNetOpenid.txt | |||
@@ -0,0 +1,10 @@ | |||
1 | Copyright (c) 2008, Andrew Arnott, Scott Hanselman, Jason Alexander, et. al | ||
2 | All rights reserved. | ||
3 | |||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
8 | * Neither the name of the DotNetOpenId nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | ||
9 | |||
10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/DotNetZip-bzip2.txt b/ThirdPartyLicenses/DotNetZip-bzip2.txt new file mode 100644 index 0000000..f8b4346 --- /dev/null +++ b/ThirdPartyLicenses/DotNetZip-bzip2.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | |||
2 | The managed BZIP2 code included in Ionic.BZip2.dll and Ionic.Zip.dll is | ||
3 | modified code, based on the bzip2 code in the Apache commons compress | ||
4 | library. | ||
5 | |||
6 | The original BZip2 was created by Julian Seward, and is licensed under | ||
7 | the BSD license. | ||
8 | |||
9 | The following license applies to the Apache code: | ||
10 | ----------------------------------------------------------------------- | ||
11 | |||
12 | /* | ||
13 | * Licensed to the Apache Software Foundation (ASF) under one | ||
14 | * or more contributor license agreements. See the NOTICE file | ||
15 | * distributed with this work for additional information | ||
16 | * regarding copyright ownership. The ASF licenses this file | ||
17 | * to you under the Apache License, Version 2.0 (the | ||
18 | * "License"); you may not use this file except in compliance | ||
19 | * with the License. You may obtain a copy of the License at | ||
20 | * | ||
21 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
22 | * | ||
23 | * Unless required by applicable law or agreed to in writing, | ||
24 | * software distributed under the License is distributed on an | ||
25 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
26 | * KIND, either express or implied. See the License for the | ||
27 | * specific language governing permissions and limitations | ||
28 | * under the License. | ||
29 | */ | ||
diff --git a/ThirdPartyLicenses/DotNetZip-zlib.txt b/ThirdPartyLicenses/DotNetZip-zlib.txt new file mode 100644 index 0000000..801e941 --- /dev/null +++ b/ThirdPartyLicenses/DotNetZip-zlib.txt | |||
@@ -0,0 +1,70 @@ | |||
1 | |||
2 | The following licenses govern use of the accompanying software, the | ||
3 | DotNetZip library ("the software"). If you use the software, you accept | ||
4 | these licenses. If you do not accept the license, do not use the software. | ||
5 | |||
6 | The managed ZLIB code included in Ionic.Zlib.dll and Ionic.Zip.dll is | ||
7 | modified code, based on jzlib. | ||
8 | |||
9 | |||
10 | |||
11 | The following notice applies to jzlib: | ||
12 | ----------------------------------------------------------------------- | ||
13 | |||
14 | Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. | ||
15 | |||
16 | Redistribution and use in source and binary forms, with or without | ||
17 | modification, are permitted provided that the following conditions are met: | ||
18 | |||
19 | 1. Redistributions of source code must retain the above copyright notice, | ||
20 | this list of conditions and the following disclaimer. | ||
21 | |||
22 | 2. Redistributions in binary form must reproduce the above copyright | ||
23 | notice, this list of conditions and the following disclaimer in | ||
24 | the documentation and/or other materials provided with the distribution. | ||
25 | |||
26 | 3. The names of the authors may not be used to endorse or promote products | ||
27 | derived from this software without specific prior written permission. | ||
28 | |||
29 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, | ||
30 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
31 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, | ||
32 | INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
33 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
34 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | ||
35 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
36 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
37 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | ||
38 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
39 | |||
40 | ----------------------------------------------------------------------- | ||
41 | |||
42 | jzlib is based on zlib-1.1.3. | ||
43 | |||
44 | The following notice applies to zlib: | ||
45 | |||
46 | ----------------------------------------------------------------------- | ||
47 | |||
48 | Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler | ||
49 | |||
50 | The ZLIB software is provided 'as-is', without any express or implied | ||
51 | warranty. In no event will the authors be held liable for any damages | ||
52 | arising from the use of this software. | ||
53 | |||
54 | Permission is granted to anyone to use this software for any purpose, | ||
55 | including commercial applications, and to alter it and redistribute it | ||
56 | freely, subject to the following restrictions: | ||
57 | |||
58 | 1. The origin of this software must not be misrepresented; you must not | ||
59 | claim that you wrote the original software. If you use this software | ||
60 | in a product, an acknowledgment in the product documentation would be | ||
61 | appreciated but is not required. | ||
62 | 2. Altered source versions must be plainly marked as such, and must not be | ||
63 | misrepresented as being the original software. | ||
64 | 3. This notice may not be removed or altered from any source distribution. | ||
65 | |||
66 | Jean-loup Gailly jloup@gzip.org | ||
67 | Mark Adler madler@alumni.caltech.edu | ||
68 | |||
69 | |||
70 | ----------------------------------------------------------------------- | ||
diff --git a/ThirdPartyLicenses/DotNetZip.txt b/ThirdPartyLicenses/DotNetZip.txt new file mode 100644 index 0000000..c3103fd --- /dev/null +++ b/ThirdPartyLicenses/DotNetZip.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | Microsoft Public License (Ms-PL) | ||
2 | |||
3 | This license governs use of the accompanying software, the DotNetZip library ("the software"). If you use the software, you accept this license. If you do not accept the license, do not use the software. | ||
4 | |||
5 | 1. Definitions | ||
6 | |||
7 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. | ||
8 | |||
9 | A "contribution" is the original software, or any additions or changes to the software. | ||
10 | |||
11 | A "contributor" is any person that distributes its contribution under this license. | ||
12 | |||
13 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. | ||
14 | |||
15 | 2. Grant of Rights | ||
16 | |||
17 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. | ||
18 | |||
19 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. | ||
20 | |||
21 | 3. Conditions and Limitations | ||
22 | |||
23 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. | ||
24 | |||
25 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. | ||
26 | |||
27 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. | ||
28 | |||
29 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. | ||
30 | |||
31 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. | ||
32 | |||
33 | |||
diff --git a/ThirdPartyLicenses/GTCache.txt b/ThirdPartyLicenses/GTCache.txt new file mode 100644 index 0000000..0e3496f --- /dev/null +++ b/ThirdPartyLicenses/GTCache.txt | |||
@@ -0,0 +1,477 @@ | |||
1 | GlynnTucker.Cache | ||
2 | |||
3 | http://gtcache.sourceforge.net/ | ||
4 | |||
5 | The GlynnTucker.Cache assembly provides a data structure for caching slow data retrievals, for example data retrieved from a database server over the network. Think of it as a Hashtable that can automatically expire its data after a set amount of time or a specified period of inactivity, on a per-object basis. It is written in C# and dual licensed under the GPL/MPL, it should work with any .NET language. | ||
6 | |||
7 | |||
8 | MOZILLA PUBLIC LICENSE | ||
9 | Version 1.1 | ||
10 | |||
11 | --------------- | ||
12 | |||
13 | 1. Definitions. | ||
14 | |||
15 | 1.0.1. "Commercial Use" means distribution or otherwise making the | ||
16 | Covered Code available to a third party. | ||
17 | |||
18 | 1.1. "Contributor" means each entity that creates or contributes to | ||
19 | the creation of Modifications. | ||
20 | |||
21 | 1.2. "Contributor Version" means the combination of the Original | ||
22 | Code, prior Modifications used by a Contributor, and the Modifications | ||
23 | made by that particular Contributor. | ||
24 | |||
25 | 1.3. "Covered Code" means the Original Code or Modifications or the | ||
26 | combination of the Original Code and Modifications, in each case | ||
27 | including portions thereof. | ||
28 | |||
29 | 1.4. "Electronic Distribution Mechanism" means a mechanism generally | ||
30 | accepted in the software development community for the electronic | ||
31 | transfer of data. | ||
32 | |||
33 | 1.5. "Executable" means Covered Code in any form other than Source | ||
34 | Code. | ||
35 | |||
36 | 1.6. "Initial Developer" means the individual or entity identified | ||
37 | as the Initial Developer in the Source Code notice required by Exhibit | ||
38 | A. | ||
39 | |||
40 | 1.7. "Larger Work" means a work which combines Covered Code or | ||
41 | portions thereof with code not governed by the terms of this License. | ||
42 | |||
43 | 1.8. "License" means this document. | ||
44 | |||
45 | 1.8.1. "Licensable" means having the right to grant, to the maximum | ||
46 | extent possible, whether at the time of the initial grant or | ||
47 | subsequently acquired, any and all of the rights conveyed herein. | ||
48 | |||
49 | 1.9. "Modifications" means any addition to or deletion from the | ||
50 | substance or structure of either the Original Code or any previous | ||
51 | Modifications. When Covered Code is released as a series of files, a | ||
52 | Modification is: | ||
53 | A. Any addition to or deletion from the contents of a file | ||
54 | containing Original Code or previous Modifications. | ||
55 | |||
56 | B. Any new file that contains any part of the Original Code or | ||
57 | previous Modifications. | ||
58 | |||
59 | 1.10. "Original Code" means Source Code of computer software code | ||
60 | which is described in the Source Code notice required by Exhibit A as | ||
61 | Original Code, and which, at the time of its release under this | ||
62 | License is not already Covered Code governed by this License. | ||
63 | |||
64 | 1.10.1. "Patent Claims" means any patent claim(s), now owned or | ||
65 | hereafter acquired, including without limitation, method, process, | ||
66 | and apparatus claims, in any patent Licensable by grantor. | ||
67 | |||
68 | 1.11. "Source Code" means the preferred form of the Covered Code for | ||
69 | making modifications to it, including all modules it contains, plus | ||
70 | any associated interface definition files, scripts used to control | ||
71 | compilation and installation of an Executable, or source code | ||
72 | differential comparisons against either the Original Code or another | ||
73 | well known, available Covered Code of the Contributor's choice. The | ||
74 | Source Code can be in a compressed or archival form, provided the | ||
75 | appropriate decompression or de-archiving software is widely available | ||
76 | for no charge. | ||
77 | |||
78 | 1.12. "You" (or "Your") means an individual or a legal entity | ||
79 | exercising rights under, and complying with all of the terms of, this | ||
80 | License or a future version of this License issued under Section 6.1. | ||
81 | For legal entities, "You" includes any entity which controls, is | ||
82 | controlled by, or is under common control with You. For purposes of | ||
83 | this definition, "control" means (a) the power, direct or indirect, | ||
84 | to cause the direction or management of such entity, whether by | ||
85 | contract or otherwise, or (b) ownership of more than fifty percent | ||
86 | (50%) of the outstanding shares or beneficial ownership of such | ||
87 | entity. | ||
88 | |||
89 | 2. Source Code License. | ||
90 | |||
91 | 2.1. The Initial Developer Grant. | ||
92 | The Initial Developer hereby grants You a world-wide, royalty-free, | ||
93 | non-exclusive license, subject to third party intellectual property | ||
94 | claims: | ||
95 | (a) under intellectual property rights (other than patent or | ||
96 | trademark) Licensable by Initial Developer to use, reproduce, | ||
97 | modify, display, perform, sublicense and distribute the Original | ||
98 | Code (or portions thereof) with or without Modifications, and/or | ||
99 | as part of a Larger Work; and | ||
100 | |||
101 | (b) under Patents Claims infringed by the making, using or | ||
102 | selling of Original Code, to make, have made, use, practice, | ||
103 | sell, and offer for sale, and/or otherwise dispose of the | ||
104 | Original Code (or portions thereof). | ||
105 | |||
106 | (c) the licenses granted in this Section 2.1(a) and (b) are | ||
107 | effective on the date Initial Developer first distributes | ||
108 | Original Code under the terms of this License. | ||
109 | |||
110 | (d) Notwithstanding Section 2.1(b) above, no patent license is | ||
111 | granted: 1) for code that You delete from the Original Code; 2) | ||
112 | separate from the Original Code; or 3) for infringements caused | ||
113 | by: i) the modification of the Original Code or ii) the | ||
114 | combination of the Original Code with other software or devices. | ||
115 | |||
116 | 2.2. Contributor Grant. | ||
117 | Subject to third party intellectual property claims, each Contributor | ||
118 | hereby grants You a world-wide, royalty-free, non-exclusive license | ||
119 | |||
120 | (a) under intellectual property rights (other than patent or | ||
121 | trademark) Licensable by Contributor, to use, reproduce, modify, | ||
122 | display, perform, sublicense and distribute the Modifications | ||
123 | created by such Contributor (or portions thereof) either on an | ||
124 | unmodified basis, with other Modifications, as Covered Code | ||
125 | and/or as part of a Larger Work; and | ||
126 | |||
127 | (b) under Patent Claims infringed by the making, using, or | ||
128 | selling of Modifications made by that Contributor either alone | ||
129 | and/or in combination with its Contributor Version (or portions | ||
130 | of such combination), to make, use, sell, offer for sale, have | ||
131 | made, and/or otherwise dispose of: 1) Modifications made by that | ||
132 | Contributor (or portions thereof); and 2) the combination of | ||
133 | Modifications made by that Contributor with its Contributor | ||
134 | Version (or portions of such combination). | ||
135 | |||
136 | (c) the licenses granted in Sections 2.2(a) and 2.2(b) are | ||
137 | effective on the date Contributor first makes Commercial Use of | ||
138 | the Covered Code. | ||
139 | |||
140 | (d) Notwithstanding Section 2.2(b) above, no patent license is | ||
141 | granted: 1) for any code that Contributor has deleted from the | ||
142 | Contributor Version; 2) separate from the Contributor Version; | ||
143 | 3) for infringements caused by: i) third party modifications of | ||
144 | Contributor Version or ii) the combination of Modifications made | ||
145 | by that Contributor with other software (except as part of the | ||
146 | Contributor Version) or other devices; or 4) under Patent Claims | ||
147 | infringed by Covered Code in the absence of Modifications made by | ||
148 | that Contributor. | ||
149 | |||
150 | 3. Distribution Obligations. | ||
151 | |||
152 | 3.1. Application of License. | ||
153 | The Modifications which You create or to which You contribute are | ||
154 | governed by the terms of this License, including without limitation | ||
155 | Section 2.2. The Source Code version of Covered Code may be | ||
156 | distributed only under the terms of this License or a future version | ||
157 | of this License released under Section 6.1, and You must include a | ||
158 | copy of this License with every copy of the Source Code You | ||
159 | distribute. You may not offer or impose any terms on any Source Code | ||
160 | version that alters or restricts the applicable version of this | ||
161 | License or the recipients' rights hereunder. However, You may include | ||
162 | an additional document offering the additional rights described in | ||
163 | Section 3.5. | ||
164 | |||
165 | 3.2. Availability of Source Code. | ||
166 | Any Modification which You create or to which You contribute must be | ||
167 | made available in Source Code form under the terms of this License | ||
168 | either on the same media as an Executable version or via an accepted | ||
169 | Electronic Distribution Mechanism to anyone to whom you made an | ||
170 | Executable version available; and if made available via Electronic | ||
171 | Distribution Mechanism, must remain available for at least twelve (12) | ||
172 | months after the date it initially became available, or at least six | ||
173 | (6) months after a subsequent version of that particular Modification | ||
174 | has been made available to such recipients. You are responsible for | ||
175 | ensuring that the Source Code version remains available even if the | ||
176 | Electronic Distribution Mechanism is maintained by a third party. | ||
177 | |||
178 | 3.3. Description of Modifications. | ||
179 | You must cause all Covered Code to which You contribute to contain a | ||
180 | file documenting the changes You made to create that Covered Code and | ||
181 | the date of any change. You must include a prominent statement that | ||
182 | the Modification is derived, directly or indirectly, from Original | ||
183 | Code provided by the Initial Developer and including the name of the | ||
184 | Initial Developer in (a) the Source Code, and (b) in any notice in an | ||
185 | Executable version or related documentation in which You describe the | ||
186 | origin or ownership of the Covered Code. | ||
187 | |||
188 | 3.4. Intellectual Property Matters | ||
189 | (a) Third Party Claims. | ||
190 | If Contributor has knowledge that a license under a third party's | ||
191 | intellectual property rights is required to exercise the rights | ||
192 | granted by such Contributor under Sections 2.1 or 2.2, | ||
193 | Contributor must include a text file with the Source Code | ||
194 | distribution titled "LEGAL" which describes the claim and the | ||
195 | party making the claim in sufficient detail that a recipient will | ||
196 | know whom to contact. If Contributor obtains such knowledge after | ||
197 | the Modification is made available as described in Section 3.2, | ||
198 | Contributor shall promptly modify the LEGAL file in all copies | ||
199 | Contributor makes available thereafter and shall take other steps | ||
200 | (such as notifying appropriate mailing lists or newsgroups) | ||
201 | reasonably calculated to inform those who received the Covered | ||
202 | Code that new knowledge has been obtained. | ||
203 | |||
204 | (b) Contributor APIs. | ||
205 | If Contributor's Modifications include an application programming | ||
206 | interface and Contributor has knowledge of patent licenses which | ||
207 | are reasonably necessary to implement that API, Contributor must | ||
208 | also include this information in the LEGAL file. | ||
209 | |||
210 | (c) Representations. | ||
211 | Contributor represents that, except as disclosed pursuant to | ||
212 | Section 3.4(a) above, Contributor believes that Contributor's | ||
213 | Modifications are Contributor's original creation(s) and/or | ||
214 | Contributor has sufficient rights to grant the rights conveyed by | ||
215 | this License. | ||
216 | |||
217 | 3.5. Required Notices. | ||
218 | You must duplicate the notice in Exhibit A in each file of the Source | ||
219 | Code. If it is not possible to put such notice in a particular Source | ||
220 | Code file due to its structure, then You must include such notice in a | ||
221 | location (such as a relevant directory) where a user would be likely | ||
222 | to look for such a notice. If You created one or more Modification(s) | ||
223 | You may add your name as a Contributor to the notice described in | ||
224 | Exhibit A. You must also duplicate this License in any documentation | ||
225 | for the Source Code where You describe recipients' rights or ownership | ||
226 | rights relating to Covered Code. You may choose to offer, and to | ||
227 | charge a fee for, warranty, support, indemnity or liability | ||
228 | obligations to one or more recipients of Covered Code. However, You | ||
229 | may do so only on Your own behalf, and not on behalf of the Initial | ||
230 | Developer or any Contributor. You must make it absolutely clear than | ||
231 | any such warranty, support, indemnity or liability obligation is | ||
232 | offered by You alone, and You hereby agree to indemnify the Initial | ||
233 | Developer and every Contributor for any liability incurred by the | ||
234 | Initial Developer or such Contributor as a result of warranty, | ||
235 | support, indemnity or liability terms You offer. | ||
236 | |||
237 | 3.6. Distribution of Executable Versions. | ||
238 | You may distribute Covered Code in Executable form only if the | ||
239 | requirements of Section 3.1-3.5 have been met for that Covered Code, | ||
240 | and if You include a notice stating that the Source Code version of | ||
241 | the Covered Code is available under the terms of this License, | ||
242 | including a description of how and where You have fulfilled the | ||
243 | obligations of Section 3.2. The notice must be conspicuously included | ||
244 | in any notice in an Executable version, related documentation or | ||
245 | collateral in which You describe recipients' rights relating to the | ||
246 | Covered Code. You may distribute the Executable version of Covered | ||
247 | Code or ownership rights under a license of Your choice, which may | ||
248 | contain terms different from this License, provided that You are in | ||
249 | compliance with the terms of this License and that the license for the | ||
250 | Executable version does not attempt to limit or alter the recipient's | ||
251 | rights in the Source Code version from the rights set forth in this | ||
252 | License. If You distribute the Executable version under a different | ||
253 | license You must make it absolutely clear that any terms which differ | ||
254 | from this License are offered by You alone, not by the Initial | ||
255 | Developer or any Contributor. You hereby agree to indemnify the | ||
256 | Initial Developer and every Contributor for any liability incurred by | ||
257 | the Initial Developer or such Contributor as a result of any such | ||
258 | terms You offer. | ||
259 | |||
260 | 3.7. Larger Works. | ||
261 | You may create a Larger Work by combining Covered Code with other code | ||
262 | not governed by the terms of this License and distribute the Larger | ||
263 | Work as a single product. In such a case, You must make sure the | ||
264 | requirements of this License are fulfilled for the Covered Code. | ||
265 | |||
266 | 4. Inability to Comply Due to Statute or Regulation. | ||
267 | |||
268 | If it is impossible for You to comply with any of the terms of this | ||
269 | License with respect to some or all of the Covered Code due to | ||
270 | statute, judicial order, or regulation then You must: (a) comply with | ||
271 | the terms of this License to the maximum extent possible; and (b) | ||
272 | describe the limitations and the code they affect. Such description | ||
273 | must be included in the LEGAL file described in Section 3.4 and must | ||
274 | be included with all distributions of the Source Code. Except to the | ||
275 | extent prohibited by statute or regulation, such description must be | ||
276 | sufficiently detailed for a recipient of ordinary skill to be able to | ||
277 | understand it. | ||
278 | |||
279 | 5. Application of this License. | ||
280 | |||
281 | This License applies to code to which the Initial Developer has | ||
282 | attached the notice in Exhibit A and to related Covered Code. | ||
283 | |||
284 | 6. Versions of the License. | ||
285 | |||
286 | 6.1. New Versions. | ||
287 | Netscape Communications Corporation ("Netscape") may publish revised | ||
288 | and/or new versions of the License from time to time. Each version | ||
289 | will be given a distinguishing version number. | ||
290 | |||
291 | 6.2. Effect of New Versions. | ||
292 | Once Covered Code has been published under a particular version of the | ||
293 | License, You may always continue to use it under the terms of that | ||
294 | version. You may also choose to use such Covered Code under the terms | ||
295 | of any subsequent version of the License published by Netscape. No one | ||
296 | other than Netscape has the right to modify the terms applicable to | ||
297 | Covered Code created under this License. | ||
298 | |||
299 | 6.3. Derivative Works. | ||
300 | If You create or use a modified version of this License (which you may | ||
301 | only do in order to apply it to code which is not already Covered Code | ||
302 | governed by this License), You must (a) rename Your license so that | ||
303 | the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", | ||
304 | "MPL", "NPL" or any confusingly similar phrase do not appear in your | ||
305 | license (except to note that your license differs from this License) | ||
306 | and (b) otherwise make it clear that Your version of the license | ||
307 | contains terms which differ from the Mozilla Public License and | ||
308 | Netscape Public License. (Filling in the name of the Initial | ||
309 | Developer, Original Code or Contributor in the notice described in | ||
310 | Exhibit A shall not of themselves be deemed to be modifications of | ||
311 | this License.) | ||
312 | |||
313 | 7. DISCLAIMER OF WARRANTY. | ||
314 | |||
315 | COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, | ||
316 | WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, | ||
317 | WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF | ||
318 | DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. | ||
319 | THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE | ||
320 | IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, | ||
321 | YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE | ||
322 | COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER | ||
323 | OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF | ||
324 | ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. | ||
325 | |||
326 | 8. TERMINATION. | ||
327 | |||
328 | 8.1. This License and the rights granted hereunder will terminate | ||
329 | automatically if You fail to comply with terms herein and fail to cure | ||
330 | such breach within 30 days of becoming aware of the breach. All | ||
331 | sublicenses to the Covered Code which are properly granted shall | ||
332 | survive any termination of this License. Provisions which, by their | ||
333 | nature, must remain in effect beyond the termination of this License | ||
334 | shall survive. | ||
335 | |||
336 | 8.2. If You initiate litigation by asserting a patent infringement | ||
337 | claim (excluding declatory judgment actions) against Initial Developer | ||
338 | or a Contributor (the Initial Developer or Contributor against whom | ||
339 | You file such action is referred to as "Participant") alleging that: | ||
340 | |||
341 | (a) such Participant's Contributor Version directly or indirectly | ||
342 | infringes any patent, then any and all rights granted by such | ||
343 | Participant to You under Sections 2.1 and/or 2.2 of this License | ||
344 | shall, upon 60 days notice from Participant terminate prospectively, | ||
345 | unless if within 60 days after receipt of notice You either: (i) | ||
346 | agree in writing to pay Participant a mutually agreeable reasonable | ||
347 | royalty for Your past and future use of Modifications made by such | ||
348 | Participant, or (ii) withdraw Your litigation claim with respect to | ||
349 | the Contributor Version against such Participant. If within 60 days | ||
350 | of notice, a reasonable royalty and payment arrangement are not | ||
351 | mutually agreed upon in writing by the parties or the litigation claim | ||
352 | is not withdrawn, the rights granted by Participant to You under | ||
353 | Sections 2.1 and/or 2.2 automatically terminate at the expiration of | ||
354 | the 60 day notice period specified above. | ||
355 | |||
356 | (b) any software, hardware, or device, other than such Participant's | ||
357 | Contributor Version, directly or indirectly infringes any patent, then | ||
358 | any rights granted to You by such Participant under Sections 2.1(b) | ||
359 | and 2.2(b) are revoked effective as of the date You first made, used, | ||
360 | sold, distributed, or had made, Modifications made by that | ||
361 | Participant. | ||
362 | |||
363 | 8.3. If You assert a patent infringement claim against Participant | ||
364 | alleging that such Participant's Contributor Version directly or | ||
365 | indirectly infringes any patent where such claim is resolved (such as | ||
366 | by license or settlement) prior to the initiation of patent | ||
367 | infringement litigation, then the reasonable value of the licenses | ||
368 | granted by such Participant under Sections 2.1 or 2.2 shall be taken | ||
369 | into account in determining the amount or value of any payment or | ||
370 | license. | ||
371 | |||
372 | 8.4. In the event of termination under Sections 8.1 or 8.2 above, | ||
373 | all end user license agreements (excluding distributors and resellers) | ||
374 | which have been validly granted by You or any distributor hereunder | ||
375 | prior to termination shall survive termination. | ||
376 | |||
377 | 9. LIMITATION OF LIABILITY. | ||
378 | |||
379 | UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT | ||
380 | (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL | ||
381 | DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, | ||
382 | OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR | ||
383 | ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY | ||
384 | CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, | ||
385 | WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER | ||
386 | COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN | ||
387 | INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF | ||
388 | LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY | ||
389 | RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW | ||
390 | PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE | ||
391 | EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO | ||
392 | THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. | ||
393 | |||
394 | 10. U.S. GOVERNMENT END USERS. | ||
395 | |||
396 | The Covered Code is a "commercial item," as that term is defined in | ||
397 | 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer | ||
398 | software" and "commercial computer software documentation," as such | ||
399 | terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 | ||
400 | C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), | ||
401 | all U.S. Government End Users acquire Covered Code with only those | ||
402 | rights set forth herein. | ||
403 | |||
404 | 11. MISCELLANEOUS. | ||
405 | |||
406 | This License represents the complete agreement concerning subject | ||
407 | matter hereof. If any provision of this License is held to be | ||
408 | unenforceable, such provision shall be reformed only to the extent | ||
409 | necessary to make it enforceable. This License shall be governed by | ||
410 | California law provisions (except to the extent applicable law, if | ||
411 | any, provides otherwise), excluding its conflict-of-law provisions. | ||
412 | With respect to disputes in which at least one party is a citizen of, | ||
413 | or an entity chartered or registered to do business in the United | ||
414 | States of America, any litigation relating to this License shall be | ||
415 | subject to the jurisdiction of the Federal Courts of the Northern | ||
416 | District of California, with venue lying in Santa Clara County, | ||
417 | California, with the losing party responsible for costs, including | ||
418 | without limitation, court costs and reasonable attorneys' fees and | ||
419 | expenses. The application of the United Nations Convention on | ||
420 | Contracts for the International Sale of Goods is expressly excluded. | ||
421 | Any law or regulation which provides that the language of a contract | ||
422 | shall be construed against the drafter shall not apply to this | ||
423 | License. | ||
424 | |||
425 | 12. RESPONSIBILITY FOR CLAIMS. | ||
426 | |||
427 | As between Initial Developer and the Contributors, each party is | ||
428 | responsible for claims and damages arising, directly or indirectly, | ||
429 | out of its utilization of rights under this License and You agree to | ||
430 | work with Initial Developer and Contributors to distribute such | ||
431 | responsibility on an equitable basis. Nothing herein is intended or | ||
432 | shall be deemed to constitute any admission of liability. | ||
433 | |||
434 | 13. MULTIPLE-LICENSED CODE. | ||
435 | |||
436 | Initial Developer may designate portions of the Covered Code as | ||
437 | "Multiple-Licensed". "Multiple-Licensed" means that the Initial | ||
438 | Developer permits you to utilize portions of the Covered Code under | ||
439 | Your choice of the NPL or the alternative licenses, if any, specified | ||
440 | by the Initial Developer in the file described in Exhibit A. | ||
441 | |||
442 | EXHIBIT A -Mozilla Public License. | ||
443 | |||
444 | ``The contents of this file are subject to the Mozilla Public License | ||
445 | Version 1.1 (the "License"); you may not use this file except in | ||
446 | compliance with the License. You may obtain a copy of the License at | ||
447 | http://www.mozilla.org/MPL/ | ||
448 | |||
449 | Software distributed under the License is distributed on an "AS IS" | ||
450 | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | ||
451 | License for the specific language governing rights and limitations | ||
452 | under the License. | ||
453 | |||
454 | The Original Code is ______________________________________. | ||
455 | |||
456 | The Initial Developer of the Original Code is ________________________. | ||
457 | Portions created by ______________________ are Copyright (C) ______ | ||
458 | _______________________. All Rights Reserved. | ||
459 | |||
460 | Contributor(s): ______________________________________. | ||
461 | |||
462 | Alternatively, the contents of this file may be used under the terms | ||
463 | of the _____ license (the "[___] License"), in which case the | ||
464 | provisions of [______] License are applicable instead of those | ||
465 | above. If you wish to allow use of your version of this file only | ||
466 | under the terms of the [____] License and not to allow others to use | ||
467 | your version of this file under the MPL, indicate your decision by | ||
468 | deleting the provisions above and replace them with the notice and | ||
469 | other provisions required by the [___] License. If you do not delete | ||
470 | the provisions above, a recipient may use your version of this file | ||
471 | under either the MPL or the [___] License." | ||
472 | |||
473 | [NOTE: The text of this Exhibit A may differ slightly from the text of | ||
474 | the notices in the Source Code files of the Original Code. You should | ||
475 | use the text of this Exhibit A rather than the text found in the | ||
476 | Original Code Source Code for Your Modifications.] | ||
477 | |||
diff --git a/ThirdPartyLicenses/GoogleProtoBuffer.txt b/ThirdPartyLicenses/GoogleProtoBuffer.txt new file mode 100644 index 0000000..e0df00c --- /dev/null +++ b/ThirdPartyLicenses/GoogleProtoBuffer.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | // Protocol Buffers - Google's data interchange format | ||
2 | // Copyright 2008 Google Inc. All rights reserved. | ||
3 | // http://github.com/jskeet/dotnet-protobufs/ | ||
4 | // Original C++/Java/Python code: | ||
5 | // http://code.google.com/p/protobuf/ | ||
6 | // | ||
7 | // Redistribution and use in source and binary forms, with or without | ||
8 | // modification, are permitted provided that the following conditions are | ||
9 | // met: | ||
10 | // | ||
11 | // * Redistributions of source code must retain the above copyright | ||
12 | // notice, this list of conditions and the following disclaimer. | ||
13 | // * Redistributions in binary form must reproduce the above | ||
14 | // copyright notice, this list of conditions and the following disclaimer | ||
15 | // in the documentation and/or other materials provided with the | ||
16 | // distribution. | ||
17 | // * Neither the name of Google Inc. nor the names of its | ||
18 | // contributors may be used to endorse or promote products derived from | ||
19 | // this software without specific prior written permission. | ||
20 | // | ||
21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
22 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
23 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
24 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
25 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
26 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
27 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
28 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
29 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
30 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
31 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/ThirdPartyLicenses/ICSharpCode.SharpZipLib.license.txt b/ThirdPartyLicenses/ICSharpCode.SharpZipLib.license.txt new file mode 100644 index 0000000..c384be4 --- /dev/null +++ b/ThirdPartyLicenses/ICSharpCode.SharpZipLib.license.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | The library is released under the GPL with the following exception: | ||
2 | |||
3 | Linking this library statically or dynamically with other modules is | ||
4 | making a combined work based on this library. Thus, the terms and | ||
5 | conditions of the GNU General Public License cover the whole combination. | ||
6 | |||
7 | As a special exception, the copyright holders of this library give you | ||
8 | permission to link this library with independent modules to produce an | ||
9 | executable, regardless of the license terms of these independent modules, | ||
10 | and to copy and distribute the resulting executable under terms of your | ||
11 | choice, provided that you also meet, for each linked independent module, | ||
12 | the terms and conditions of the license of that module. An independent | ||
13 | module is a module which is not derived from or based on this library. | ||
14 | |||
15 | If you modify this library, you may extend this exception to your | ||
16 | version of the library, but you are not obligated to do so. If you do not | ||
17 | wish to do so, delete this exception statement from your version. | ||
diff --git a/ThirdPartyLicenses/MXP.txt b/ThirdPartyLicenses/MXP.txt new file mode 100644 index 0000000..43f51ce --- /dev/null +++ b/ThirdPartyLicenses/MXP.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | Metaverse Exchange Protocol specification and reference implementation. | ||
2 | |||
3 | Copyright 2008-2009 Bubble Cloud Comminity (http://www.bubblecloud.org) | ||
4 | |||
5 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | you may not use this file except in compliance with the License. | ||
7 | You may obtain a copy of the License at | ||
8 | |||
9 | http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | |||
11 | Unless required by applicable law or agreed to in writing, software | ||
12 | distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | See the License for the specific language governing permissions and | ||
15 | limitations under the License. | ||
diff --git a/ThirdPartyLicenses/Mono.Xna (MonoXnaCompactMaths).txt b/ThirdPartyLicenses/Mono.Xna (MonoXnaCompactMaths).txt new file mode 100644 index 0000000..ef324b6 --- /dev/null +++ b/ThirdPartyLicenses/Mono.Xna (MonoXnaCompactMaths).txt | |||
@@ -0,0 +1,22 @@ | |||
1 | MIT License | ||
2 | Copyright © 2006 The Mono.Xna Team | ||
3 | |||
4 | All rights reserved. | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/MonoAddins.txt b/ThirdPartyLicenses/MonoAddins.txt new file mode 100644 index 0000000..10c23b3 --- /dev/null +++ b/ThirdPartyLicenses/MonoAddins.txt | |||
@@ -0,0 +1,41 @@ | |||
1 | Authors: Lluis Sanchez Gual <lluis@novell.com> | ||
2 | |||
3 | The MIT License | ||
4 | |||
5 | Copyright (C) 2007 Novell, Inc (http://www.novell.com) | ||
6 | |||
7 | |||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy | ||
11 | of this software and associated documentation files (the "Software"), | ||
12 | to deal | ||
13 | in the Software without restriction, including without limitation | ||
14 | the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, | ||
16 | and/or sell | ||
17 | copies of the Software, and to permit persons to whom the | ||
18 | Software is | ||
19 | furnished to do so, subject to the following conditions: | ||
20 | |||
21 | |||
22 | |||
23 | The above copyright notice and this permission notice shall be included in | ||
24 | |||
25 | all copies or substantial portions of the Software. | ||
26 | |||
27 | |||
28 | |||
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
30 | EXPRESS OR | ||
31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
32 | MERCHANTABILITY, | ||
33 | FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. | ||
34 | IN NO EVENT SHALL THE | ||
35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
36 | DAMAGES OR OTHER | ||
37 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
38 | OTHERWISE, ARISING FROM, | ||
39 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR | ||
40 | THE USE OR OTHER DEALINGS IN | ||
41 | THE SOFTWARE. | ||
diff --git a/ThirdPartyLicenses/MySQL.txt b/ThirdPartyLicenses/MySQL.txt new file mode 100644 index 0000000..bbda936 --- /dev/null +++ b/ThirdPartyLicenses/MySQL.txt | |||
@@ -0,0 +1,122 @@ | |||
1 | GPLv2 + MySQL FLOSS License Exception (files COPYING and EXCEPTIONS) | ||
2 | |||
3 | --- file: EXCEPTIONS --- | ||
4 | MySQL FLOSS License Exception | ||
5 | |||
6 | The MySQL AB Exception for Free/Libre and Open Source | ||
7 | Software-only Applications Using MySQL Client Libraries (the | ||
8 | "FLOSS Exception"). | ||
9 | |||
10 | Version 0.6, 7 March 2007 | ||
11 | |||
12 | Exception Intent | ||
13 | |||
14 | We want specified Free/Libre and Open Source Software (``FLOSS'') | ||
15 | applications to be able to use specified GPL-licensed MySQL client | ||
16 | libraries (the ``Program'') despite the fact that not all FLOSS | ||
17 | licenses are compatible with version 2 of the GNU General Public | ||
18 | License (the ``GPL''). | ||
19 | |||
20 | Legal Terms and Conditions | ||
21 | |||
22 | As a special exception to the terms and conditions of version 2.0 | ||
23 | of the GPL: | ||
24 | |||
25 | 1. You are free to distribute a Derivative Work that is formed | ||
26 | entirely from the Program and one or more works (each, a | ||
27 | "FLOSS Work") licensed under one or more of the licenses | ||
28 | listed below in section 1, as long as: | ||
29 | a. You obey the GPL in all respects for the Program and the | ||
30 | Derivative Work, except for identifiable sections of the | ||
31 | Derivative Work which are not derived from the Program, | ||
32 | and which can reasonably be considered independent and | ||
33 | separate works in themselves, | ||
34 | b. all identifiable sections of the Derivative Work which | ||
35 | are not derived from the Program, and which can | ||
36 | reasonably be considered independent and separate works | ||
37 | in themselves, | ||
38 | i. are distributed subject to one of the FLOSS licenses | ||
39 | listed below, and | ||
40 | ii. the object code or executable form of those sections | ||
41 | are accompanied by the complete corresponding | ||
42 | machine-readable source code for those sections on | ||
43 | the same medium and under the same FLOSS license as | ||
44 | the corresponding object code or executable forms of | ||
45 | those sections, and | ||
46 | c. any works which are aggregated with the Program or with a | ||
47 | Derivative Work on a volume of a storage or distribution | ||
48 | medium in accordance with the GPL, can reasonably be | ||
49 | considered independent and separate works in themselves | ||
50 | which are not derivatives of either the Program, a | ||
51 | Derivative Work or a FLOSS Work. | ||
52 | If the above conditions are not met, then the Program may only | ||
53 | be copied, modified, distributed or used under the terms and | ||
54 | conditions of the GPL or another valid licensing option from | ||
55 | MySQL AB. | ||
56 | |||
57 | 2. FLOSS License List | ||
58 | |||
59 | License name Version(s)/Copyright Date | ||
60 | Academic Free License 2.0 | ||
61 | Apache Software License 1.0/1.1/2.0 | ||
62 | Apple Public Source License 2.0 | ||
63 | Artistic license From Perl 5.8.0 | ||
64 | BSD license "July 22 1999" | ||
65 | Common Development and Distribution License (CDDL) 1.0 | ||
66 | Common Public License 1.0 | ||
67 | Eclipse Public License 1.0 | ||
68 | GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1 | ||
69 | Jabber Open Source License 1.0 | ||
70 | MIT license (As listed in file MIT-License.txt) --- | ||
71 | Mozilla Public License (MPL) 1.0/1.1 | ||
72 | Open Software License 2.0 | ||
73 | OpenSSL license (with original SSLeay license) "2003" ("1998") | ||
74 | PHP License 3.0 | ||
75 | Python license (CNRI Python License) --- | ||
76 | Python Software Foundation License 2.1.1 | ||
77 | Sleepycat License "1999" | ||
78 | University of Illinois/NCSA Open Source License --- | ||
79 | W3C License "2001" | ||
80 | X11 License "2001" | ||
81 | Zlib/libpng License --- | ||
82 | Zope Public License 2.0 | ||
83 | |||
84 | Due to the many variants of some of the above licenses, we | ||
85 | require that any version follow the 2003 version of the Free | ||
86 | Software Foundation's Free Software Definition | ||
87 | (http://www.gnu.org/philosophy/free-sw.html) or version 1.9 of | ||
88 | the Open Source Definition by the Open Source Initiative | ||
89 | (http://www.opensource.org/docs/definition.php). | ||
90 | |||
91 | 3. Definitions | ||
92 | |||
93 | a. Terms used, but not defined, herein shall have the | ||
94 | meaning provided in the GPL. | ||
95 | b. Derivative Work means a derivative work under copyright | ||
96 | law. | ||
97 | |||
98 | 4. Applicability: This FLOSS Exception applies to all Programs | ||
99 | that contain a notice placed by MySQL AB saying that the | ||
100 | Program may be distributed under the terms of this FLOSS | ||
101 | Exception. If you create or distribute a work which is a | ||
102 | Derivative Work of both the Program and any other work | ||
103 | licensed under the GPL, then this FLOSS Exception is not | ||
104 | available for that work; thus, you must remove the FLOSS | ||
105 | Exception notice from that work and comply with the GPL in all | ||
106 | respects, including by retaining all GPL notices. You may | ||
107 | choose to redistribute a copy of the Program exclusively under | ||
108 | the terms of the GPL by removing the FLOSS Exception notice | ||
109 | from that copy of the Program, provided that the copy has | ||
110 | never been modified by you or any third party. | ||
111 | |||
112 | Appendix A. Qualified Libraries and Packages | ||
113 | |||
114 | The following is a non-exhaustive list of libraries and packages | ||
115 | which are covered by the FLOSS License Exception. Please note that | ||
116 | this appendix is provided merely as an additional service to | ||
117 | specific FLOSS projects wishing to simplify licensing information | ||
118 | for their users. Compliance with one of the licenses noted under | ||
119 | the "FLOSS license list" section remains a prerequisite. | ||
120 | |||
121 | Package Name Qualifying License and Version | ||
122 | Apache Portable Runtime (APR) Apache Software License 2.0 | ||
diff --git a/ThirdPartyLicenses/Nini.txt b/ThirdPartyLicenses/Nini.txt new file mode 100644 index 0000000..fe38b62 --- /dev/null +++ b/ThirdPartyLicenses/Nini.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | |||
2 | Nini Configuration Project. | ||
3 | Copyright (c) 2006 Brent R. Matzelle | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining | ||
6 | a copy of this software and associated documentation files (the | ||
7 | "Software"), to deal in the Software without restriction, including | ||
8 | without limitation the rights to use, copy, modify, merge, publish, | ||
9 | distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | permit persons to whom the Software is furnished to do so, subject to | ||
11 | the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be | ||
14 | included in all copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
23 | |||
diff --git a/ThirdPartyLicenses/Npgsql.txt b/ThirdPartyLicenses/Npgsql.txt new file mode 100644 index 0000000..e2e4f12 --- /dev/null +++ b/ThirdPartyLicenses/Npgsql.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | Copyright (c) 2002-2007, The Npgsql Development Team | ||
2 | |||
3 | Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. | ||
4 | |||
5 | IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
6 | |||
7 | THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||
diff --git a/ThirdPartyLicenses/ODE.txt b/ThirdPartyLicenses/ODE.txt new file mode 100644 index 0000000..53a93db --- /dev/null +++ b/ThirdPartyLicenses/ODE.txt | |||
@@ -0,0 +1,13 @@ | |||
1 | Open Dynamics Engine | ||
2 | Copyright (c) 2001-2004, Russell L. Smith. | ||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
6 | |||
7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
8 | |||
9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
10 | |||
11 | Neither the names of ODE's copyright owner nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | ||
12 | |||
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/OpenJpeg.txt b/ThirdPartyLicenses/OpenJpeg.txt new file mode 100644 index 0000000..d1e5b6a --- /dev/null +++ b/ThirdPartyLicenses/OpenJpeg.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium | ||
3 | * Copyright (c) 2002-2007, Professor Benoit Macq | ||
4 | * Copyright (c) 2001-2003, David Janssens | ||
5 | * Copyright (c) 2002-2003, Yannick Verschueren | ||
6 | * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe | ||
7 | * Copyright (c) 2005, Herve Drolon, FreeImage Team | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted provided that the following conditions | ||
12 | * are met: | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' | ||
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
29 | * POSSIBILITY OF SUCH DAMAGE. | ||
30 | */ \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/Protobuf-net.txt b/ThirdPartyLicenses/Protobuf-net.txt new file mode 100644 index 0000000..8eb6c71 --- /dev/null +++ b/ThirdPartyLicenses/Protobuf-net.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | The core Protocol Buffers technology is provided courtesy of Google. | ||
2 | At the time of writing, this is released under the BSD license. | ||
3 | Full details can be found here: | ||
4 | |||
5 | http://code.google.com/p/protobuf/ | ||
6 | |||
7 | |||
8 | This .NET implementation is Copyright 2008 Marc Gravell | ||
9 | |||
10 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
11 | you may not use this file except in compliance with the License. | ||
12 | You may obtain a copy of the License at | ||
13 | |||
14 | http://www.apache.org/licenses/LICENSE-2.0 | ||
15 | |||
16 | Unless required by applicable law or agreed to in writing, software | ||
17 | distributed under the License is distributed on an "AS IS" BASIS, | ||
18 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
19 | See the License for the specific language governing permissions and | ||
20 | limitations under the License. | ||
21 | |||
diff --git a/ThirdPartyLicenses/Prototype.txt b/ThirdPartyLicenses/Prototype.txt new file mode 100644 index 0000000..61e4918 --- /dev/null +++ b/ThirdPartyLicenses/Prototype.txt | |||
@@ -0,0 +1,16 @@ | |||
1 | Copyright (c) 2005-2008 Sam Stephenson | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
4 | of this software and associated documentation files (the "Software"), to deal | ||
5 | in the Software without restriction, including without limitation the rights | ||
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
7 | copies of the Software, and to permit persons to whom the Software is | ||
8 | furnished to do so, subject to the following conditions: | ||
9 | |||
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | SOFTWARE. | ||
diff --git a/ThirdPartyLicenses/SmartThreadPool.txt b/ThirdPartyLicenses/SmartThreadPool.txt new file mode 100644 index 0000000..7bfc997 --- /dev/null +++ b/ThirdPartyLicenses/SmartThreadPool.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | Microsoft Public License (Ms-PL) | ||
2 | |||
3 | This license governs use of the accompanying software. If you use the software, you | ||
4 | accept this license. If you do not accept the license, do not use the software. | ||
5 | |||
6 | 1. Definitions | ||
7 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the | ||
8 | same meaning here as under U.S. copyright law. | ||
9 | A "contribution" is the original software, or any additions or changes to the software. | ||
10 | A "contributor" is any person that distributes its contribution under this license. | ||
11 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. | ||
12 | |||
13 | 2. Grant of Rights | ||
14 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. | ||
15 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. | ||
16 | |||
17 | 3. Conditions and Limitations | ||
18 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. | ||
19 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. | ||
20 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. | ||
21 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. | ||
22 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. | ||
diff --git a/ThirdPartyLicenses/XML-RPC.NET.txt b/ThirdPartyLicenses/XML-RPC.NET.txt new file mode 100644 index 0000000..2aff37f --- /dev/null +++ b/ThirdPartyLicenses/XML-RPC.NET.txt | |||
@@ -0,0 +1,27 @@ | |||
1 | XML-RPC.NET - XML-RPC for .NET | ||
2 | v2.1.0 | ||
3 | Copyright (C) 2001-2006 Charles Cook (chascook@gmail.com) | ||
4 | |||
5 | xmlrpcgen | ||
6 | Copyright (C) 2003 Joe Bork | ||
7 | |||
8 | For more information about XML-RPC.NET visit http://www.xml-rpc.net. | ||
9 | |||
10 | XML-RPC.NET is licensed with MIT X11 license. | ||
11 | (see http://www.xml-rpc.net/faq/xmlrpcnetfaq.html#6.12) | ||
12 | |||
13 | For more information about XML-RPC refer to http://www.xmlrpc.com/ | ||
14 | |||
15 | |||
16 | PREQUISITES | ||
17 | ----------- | ||
18 | Assembly CookComputing.XmlRpc.dll requires 1.0 .NET runtime and | ||
19 | runs on all later versions. | ||
20 | |||
21 | Assembly CookComputing.XmlRpcV2.dll requires 2.0 .NET runtime. | ||
22 | |||
23 | |||
24 | DOCUMENTATION | ||
25 | ------------- | ||
26 | For help on using XML-RPC.NET, see | ||
27 | http://www.xml-rpc.net/faq/xmlrpcnetfaq.html. \ No newline at end of file | ||
diff --git a/ThirdPartyLicenses/libsl.txt b/ThirdPartyLicenses/libsl.txt new file mode 100644 index 0000000..73951dc --- /dev/null +++ b/ThirdPartyLicenses/libsl.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | Copyright (c) 2006, Second Life Reverse Engineering Team | ||
2 | All rights reserved. | ||
3 | |||
4 | - Redistribution and use in source and binary forms, with or without | ||
5 | modification, are permitted provided that the following conditions are met: | ||
6 | |||
7 | - Redistributions of source code must retain the above copyright notice, this | ||
8 | list of conditions and the following disclaimer. | ||
9 | - Neither the name of the Second Life Reverse Engineering Team nor the names | ||
10 | of its contributors may be used to endorse or promote products derived from | ||
11 | this software without specific prior written permission. | ||
12 | |||
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
23 | POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file | ||