diff options
Diffstat (limited to 'ThirdParty/SmartThreadPool/WorkItem.cs')
-rw-r--r-- | ThirdParty/SmartThreadPool/WorkItem.cs | 659 |
1 files changed, 313 insertions, 346 deletions
diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs index d0c0524..185f10c 100644 --- a/ThirdParty/SmartThreadPool/WorkItem.cs +++ b/ThirdParty/SmartThreadPool/WorkItem.cs | |||
@@ -1,58 +1,13 @@ | |||
1 | // Ami Bar | ||
2 | // amibar@gmail.com | ||
3 | |||
4 | using System; | 1 | using System; |
5 | using System.Threading; | 2 | using System.Threading; |
6 | using System.Diagnostics; | 3 | using System.Diagnostics; |
7 | 4 | ||
8 | namespace Amib.Threading.Internal | 5 | namespace Amib.Threading.Internal |
9 | { | 6 | { |
10 | #region WorkItem Delegate | ||
11 | |||
12 | /// <summary> | ||
13 | /// An internal delegate to call when the WorkItem starts or completes | ||
14 | /// </summary> | ||
15 | internal delegate void WorkItemStateCallback(WorkItem workItem); | ||
16 | |||
17 | #endregion | ||
18 | |||
19 | #region IInternalWorkItemResult interface | ||
20 | |||
21 | public class CanceledWorkItemsGroup | ||
22 | { | ||
23 | public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); | ||
24 | |||
25 | private bool _isCanceled = false; | ||
26 | public bool IsCanceled | ||
27 | { | ||
28 | get { return _isCanceled; } | ||
29 | set { _isCanceled = value; } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | internal interface IInternalWorkItemResult | ||
34 | { | ||
35 | event WorkItemStateCallback OnWorkItemStarted; | ||
36 | event WorkItemStateCallback OnWorkItemCompleted; | ||
37 | } | ||
38 | |||
39 | #endregion | ||
40 | |||
41 | #region IWorkItem interface | ||
42 | |||
43 | public interface IWorkItem | ||
44 | { | ||
45 | |||
46 | } | ||
47 | |||
48 | #endregion | ||
49 | |||
50 | #region WorkItem class | ||
51 | |||
52 | /// <summary> | 7 | /// <summary> |
53 | /// Holds a callback delegate and the state for that delegate. | 8 | /// Holds a callback delegate and the state for that delegate. |
54 | /// </summary> | 9 | /// </summary> |
55 | public class WorkItem : IHasWorkItemPriority, IWorkItem | 10 | public partial class WorkItem : IHasWorkItemPriority |
56 | { | 11 | { |
57 | #region WorkItemState enum | 12 | #region WorkItemState enum |
58 | 13 | ||
@@ -61,33 +16,57 @@ namespace Amib.Threading.Internal | |||
61 | /// </summary> | 16 | /// </summary> |
62 | private enum WorkItemState | 17 | private enum WorkItemState |
63 | { | 18 | { |
64 | InQueue, | 19 | InQueue = 0, // Nexts: InProgress, Canceled |
65 | InProgress, | 20 | InProgress = 1, // Nexts: Completed, Canceled |
66 | Completed, | 21 | Completed = 2, // Stays Completed |
67 | Canceled, | 22 | Canceled = 3, // Stays Canceled |
68 | } | 23 | } |
69 | 24 | ||
70 | #endregion | 25 | private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState) |
26 | { | ||
27 | bool valid = false; | ||
28 | |||
29 | switch (currentState) | ||
30 | { | ||
31 | case WorkItemState.InQueue: | ||
32 | valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState); | ||
33 | break; | ||
34 | case WorkItemState.InProgress: | ||
35 | valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState); | ||
36 | break; | ||
37 | case WorkItemState.Completed: | ||
38 | case WorkItemState.Canceled: | ||
39 | // Cannot be changed | ||
40 | break; | ||
41 | default: | ||
42 | // Unknown state | ||
43 | Debug.Assert(false); | ||
44 | break; | ||
45 | } | ||
71 | 46 | ||
72 | #region Member Variables | 47 | return valid; |
48 | } | ||
73 | 49 | ||
74 | public Thread currentThread; | 50 | #endregion |
51 | |||
52 | #region Fields | ||
75 | 53 | ||
76 | /// <summary> | 54 | /// <summary> |
77 | /// Callback delegate for the callback. | 55 | /// Callback delegate for the callback. |
78 | /// </summary> | 56 | /// </summary> |
79 | private WorkItemCallback _callback; | 57 | private readonly WorkItemCallback _callback; |
80 | 58 | ||
81 | /// <summary> | 59 | /// <summary> |
82 | /// State with which to call the callback delegate. | 60 | /// State with which to call the callback delegate. |
83 | /// </summary> | 61 | /// </summary> |
84 | private object _state; | 62 | private object _state; |
85 | 63 | ||
64 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
86 | /// <summary> | 65 | /// <summary> |
87 | /// Stores the caller's context | 66 | /// Stores the caller's context |
88 | /// </summary> | 67 | /// </summary> |
89 | private CallerThreadContext _callerContext; | 68 | private readonly CallerThreadContext _callerContext; |
90 | 69 | #endif | |
91 | /// <summary> | 70 | /// <summary> |
92 | /// Holds the result of the mehtod | 71 | /// Holds the result of the mehtod |
93 | /// </summary> | 72 | /// </summary> |
@@ -117,12 +96,12 @@ namespace Amib.Threading.Internal | |||
117 | /// <summary> | 96 | /// <summary> |
118 | /// Represents the result state of the work item | 97 | /// Represents the result state of the work item |
119 | /// </summary> | 98 | /// </summary> |
120 | private WorkItemResult _workItemResult; | 99 | private readonly WorkItemResult _workItemResult; |
121 | 100 | ||
122 | /// <summary> | 101 | /// <summary> |
123 | /// Work item info | 102 | /// Work item info |
124 | /// </summary> | 103 | /// </summary> |
125 | private WorkItemInfo _workItemInfo; | 104 | private readonly WorkItemInfo _workItemInfo; |
126 | 105 | ||
127 | /// <summary> | 106 | /// <summary> |
128 | /// Called when the WorkItem starts | 107 | /// Called when the WorkItem starts |
@@ -141,30 +120,41 @@ namespace Amib.Threading.Internal | |||
141 | private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; | 120 | private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; |
142 | 121 | ||
143 | /// <summary> | 122 | /// <summary> |
123 | /// A reference to an object that indicates whatever the | ||
124 | /// SmartThreadPool has been canceled | ||
125 | /// </summary> | ||
126 | private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; | ||
127 | |||
128 | /// <summary> | ||
144 | /// The work item group this work item belong to. | 129 | /// The work item group this work item belong to. |
145 | /// | ||
146 | /// </summary> | 130 | /// </summary> |
147 | private IWorkItemsGroup _workItemsGroup; | 131 | private readonly IWorkItemsGroup _workItemsGroup; |
148 | 132 | ||
149 | #region Performance Counter fields | 133 | /// <summary> |
134 | /// The thread that executes this workitem. | ||
135 | /// This field is available for the period when the work item is executed, before and after it is null. | ||
136 | /// </summary> | ||
137 | private Thread _executingThread; | ||
150 | 138 | ||
151 | /// <summary> | 139 | /// <summary> |
152 | /// The time when the work items is queued. | 140 | /// The absulote time when the work item will be timeout |
153 | /// Used with the performance counter. | ||
154 | /// </summary> | 141 | /// </summary> |
155 | private DateTime _queuedTime; | 142 | private long _expirationTime; |
143 | |||
144 | #region Performance Counter fields | ||
145 | |||
146 | |||
147 | |||
156 | 148 | ||
157 | /// <summary> | 149 | /// <summary> |
158 | /// The time when the work items starts its execution. | 150 | /// Stores how long the work item waited on the stp queue |
159 | /// Used with the performance counter. | ||
160 | /// </summary> | 151 | /// </summary> |
161 | private DateTime _beginProcessTime; | 152 | private Stopwatch _waitingOnQueueStopwatch; |
162 | 153 | ||
163 | /// <summary> | 154 | /// <summary> |
164 | /// The time when the work items ends its execution. | 155 | /// Stores how much time it took the work item to execute after it went out of the queue |
165 | /// Used with the performance counter. | ||
166 | /// </summary> | 156 | /// </summary> |
167 | private DateTime _endProcessTime; | 157 | private Stopwatch _processingStopwatch; |
168 | 158 | ||
169 | #endregion | 159 | #endregion |
170 | 160 | ||
@@ -174,17 +164,25 @@ namespace Amib.Threading.Internal | |||
174 | 164 | ||
175 | public TimeSpan WaitingTime | 165 | public TimeSpan WaitingTime |
176 | { | 166 | { |
177 | get | 167 | get |
178 | { | 168 | { |
179 | return (_beginProcessTime - _queuedTime); | 169 | return _waitingOnQueueStopwatch.Elapsed; |
180 | } | 170 | } |
181 | } | 171 | } |
182 | 172 | ||
183 | public TimeSpan ProcessTime | 173 | public TimeSpan ProcessTime |
184 | { | 174 | { |
185 | get | 175 | get |
176 | { | ||
177 | return _processingStopwatch.Elapsed; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | internal WorkItemInfo WorkItemInfo | ||
182 | { | ||
183 | get | ||
186 | { | 184 | { |
187 | return (_endProcessTime - _beginProcessTime); | 185 | return _workItemInfo; |
188 | } | 186 | } |
189 | } | 187 | } |
190 | 188 | ||
@@ -195,6 +193,8 @@ namespace Amib.Threading.Internal | |||
195 | /// <summary> | 193 | /// <summary> |
196 | /// Initialize the callback holding object. | 194 | /// Initialize the callback holding object. |
197 | /// </summary> | 195 | /// </summary> |
196 | /// <param name="workItemsGroup">The workItemGroup of the workitem</param> | ||
197 | /// <param name="workItemInfo">The WorkItemInfo of te workitem</param> | ||
198 | /// <param name="callback">Callback delegate for the callback.</param> | 198 | /// <param name="callback">Callback delegate for the callback.</param> |
199 | /// <param name="state">State with which to call the callback delegate.</param> | 199 | /// <param name="state">State with which to call the callback delegate.</param> |
200 | /// | 200 | /// |
@@ -203,16 +203,18 @@ namespace Amib.Threading.Internal | |||
203 | public WorkItem( | 203 | public WorkItem( |
204 | IWorkItemsGroup workItemsGroup, | 204 | IWorkItemsGroup workItemsGroup, |
205 | WorkItemInfo workItemInfo, | 205 | WorkItemInfo workItemInfo, |
206 | WorkItemCallback callback, | 206 | WorkItemCallback callback, |
207 | object state) | 207 | object state) |
208 | { | 208 | { |
209 | _workItemsGroup = workItemsGroup; | 209 | _workItemsGroup = workItemsGroup; |
210 | _workItemInfo = workItemInfo; | 210 | _workItemInfo = workItemInfo; |
211 | 211 | ||
212 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
212 | if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext) | 213 | if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext) |
213 | { | 214 | { |
214 | _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext); | 215 | _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext); |
215 | } | 216 | } |
217 | #endif | ||
216 | 218 | ||
217 | _callback = callback; | 219 | _callback = callback; |
218 | _state = state; | 220 | _state = state; |
@@ -222,9 +224,18 @@ namespace Amib.Threading.Internal | |||
222 | 224 | ||
223 | internal void Initialize() | 225 | internal void Initialize() |
224 | { | 226 | { |
227 | // The _workItemState is changed directly instead of using the SetWorkItemState | ||
228 | // method since we don't want to go throught IsValidStateTransition. | ||
225 | _workItemState = WorkItemState.InQueue; | 229 | _workItemState = WorkItemState.InQueue; |
230 | |||
226 | _workItemCompleted = null; | 231 | _workItemCompleted = null; |
227 | _workItemCompletedRefCount = 0; | 232 | _workItemCompletedRefCount = 0; |
233 | _waitingOnQueueStopwatch = new Stopwatch(); | ||
234 | _processingStopwatch = new Stopwatch(); | ||
235 | _expirationTime = | ||
236 | _workItemInfo.Timeout > 0 ? | ||
237 | DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond : | ||
238 | long.MaxValue; | ||
228 | } | 239 | } |
229 | 240 | ||
230 | internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup) | 241 | internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup) |
@@ -237,17 +248,16 @@ namespace Amib.Threading.Internal | |||
237 | 248 | ||
238 | #region Methods | 249 | #region Methods |
239 | 250 | ||
240 | public CanceledWorkItemsGroup CanceledWorkItemsGroup | 251 | internal CanceledWorkItemsGroup CanceledWorkItemsGroup |
241 | { | 252 | { |
242 | get | 253 | get { return _canceledWorkItemsGroup; } |
243 | { | 254 | set { _canceledWorkItemsGroup = value; } |
244 | return _canceledWorkItemsGroup; | 255 | } |
245 | } | ||
246 | 256 | ||
247 | set | 257 | internal CanceledWorkItemsGroup CanceledSmartThreadPool |
248 | { | 258 | { |
249 | _canceledWorkItemsGroup = value; | 259 | get { return _canceledSmartThreadPool; } |
250 | } | 260 | set { _canceledSmartThreadPool = value; } |
251 | } | 261 | } |
252 | 262 | ||
253 | /// <summary> | 263 | /// <summary> |
@@ -259,9 +269,10 @@ namespace Amib.Threading.Internal | |||
259 | /// </returns> | 269 | /// </returns> |
260 | public bool StartingWorkItem() | 270 | public bool StartingWorkItem() |
261 | { | 271 | { |
262 | _beginProcessTime = DateTime.Now; | 272 | _waitingOnQueueStopwatch.Stop(); |
273 | _processingStopwatch.Start(); | ||
263 | 274 | ||
264 | lock(this) | 275 | lock (this) |
265 | { | 276 | { |
266 | if (IsCanceled) | 277 | if (IsCanceled) |
267 | { | 278 | { |
@@ -277,6 +288,9 @@ namespace Amib.Threading.Internal | |||
277 | 288 | ||
278 | Debug.Assert(WorkItemState.InQueue == GetWorkItemState()); | 289 | Debug.Assert(WorkItemState.InQueue == GetWorkItemState()); |
279 | 290 | ||
291 | // No need for a lock yet, only after the state has changed to InProgress | ||
292 | _executingThread = Thread.CurrentThread; | ||
293 | |||
280 | SetWorkItemState(WorkItemState.InProgress); | 294 | SetWorkItemState(WorkItemState.InProgress); |
281 | } | 295 | } |
282 | 296 | ||
@@ -291,7 +305,7 @@ namespace Amib.Threading.Internal | |||
291 | CallToPostExecute currentCallToPostExecute = 0; | 305 | CallToPostExecute currentCallToPostExecute = 0; |
292 | 306 | ||
293 | // Execute the work item if we are in the correct state | 307 | // Execute the work item if we are in the correct state |
294 | switch(GetWorkItemState()) | 308 | switch (GetWorkItemState()) |
295 | { | 309 | { |
296 | case WorkItemState.InProgress: | 310 | case WorkItemState.InProgress: |
297 | currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled; | 311 | currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled; |
@@ -311,7 +325,7 @@ namespace Amib.Threading.Internal | |||
311 | PostExecute(); | 325 | PostExecute(); |
312 | } | 326 | } |
313 | 327 | ||
314 | _endProcessTime = DateTime.Now; | 328 | _processingStopwatch.Stop(); |
315 | } | 329 | } |
316 | 330 | ||
317 | internal void FireWorkItemCompleted() | 331 | internal void FireWorkItemCompleted() |
@@ -323,8 +337,21 @@ namespace Amib.Threading.Internal | |||
323 | _workItemCompletedEvent(this); | 337 | _workItemCompletedEvent(this); |
324 | } | 338 | } |
325 | } | 339 | } |
326 | catch // Ignore exceptions | 340 | catch // Suppress exceptions |
327 | {} | 341 | { } |
342 | } | ||
343 | |||
344 | internal void FireWorkItemStarted() | ||
345 | { | ||
346 | try | ||
347 | { | ||
348 | if (null != _workItemStartedEvent) | ||
349 | { | ||
350 | _workItemStartedEvent(this); | ||
351 | } | ||
352 | } | ||
353 | catch // Suppress exceptions | ||
354 | { } | ||
328 | } | 355 | } |
329 | 356 | ||
330 | /// <summary> | 357 | /// <summary> |
@@ -332,32 +359,70 @@ namespace Amib.Threading.Internal | |||
332 | /// </summary> | 359 | /// </summary> |
333 | private void ExecuteWorkItem() | 360 | private void ExecuteWorkItem() |
334 | { | 361 | { |
362 | |||
363 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
335 | CallerThreadContext ctc = null; | 364 | CallerThreadContext ctc = null; |
336 | if (null != _callerContext) | 365 | if (null != _callerContext) |
337 | { | 366 | { |
338 | ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext); | 367 | ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext); |
339 | CallerThreadContext.Apply(_callerContext); | 368 | CallerThreadContext.Apply(_callerContext); |
340 | } | 369 | } |
370 | #endif | ||
341 | 371 | ||
342 | Exception exception = null; | 372 | Exception exception = null; |
343 | object result = null; | 373 | object result = null; |
344 | 374 | ||
345 | try | 375 | try |
346 | { | 376 | { |
347 | result = _callback(_state); | 377 | try |
378 | { | ||
379 | result = _callback(_state); | ||
380 | } | ||
381 | catch (Exception e) | ||
382 | { | ||
383 | // Save the exception so we can rethrow it later | ||
384 | exception = e; | ||
385 | } | ||
386 | |||
387 | // Remove the value of the execution thread, so it will be impossible to cancel the work item, | ||
388 | // since it is already completed. | ||
389 | // Cancelling a work item that already completed may cause the abortion of the next work item!!! | ||
390 | Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); | ||
391 | |||
392 | if (null == executionThread) | ||
393 | { | ||
394 | // Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException | ||
395 | Thread.Sleep(60 * 1000); | ||
396 | |||
397 | // If after 1 minute this thread was not aborted then let it continue working. | ||
398 | } | ||
348 | } | 399 | } |
349 | catch (Exception e) | 400 | // We must treat the ThreadAbortException or else it will be stored in the exception variable |
401 | catch (ThreadAbortException tae) | ||
350 | { | 402 | { |
351 | // Save the exception so we can rethrow it later | 403 | tae.GetHashCode(); |
352 | exception = e; | 404 | // Check if the work item was cancelled |
405 | // If we got a ThreadAbortException and the STP is not shutting down, it means the | ||
406 | // work items was cancelled. | ||
407 | if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown) | ||
408 | { | ||
409 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
410 | Thread.ResetAbort(); | ||
411 | #endif | ||
412 | } | ||
353 | } | 413 | } |
354 | 414 | ||
415 | #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) | ||
355 | if (null != _callerContext) | 416 | if (null != _callerContext) |
356 | { | 417 | { |
357 | CallerThreadContext.Apply(ctc); | 418 | CallerThreadContext.Apply(ctc); |
358 | } | 419 | } |
420 | #endif | ||
359 | 421 | ||
360 | SetResult(result, exception); | 422 | if (!SmartThreadPool.IsWorkItemCanceled) |
423 | { | ||
424 | SetResult(result, exception); | ||
425 | } | ||
361 | } | 426 | } |
362 | 427 | ||
363 | /// <summary> | 428 | /// <summary> |
@@ -369,9 +434,9 @@ namespace Amib.Threading.Internal | |||
369 | { | 434 | { |
370 | try | 435 | try |
371 | { | 436 | { |
372 | _workItemInfo.PostExecuteWorkItemCallback(this._workItemResult); | 437 | _workItemInfo.PostExecuteWorkItemCallback(_workItemResult); |
373 | } | 438 | } |
374 | catch (Exception e) | 439 | catch (Exception e) |
375 | { | 440 | { |
376 | Debug.Assert(null != e); | 441 | Debug.Assert(null != e); |
377 | } | 442 | } |
@@ -382,6 +447,8 @@ namespace Amib.Threading.Internal | |||
382 | /// Set the result of the work item to return | 447 | /// Set the result of the work item to return |
383 | /// </summary> | 448 | /// </summary> |
384 | /// <param name="result">The result of the work item</param> | 449 | /// <param name="result">The result of the work item</param> |
450 | /// <param name="exception">The exception that was throw while the workitem executed, null | ||
451 | /// if there was no exception.</param> | ||
385 | internal void SetResult(object result, Exception exception) | 452 | internal void SetResult(object result, Exception exception) |
386 | { | 453 | { |
387 | _result = result; | 454 | _result = result; |
@@ -401,48 +468,48 @@ namespace Amib.Threading.Internal | |||
401 | /// <summary> | 468 | /// <summary> |
402 | /// Wait for all work items to complete | 469 | /// Wait for all work items to complete |
403 | /// </summary> | 470 | /// </summary> |
404 | /// <param name="workItemResults">Array of work item result objects</param> | 471 | /// <param name="waitableResults">Array of work item result objects</param> |
405 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | 472 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> |
406 | /// <param name="exitContext"> | 473 | /// <param name="exitContext"> |
407 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | 474 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. |
408 | /// </param> | 475 | /// </param> |
409 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> | 476 | /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> |
410 | /// <returns> | 477 | /// <returns> |
411 | /// true when every work item in workItemResults has completed; otherwise false. | 478 | /// true when every work item in waitableResults has completed; otherwise false. |
412 | /// </returns> | 479 | /// </returns> |
413 | internal static bool WaitAll( | 480 | internal static bool WaitAll( |
414 | IWorkItemResult [] workItemResults, | 481 | IWaitableResult[] waitableResults, |
415 | int millisecondsTimeout, | 482 | int millisecondsTimeout, |
416 | bool exitContext, | 483 | bool exitContext, |
417 | WaitHandle cancelWaitHandle) | 484 | WaitHandle cancelWaitHandle) |
418 | { | 485 | { |
419 | if (0 == workItemResults.Length) | 486 | if (0 == waitableResults.Length) |
420 | { | 487 | { |
421 | return true; | 488 | return true; |
422 | } | 489 | } |
423 | 490 | ||
424 | bool success; | 491 | bool success; |
425 | WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];; | 492 | WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length]; |
426 | GetWaitHandles(workItemResults, waitHandles); | 493 | GetWaitHandles(waitableResults, waitHandles); |
427 | 494 | ||
428 | if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) | 495 | if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) |
429 | { | 496 | { |
430 | success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); | 497 | success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); |
431 | } | 498 | } |
432 | else | 499 | else |
433 | { | 500 | { |
434 | success = true; | 501 | success = true; |
435 | int millisecondsLeft = millisecondsTimeout; | 502 | int millisecondsLeft = millisecondsTimeout; |
436 | DateTime start = DateTime.Now; | 503 | Stopwatch stopwatch = Stopwatch.StartNew(); |
437 | 504 | ||
438 | WaitHandle [] whs; | 505 | WaitHandle[] whs; |
439 | if (null != cancelWaitHandle) | 506 | if (null != cancelWaitHandle) |
440 | { | 507 | { |
441 | whs = new WaitHandle [] { null, cancelWaitHandle }; | 508 | whs = new WaitHandle[] { null, cancelWaitHandle }; |
442 | } | 509 | } |
443 | else | 510 | else |
444 | { | 511 | { |
445 | whs = new WaitHandle [] { null }; | 512 | whs = new WaitHandle[] { null }; |
446 | } | 513 | } |
447 | 514 | ||
448 | bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); | 515 | bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); |
@@ -450,7 +517,7 @@ namespace Amib.Threading.Internal | |||
450 | // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle | 517 | // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle |
451 | // won't affect it. | 518 | // won't affect it. |
452 | // Each iteration we update the time left for the timeout. | 519 | // Each iteration we update the time left for the timeout. |
453 | for(int i = 0; i < workItemResults.Length; ++i) | 520 | for (int i = 0; i < waitableResults.Length; ++i) |
454 | { | 521 | { |
455 | // WaitAny don't work with negative numbers | 522 | // WaitAny don't work with negative numbers |
456 | if (!waitInfinitely && (millisecondsLeft < 0)) | 523 | if (!waitInfinitely && (millisecondsLeft < 0)) |
@@ -460,23 +527,22 @@ namespace Amib.Threading.Internal | |||
460 | } | 527 | } |
461 | 528 | ||
462 | whs[0] = waitHandles[i]; | 529 | whs[0] = waitHandles[i]; |
463 | int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext); | 530 | int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext); |
464 | if((result > 0) || (WaitHandle.WaitTimeout == result)) | 531 | if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result)) |
465 | { | 532 | { |
466 | success = false; | 533 | success = false; |
467 | break; | 534 | break; |
468 | } | 535 | } |
469 | 536 | ||
470 | if(!waitInfinitely) | 537 | if (!waitInfinitely) |
471 | { | 538 | { |
472 | // Update the time left to wait | 539 | // Update the time left to wait |
473 | TimeSpan ts = DateTime.Now - start; | 540 | millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; |
474 | millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds; | ||
475 | } | 541 | } |
476 | } | 542 | } |
477 | } | 543 | } |
478 | // Release the wait handles | 544 | // Release the wait handles |
479 | ReleaseWaitHandles(workItemResults); | 545 | ReleaseWaitHandles(waitableResults); |
480 | 546 | ||
481 | return success; | 547 | return success; |
482 | } | 548 | } |
@@ -484,7 +550,7 @@ namespace Amib.Threading.Internal | |||
484 | /// <summary> | 550 | /// <summary> |
485 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout | 551 | /// Waits for any of the work items in the specified array to complete, cancel, or timeout |
486 | /// </summary> | 552 | /// </summary> |
487 | /// <param name="workItemResults">Array of work item result objects</param> | 553 | /// <param name="waitableResults">Array of work item result objects</param> |
488 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> | 554 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> |
489 | /// <param name="exitContext"> | 555 | /// <param name="exitContext"> |
490 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. | 556 | /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. |
@@ -493,38 +559,38 @@ namespace Amib.Threading.Internal | |||
493 | /// <returns> | 559 | /// <returns> |
494 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. | 560 | /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. |
495 | /// </returns> | 561 | /// </returns> |
496 | internal static int WaitAny( | 562 | internal static int WaitAny( |
497 | IWorkItemResult [] workItemResults, | 563 | IWaitableResult[] waitableResults, |
498 | int millisecondsTimeout, | 564 | int millisecondsTimeout, |
499 | bool exitContext, | 565 | bool exitContext, |
500 | WaitHandle cancelWaitHandle) | 566 | WaitHandle cancelWaitHandle) |
501 | { | 567 | { |
502 | WaitHandle [] waitHandles = null; | 568 | WaitHandle[] waitHandles; |
503 | 569 | ||
504 | if (null != cancelWaitHandle) | 570 | if (null != cancelWaitHandle) |
505 | { | 571 | { |
506 | waitHandles = new WaitHandle[workItemResults.Length+1]; | 572 | waitHandles = new WaitHandle[waitableResults.Length + 1]; |
507 | GetWaitHandles(workItemResults, waitHandles); | 573 | GetWaitHandles(waitableResults, waitHandles); |
508 | waitHandles[workItemResults.Length] = cancelWaitHandle; | 574 | waitHandles[waitableResults.Length] = cancelWaitHandle; |
509 | } | 575 | } |
510 | else | 576 | else |
511 | { | 577 | { |
512 | waitHandles = new WaitHandle[workItemResults.Length]; | 578 | waitHandles = new WaitHandle[waitableResults.Length]; |
513 | GetWaitHandles(workItemResults, waitHandles); | 579 | GetWaitHandles(waitableResults, waitHandles); |
514 | } | 580 | } |
515 | 581 | ||
516 | int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); | 582 | int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); |
517 | 583 | ||
518 | // Treat cancel as timeout | 584 | // Treat cancel as timeout |
519 | if (null != cancelWaitHandle) | 585 | if (null != cancelWaitHandle) |
520 | { | 586 | { |
521 | if (result == workItemResults.Length) | 587 | if (result == waitableResults.Length) |
522 | { | 588 | { |
523 | result = WaitHandle.WaitTimeout; | 589 | result = STPEventWaitHandle.WaitTimeout; |
524 | } | 590 | } |
525 | } | 591 | } |
526 | 592 | ||
527 | ReleaseWaitHandles(workItemResults); | 593 | ReleaseWaitHandles(waitableResults); |
528 | 594 | ||
529 | return result; | 595 | return result; |
530 | } | 596 | } |
@@ -532,16 +598,16 @@ namespace Amib.Threading.Internal | |||
532 | /// <summary> | 598 | /// <summary> |
533 | /// Fill an array of wait handles with the work items wait handles. | 599 | /// Fill an array of wait handles with the work items wait handles. |
534 | /// </summary> | 600 | /// </summary> |
535 | /// <param name="workItemResults">An array of work item results</param> | 601 | /// <param name="waitableResults">An array of work item results</param> |
536 | /// <param name="waitHandles">An array of wait handles to fill</param> | 602 | /// <param name="waitHandles">An array of wait handles to fill</param> |
537 | private static void GetWaitHandles( | 603 | private static void GetWaitHandles( |
538 | IWorkItemResult [] workItemResults, | 604 | IWaitableResult[] waitableResults, |
539 | WaitHandle [] waitHandles) | 605 | WaitHandle[] waitHandles) |
540 | { | 606 | { |
541 | for(int i = 0; i < workItemResults.Length; ++i) | 607 | for (int i = 0; i < waitableResults.Length; ++i) |
542 | { | 608 | { |
543 | WorkItemResult wir = workItemResults[i] as WorkItemResult; | 609 | WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult; |
544 | Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects"); | 610 | Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects"); |
545 | 611 | ||
546 | waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); | 612 | waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); |
547 | } | 613 | } |
@@ -550,40 +616,64 @@ namespace Amib.Threading.Internal | |||
550 | /// <summary> | 616 | /// <summary> |
551 | /// Release the work items' wait handles | 617 | /// Release the work items' wait handles |
552 | /// </summary> | 618 | /// </summary> |
553 | /// <param name="workItemResults">An array of work item results</param> | 619 | /// <param name="waitableResults">An array of work item results</param> |
554 | private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults) | 620 | private static void ReleaseWaitHandles(IWaitableResult[] waitableResults) |
555 | { | 621 | { |
556 | for(int i = 0; i < workItemResults.Length; ++i) | 622 | for (int i = 0; i < waitableResults.Length; ++i) |
557 | { | 623 | { |
558 | WorkItemResult wir = workItemResults[i] as WorkItemResult; | 624 | WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult(); |
559 | 625 | ||
560 | wir.GetWorkItem().ReleaseWaitHandle(); | 626 | wir.GetWorkItem().ReleaseWaitHandle(); |
561 | } | 627 | } |
562 | } | 628 | } |
563 | 629 | ||
564 | |||
565 | #endregion | 630 | #endregion |
566 | 631 | ||
567 | #region Private Members | 632 | #region Private Members |
568 | 633 | ||
569 | private WorkItemState GetWorkItemState() | 634 | private WorkItemState GetWorkItemState() |
570 | { | 635 | { |
571 | if (_canceledWorkItemsGroup.IsCanceled) | 636 | lock (this) |
572 | { | 637 | { |
573 | return WorkItemState.Canceled; | 638 | if (WorkItemState.Completed == _workItemState) |
574 | } | 639 | { |
575 | return _workItemState; | 640 | return _workItemState; |
641 | } | ||
642 | |||
643 | long nowTicks = DateTime.UtcNow.Ticks; | ||
576 | 644 | ||
645 | if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime) | ||
646 | { | ||
647 | _workItemState = WorkItemState.Canceled; | ||
648 | } | ||
649 | |||
650 | if (WorkItemState.InProgress == _workItemState) | ||
651 | { | ||
652 | return _workItemState; | ||
653 | } | ||
654 | |||
655 | if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled) | ||
656 | { | ||
657 | return WorkItemState.Canceled; | ||
658 | } | ||
659 | |||
660 | return _workItemState; | ||
661 | } | ||
577 | } | 662 | } |
663 | |||
664 | |||
578 | /// <summary> | 665 | /// <summary> |
579 | /// Sets the work item's state | 666 | /// Sets the work item's state |
580 | /// </summary> | 667 | /// </summary> |
581 | /// <param name="workItemState">The state to set the work item to</param> | 668 | /// <param name="workItemState">The state to set the work item to</param> |
582 | private void SetWorkItemState(WorkItemState workItemState) | 669 | private void SetWorkItemState(WorkItemState workItemState) |
583 | { | 670 | { |
584 | lock(this) | 671 | lock (this) |
585 | { | 672 | { |
586 | _workItemState = workItemState; | 673 | if (IsValidStatesTransition(_workItemState, workItemState)) |
674 | { | ||
675 | _workItemState = workItemState; | ||
676 | } | ||
587 | } | 677 | } |
588 | } | 678 | } |
589 | 679 | ||
@@ -594,7 +684,7 @@ namespace Amib.Threading.Internal | |||
594 | private void SignalComplete(bool canceled) | 684 | private void SignalComplete(bool canceled) |
595 | { | 685 | { |
596 | SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed); | 686 | SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed); |
597 | lock(this) | 687 | lock (this) |
598 | { | 688 | { |
599 | // If someone is waiting then signal. | 689 | // If someone is waiting then signal. |
600 | if (null != _workItemCompleted) | 690 | if (null != _workItemCompleted) |
@@ -606,40 +696,93 @@ namespace Amib.Threading.Internal | |||
606 | 696 | ||
607 | internal void WorkItemIsQueued() | 697 | internal void WorkItemIsQueued() |
608 | { | 698 | { |
609 | _queuedTime = DateTime.Now; | 699 | _waitingOnQueueStopwatch.Start(); |
610 | } | 700 | } |
611 | 701 | ||
612 | #endregion | 702 | #endregion |
613 | 703 | ||
614 | #region Members exposed by WorkItemResult | 704 | #region Members exposed by WorkItemResult |
615 | 705 | ||
616 | /// <summary> | 706 | /// <summary> |
617 | /// Cancel the work item if it didn't start running yet. | 707 | /// Cancel the work item if it didn't start running yet. |
618 | /// </summary> | 708 | /// </summary> |
619 | /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> | 709 | /// <returns>Returns true on success or false if the work item is in progress or already completed</returns> |
620 | private bool Cancel() | 710 | private bool Cancel(bool abortExecution) |
621 | { | 711 | { |
622 | lock(this) | 712 | #if (_WINDOWS_CE) |
713 | if(abortExecution) | ||
714 | { | ||
715 | throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature"); | ||
716 | } | ||
717 | #endif | ||
718 | bool success = false; | ||
719 | bool signalComplete = false; | ||
720 | |||
721 | lock (this) | ||
623 | { | 722 | { |
624 | switch(GetWorkItemState()) | 723 | switch (GetWorkItemState()) |
625 | { | 724 | { |
626 | case WorkItemState.Canceled: | 725 | case WorkItemState.Canceled: |
627 | //Debug.WriteLine("Work item already canceled"); | 726 | //Debug.WriteLine("Work item already canceled"); |
628 | return true; | 727 | if (abortExecution) |
728 | { | ||
729 | Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); | ||
730 | if (null != executionThread) | ||
731 | { | ||
732 | executionThread.Abort(); // "Cancel" | ||
733 | // No need to signalComplete, because we already cancelled this work item | ||
734 | // so it already signaled its completion. | ||
735 | //signalComplete = true; | ||
736 | } | ||
737 | } | ||
738 | success = true; | ||
739 | break; | ||
629 | case WorkItemState.Completed: | 740 | case WorkItemState.Completed: |
630 | case WorkItemState.InProgress: | ||
631 | //Debug.WriteLine("Work item cannot be canceled"); | 741 | //Debug.WriteLine("Work item cannot be canceled"); |
632 | return false; | 742 | break; |
743 | case WorkItemState.InProgress: | ||
744 | if (abortExecution) | ||
745 | { | ||
746 | Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); | ||
747 | if (null != executionThread) | ||
748 | { | ||
749 | executionThread.Abort(); // "Cancel" | ||
750 | success = true; | ||
751 | signalComplete = true; | ||
752 | } | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | // ************************** | ||
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; | ||
633 | case WorkItemState.InQueue: | 770 | case WorkItemState.InQueue: |
634 | // Signal to the wait for completion that the work | 771 | // Signal to the wait for completion that the work |
635 | // item has been completed (canceled). There is no | 772 | // item has been completed (canceled). There is no |
636 | // reason to wait for it to get out of the queue | 773 | // reason to wait for it to get out of the queue |
637 | SignalComplete(true); | 774 | signalComplete = true; |
638 | //Debug.WriteLine("Work item canceled"); | 775 | //Debug.WriteLine("Work item canceled"); |
639 | return true; | 776 | success = true; |
777 | break; | ||
778 | } | ||
779 | |||
780 | if (signalComplete) | ||
781 | { | ||
782 | SignalComplete(true); | ||
640 | } | 783 | } |
641 | } | 784 | } |
642 | return false; | 785 | return success; |
643 | } | 786 | } |
644 | 787 | ||
645 | /// <summary> | 788 | /// <summary> |
@@ -653,7 +796,7 @@ namespace Amib.Threading.Internal | |||
653 | bool exitContext, | 796 | bool exitContext, |
654 | WaitHandle cancelWaitHandle) | 797 | WaitHandle cancelWaitHandle) |
655 | { | 798 | { |
656 | Exception e = null; | 799 | Exception e; |
657 | object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); | 800 | object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); |
658 | if (null != e) | 801 | if (null != e) |
659 | { | 802 | { |
@@ -694,7 +837,7 @@ namespace Amib.Threading.Internal | |||
694 | { | 837 | { |
695 | WaitHandle wh = GetWaitHandle(); | 838 | WaitHandle wh = GetWaitHandle(); |
696 | 839 | ||
697 | bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext); | 840 | bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext); |
698 | 841 | ||
699 | ReleaseWaitHandle(); | 842 | ReleaseWaitHandle(); |
700 | 843 | ||
@@ -706,10 +849,10 @@ namespace Amib.Threading.Internal | |||
706 | else | 849 | else |
707 | { | 850 | { |
708 | WaitHandle wh = GetWaitHandle(); | 851 | WaitHandle wh = GetWaitHandle(); |
709 | int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); | 852 | int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); |
710 | ReleaseWaitHandle(); | 853 | ReleaseWaitHandle(); |
711 | 854 | ||
712 | switch(result) | 855 | switch (result) |
713 | { | 856 | { |
714 | case 0: | 857 | case 0: |
715 | // The work item signaled | 858 | // The work item signaled |
@@ -717,7 +860,7 @@ namespace Amib.Threading.Internal | |||
717 | // work item (not the get result) | 860 | // work item (not the get result) |
718 | break; | 861 | break; |
719 | case 1: | 862 | case 1: |
720 | case WaitHandle.WaitTimeout: | 863 | case STPEventWaitHandle.WaitTimeout: |
721 | throw new WorkItemTimeoutException("Work item timeout"); | 864 | throw new WorkItemTimeoutException("Work item timeout"); |
722 | default: | 865 | default: |
723 | Debug.Assert(false); | 866 | Debug.Assert(false); |
@@ -745,11 +888,11 @@ namespace Amib.Threading.Internal | |||
745 | /// </summary> | 888 | /// </summary> |
746 | private WaitHandle GetWaitHandle() | 889 | private WaitHandle GetWaitHandle() |
747 | { | 890 | { |
748 | lock(this) | 891 | lock (this) |
749 | { | 892 | { |
750 | if (null == _workItemCompleted) | 893 | if (null == _workItemCompleted) |
751 | { | 894 | { |
752 | _workItemCompleted = new ManualResetEvent(IsCompleted); | 895 | _workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted); |
753 | } | 896 | } |
754 | ++_workItemCompletedRefCount; | 897 | ++_workItemCompletedRefCount; |
755 | } | 898 | } |
@@ -758,7 +901,7 @@ namespace Amib.Threading.Internal | |||
758 | 901 | ||
759 | private void ReleaseWaitHandle() | 902 | private void ReleaseWaitHandle() |
760 | { | 903 | { |
761 | lock(this) | 904 | lock (this) |
762 | { | 905 | { |
763 | if (null != _workItemCompleted) | 906 | if (null != _workItemCompleted) |
764 | { | 907 | { |
@@ -779,10 +922,10 @@ namespace Amib.Threading.Internal | |||
779 | { | 922 | { |
780 | get | 923 | get |
781 | { | 924 | { |
782 | lock(this) | 925 | lock (this) |
783 | { | 926 | { |
784 | WorkItemState workItemState = GetWorkItemState(); | 927 | WorkItemState workItemState = GetWorkItemState(); |
785 | return ((workItemState == WorkItemState.Completed) || | 928 | return ((workItemState == WorkItemState.Completed) || |
786 | (workItemState == WorkItemState.Canceled)); | 929 | (workItemState == WorkItemState.Canceled)); |
787 | } | 930 | } |
788 | } | 931 | } |
@@ -795,7 +938,7 @@ namespace Amib.Threading.Internal | |||
795 | { | 938 | { |
796 | get | 939 | get |
797 | { | 940 | { |
798 | lock(this) | 941 | lock (this) |
799 | { | 942 | { |
800 | return (GetWorkItemState() == WorkItemState.Canceled); | 943 | return (GetWorkItemState() == WorkItemState.Canceled); |
801 | } | 944 | } |
@@ -843,172 +986,6 @@ namespace Amib.Threading.Internal | |||
843 | } | 986 | } |
844 | } | 987 | } |
845 | 988 | ||
846 | |||
847 | #region WorkItemResult class | ||
848 | |||
849 | private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult | ||
850 | { | ||
851 | /// <summary> | ||
852 | /// A back reference to the work item | ||
853 | /// </summary> | ||
854 | private WorkItem _workItem; | ||
855 | |||
856 | public WorkItemResult(WorkItem workItem) | ||
857 | { | ||
858 | _workItem = workItem; | ||
859 | } | ||
860 | |||
861 | internal WorkItem GetWorkItem() | ||
862 | { | ||
863 | return _workItem; | ||
864 | } | ||
865 | |||
866 | #region IWorkItemResult Members | ||
867 | |||
868 | public bool IsCompleted | ||
869 | { | ||
870 | get | ||
871 | { | ||
872 | return _workItem.IsCompleted; | ||
873 | } | ||
874 | } | ||
875 | |||
876 | public void Abort() | ||
877 | { | ||
878 | _workItem.Abort(); | ||
879 | } | ||
880 | |||
881 | public bool IsCanceled | ||
882 | { | ||
883 | get | ||
884 | { | ||
885 | return _workItem.IsCanceled; | ||
886 | } | ||
887 | } | ||
888 | |||
889 | public object GetResult() | ||
890 | { | ||
891 | return _workItem.GetResult(Timeout.Infinite, true, null); | ||
892 | } | ||
893 | |||
894 | public object GetResult(int millisecondsTimeout, bool exitContext) | ||
895 | { | ||
896 | return _workItem.GetResult(millisecondsTimeout, exitContext, null); | ||
897 | } | ||
898 | |||
899 | public object GetResult(TimeSpan timeout, bool exitContext) | ||
900 | { | ||
901 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); | ||
902 | } | ||
903 | |||
904 | public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) | ||
905 | { | ||
906 | return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); | ||
907 | } | ||
908 | |||
909 | public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) | ||
910 | { | ||
911 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); | ||
912 | } | ||
913 | |||
914 | public object GetResult(out Exception e) | ||
915 | { | ||
916 | return _workItem.GetResult(Timeout.Infinite, true, null, out e); | ||
917 | } | ||
918 | |||
919 | public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) | ||
920 | { | ||
921 | return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); | ||
922 | } | ||
923 | |||
924 | public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) | ||
925 | { | ||
926 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); | ||
927 | } | ||
928 | |||
929 | public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) | ||
930 | { | ||
931 | return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); | ||
932 | } | ||
933 | |||
934 | public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) | ||
935 | { | ||
936 | return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); | ||
937 | } | ||
938 | |||
939 | public bool Cancel() | ||
940 | { | ||
941 | return _workItem.Cancel(); | ||
942 | } | ||
943 | |||
944 | public object State | ||
945 | { | ||
946 | get | ||
947 | { | ||
948 | return _workItem._state; | ||
949 | } | ||
950 | } | ||
951 | |||
952 | public WorkItemPriority WorkItemPriority | ||
953 | { | ||
954 | get | ||
955 | { | ||
956 | return _workItem._workItemInfo.WorkItemPriority; | ||
957 | } | ||
958 | } | ||
959 | |||
960 | /// <summary> | ||
961 | /// Return the result, same as GetResult() | ||
962 | /// </summary> | ||
963 | public object Result | ||
964 | { | ||
965 | get { return GetResult(); } | ||
966 | } | ||
967 | |||
968 | /// <summary> | ||
969 | /// Returns the exception if occured otherwise returns null. | ||
970 | /// This value is valid only after the work item completed, | ||
971 | /// before that it is always null. | ||
972 | /// </summary> | ||
973 | public object Exception | ||
974 | { | ||
975 | get { return _workItem._exception; } | ||
976 | } | ||
977 | |||
978 | #endregion | ||
979 | |||
980 | #region IInternalWorkItemResult Members | ||
981 | |||
982 | public event WorkItemStateCallback OnWorkItemStarted | ||
983 | { | ||
984 | add | ||
985 | { | ||
986 | _workItem.OnWorkItemStarted += value; | ||
987 | } | ||
988 | remove | ||
989 | { | ||
990 | _workItem.OnWorkItemStarted -= value; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | |||
995 | public event WorkItemStateCallback OnWorkItemCompleted | ||
996 | { | ||
997 | add | ||
998 | { | ||
999 | _workItem.OnWorkItemCompleted += value; | ||
1000 | } | ||
1001 | remove | ||
1002 | { | ||
1003 | _workItem.OnWorkItemCompleted -= value; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | #endregion | ||
1008 | } | ||
1009 | |||
1010 | #endregion | ||
1011 | |||
1012 | public void DisposeOfState() | 989 | public void DisposeOfState() |
1013 | { | 990 | { |
1014 | if (_workItemInfo.DisposeOfStateObjects) | 991 | if (_workItemInfo.DisposeOfStateObjects) |
@@ -1021,15 +998,5 @@ namespace Amib.Threading.Internal | |||
1021 | } | 998 | } |
1022 | } | 999 | } |
1023 | } | 1000 | } |
1024 | |||
1025 | public void Abort() | ||
1026 | { | ||
1027 | lock (this) | ||
1028 | { | ||
1029 | if(currentThread != null) | ||
1030 | currentThread.Abort(); | ||
1031 | } | ||
1032 | } | ||
1033 | } | 1001 | } |
1034 | #endregion | ||
1035 | } | 1002 | } |