aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
diff options
context:
space:
mode:
authoronefang2019-09-11 16:36:50 +1000
committeronefang2019-09-11 16:36:50 +1000
commit50cd1ffd32f69228e566f2b0b89f86ea0d9fe489 (patch)
tree52f2ab0c04f1a5d7d6ac5dc872981b4b156447e7 /ThirdParty/SmartThreadPool/WorkItemsQueue.cs
parentRenamed branch to SledjChisl. (diff)
parentBump to release flavour, build 0. (diff)
downloadopensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.zip
opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.gz
opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.bz2
opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.xz
Merge branch 'SledjChisl'
Diffstat (limited to 'ThirdParty/SmartThreadPool/WorkItemsQueue.cs')
-rw-r--r--ThirdParty/SmartThreadPool/WorkItemsQueue.cs871
1 files changed, 436 insertions, 435 deletions
diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
index e0bc916..21403a0 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
@@ -4,29 +4,29 @@ using System.Threading;
4 4
5namespace Amib.Threading.Internal 5namespace Amib.Threading.Internal
6{ 6{
7 #region WorkItemsQueue class 7 #region WorkItemsQueue class
8 8
9 /// <summary> 9 /// <summary>
10 /// WorkItemsQueue class. 10 /// WorkItemsQueue class.
11 /// </summary> 11 /// </summary>
12 public class WorkItemsQueue : IDisposable 12 public class WorkItemsQueue : IDisposable
13 { 13 {
14 #region Member variables 14 #region Member variables
15 15
16 /// <summary> 16 /// <summary>
17 /// Waiters queue (implemented as stack). 17 /// Waiters queue (implemented as stack).
18 /// </summary> 18 /// </summary>
19 private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); 19 private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
20 20
21 /// <summary> 21 /// <summary>
22 /// Waiters count 22 /// Waiters count
23 /// </summary> 23 /// </summary>
24 private int _waitersCount = 0; 24 private int _waitersCount = 0;
25 25
26 /// <summary> 26 /// <summary>
27 /// Work items queue 27 /// Work items queue
28 /// </summary> 28 /// </summary>
29 private readonly PriorityQueue _workItems = new PriorityQueue(); 29 private readonly PriorityQueue _workItems = new PriorityQueue();
30 30
31 /// <summary> 31 /// <summary>
32 /// Indicate that work items are allowed to be queued 32 /// Indicate that work items are allowed to be queued
@@ -34,7 +34,7 @@ namespace Amib.Threading.Internal
34 private bool _isWorkItemsQueueActive = true; 34 private bool _isWorkItemsQueueActive = true;
35 35
36 36
37#if (WINDOWS_PHONE) 37#if (WINDOWS_PHONE)
38 private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>(); 38 private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>();
39#elif (_WINDOWS_CE) 39#elif (_WINDOWS_CE)
40 private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); 40 private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
@@ -50,7 +50,7 @@ namespace Amib.Threading.Internal
50 /// </summary> 50 /// </summary>
51 private static WaiterEntry CurrentWaiterEntry 51 private static WaiterEntry CurrentWaiterEntry
52 { 52 {
53#if (WINDOWS_PHONE) 53#if (WINDOWS_PHONE)
54 get 54 get
55 { 55 {
56 lock (_waiterEntries) 56 lock (_waiterEntries)
@@ -92,60 +92,60 @@ namespace Amib.Threading.Internal
92 } 92 }
93 93
94 /// <summary> 94 /// <summary>
95 /// A flag that indicates if the WorkItemsQueue has been disposed. 95 /// A flag that indicates if the WorkItemsQueue has been disposed.
96 /// </summary> 96 /// </summary>
97 private bool _isDisposed = false; 97 private bool _isDisposed = false;
98 98
99 #endregion 99 #endregion
100 100
101 #region Public properties 101 #region Public properties
102 102
103 /// <summary> 103 /// <summary>
104 /// Returns the current number of work items in the queue 104 /// Returns the current number of work items in the queue
105 /// </summary> 105 /// </summary>
106 public int Count 106 public int Count
107 { 107 {
108 get 108 get
109 { 109 {
110 return _workItems.Count; 110 return _workItems.Count;
111 } 111 }
112 } 112 }
113 113
114 /// <summary> 114 /// <summary>
115 /// Returns the current number of waiters 115 /// Returns the current number of waiters
116 /// </summary> 116 /// </summary>
117 public int WaitersCount 117 public int WaitersCount
118 { 118 {
119 get 119 get
120 { 120 {
121 return _waitersCount; 121 return _waitersCount;
122 } 122 }
123 } 123 }
124 124
125 125
126 #endregion 126 #endregion
127 127
128 #region Public methods 128 #region Public methods
129 129
130 /// <summary> 130 /// <summary>
131 /// Enqueue a work item to the queue. 131 /// Enqueue a work item to the queue.
132 /// </summary> 132 /// </summary>
133 public bool EnqueueWorkItem(WorkItem workItem) 133 public bool EnqueueWorkItem(WorkItem workItem)
134 { 134 {
135 // A work item cannot be null, since null is used in the 135 // A work item cannot be null, since null is used in the
136 // WaitForWorkItem() method to indicate timeout or cancel 136 // WaitForWorkItem() method to indicate timeout or cancel
137 if (null == workItem) 137 if (null == workItem)
138 { 138 {
139 throw new ArgumentNullException("workItem" , "workItem cannot be null"); 139 throw new ArgumentNullException("workItem" , "workItem cannot be null");
140 } 140 }
141 141
142 bool enqueue = true; 142 bool enqueue = true;
143 143
144 // First check if there is a waiter waiting for work item. During 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 145 // the check, timed out waiters are ignored. If there is no
146 // waiter then the work item is queued. 146 // waiter then the work item is queued.
147 lock(this) 147 lock(this)
148 { 148 {
149 ValidateNotDisposed(); 149 ValidateNotDisposed();
150 150
151 if (!_isWorkItemsQueueActive) 151 if (!_isWorkItemsQueueActive)
@@ -153,55 +153,55 @@ namespace Amib.Threading.Internal
153 return false; 153 return false;
154 } 154 }
155 155
156 while(_waitersCount > 0) 156 while(_waitersCount > 0)
157 { 157 {
158 // Dequeue a waiter. 158 // Dequeue a waiter.
159 WaiterEntry waiterEntry = PopWaiter(); 159 WaiterEntry waiterEntry = PopWaiter();
160 160
161 // Signal the waiter. On success break the loop 161 // Signal the waiter. On success break the loop
162 if (waiterEntry.Signal(workItem)) 162 if (waiterEntry.Signal(workItem))
163 { 163 {
164 enqueue = false; 164 enqueue = false;
165 break; 165 break;
166 } 166 }
167 } 167 }
168 168
169 if (enqueue) 169 if (enqueue)
170 { 170 {
171 // Enqueue the work item 171 // Enqueue the work item
172 _workItems.Enqueue(workItem); 172 _workItems.Enqueue(workItem);
173 } 173 }
174 } 174 }
175 return true; 175 return true;
176 } 176 }
177 177
178 178
179 /// <summary> 179 /// <summary>
180 /// Waits for a work item or exits on timeout or cancel 180 /// Waits for a work item or exits on timeout or cancel
181 /// </summary> 181 /// </summary>
182 /// <param name="millisecondsTimeout">Timeout in milliseconds</param> 182 /// <param name="millisecondsTimeout">Timeout in milliseconds</param>
183 /// <param name="cancelEvent">Cancel wait handle</param> 183 /// <param name="cancelEvent">Cancel wait handle</param>
184 /// <returns>Returns true if the resource was granted</returns> 184 /// <returns>Returns true if the resource was granted</returns>
185 public WorkItem DequeueWorkItem( 185 public WorkItem DequeueWorkItem(
186 int millisecondsTimeout, 186 int millisecondsTimeout,
187 WaitHandle cancelEvent) 187 WaitHandle cancelEvent)
188 { 188 {
189 // This method cause the caller to wait for a work item. 189 // This method cause the caller to wait for a work item.
190 // If there is at least one waiting work item then the 190 // If there is at least one waiting work item then the
191 // method returns immidiately with it. 191 // method returns immidiately with it.
192 // 192 //
193 // If there are no waiting work items then the caller 193 // If there are no waiting work items then the caller
194 // is queued between other waiters for a work item to arrive. 194 // is queued between other waiters for a work item to arrive.
195 // 195 //
196 // If a work item didn't come within millisecondsTimeout or 196 // If a work item didn't come within millisecondsTimeout or
197 // the user canceled the wait by signaling the cancelEvent 197 // the user canceled the wait by signaling the cancelEvent
198 // then the method returns null to indicate that the caller 198 // then the method returns null to indicate that the caller
199 // didn't get a work item. 199 // didn't get a work item.
200 200
201 WaiterEntry waiterEntry; 201 WaiterEntry waiterEntry;
202 WorkItem workItem = null; 202 WorkItem workItem = null;
203 lock (this) 203 lock (this)
204 { 204 {
205 ValidateNotDisposed(); 205 ValidateNotDisposed();
206 206
207 // If there are waiting work items then take one and return. 207 // If there are waiting work items then take one and return.
@@ -218,68 +218,68 @@ namespace Amib.Threading.Internal
218 218
219 // Put the waiter with the other waiters 219 // Put the waiter with the other waiters
220 PushWaiter(waiterEntry); 220 PushWaiter(waiterEntry);
221 } 221 }
222 222
223 // Prepare array of wait handle for the WaitHandle.WaitAny() 223 // Prepare array of wait handle for the WaitHandle.WaitAny()
224 WaitHandle [] waitHandles = new WaitHandle[] { 224 WaitHandle [] waitHandles = new WaitHandle[] {
225 waiterEntry.WaitHandle, 225 waiterEntry.WaitHandle,
226 cancelEvent }; 226 cancelEvent };
227 227
228 // Wait for an available resource, cancel event, or timeout. 228 // Wait for an available resource, cancel event, or timeout.
229 229
230 // During the wait we are supposes to exit the synchronization 230 // During the wait we are supposes to exit the synchronization
231 // domain. (Placing true as the third argument of the WaitAny()) 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) 232 // It just doesn't work, I don't know why, so I have two lock(this)
233 // statments instead of one. 233 // statments instead of one.
234 234
235 int index = STPEventWaitHandle.WaitAny( 235 int index = STPEventWaitHandle.WaitAny(
236 waitHandles, 236 waitHandles,
237 millisecondsTimeout, 237 millisecondsTimeout,
238 true); 238 true);
239 239
240 lock(this) 240 lock(this)
241 { 241 {
242 // success is true if it got a work item. 242 // success is true if it got a work item.
243 bool success = (0 == index); 243 bool success = (0 == index);
244 244
245 // The timeout variable is used only for readability. 245 // The timeout variable is used only for readability.
246 // (We treat cancel as timeout) 246 // (We treat cancel as timeout)
247 bool timeout = !success; 247 bool timeout = !success;
248 248
249 // On timeout update the waiterEntry that it is timed out 249 // On timeout update the waiterEntry that it is timed out
250 if (timeout) 250 if (timeout)
251 { 251 {
252 // The Timeout() fails if the waiter has already been signaled 252 // The Timeout() fails if the waiter has already been signaled
253 timeout = waiterEntry.Timeout(); 253 timeout = waiterEntry.Timeout();
254 254
255 // On timeout remove the waiter from the queue. 255 // On timeout remove the waiter from the queue.
256 // Note that the complexity is O(1). 256 // Note that the complexity is O(1).
257 if(timeout) 257 if(timeout)
258 { 258 {
259 RemoveWaiter(waiterEntry, false); 259 RemoveWaiter(waiterEntry, false);
260 } 260 }
261 261
262 // Again readability 262 // Again readability
263 success = !timeout; 263 success = !timeout;
264 } 264 }
265 265
266 // On success return the work item 266 // On success return the work item
267 if (success) 267 if (success)
268 { 268 {
269 workItem = waiterEntry.WorkItem; 269 workItem = waiterEntry.WorkItem;
270 270
271 if (null == workItem) 271 if (null == workItem)
272 { 272 {
273 workItem = _workItems.Dequeue() as WorkItem; 273 workItem = _workItems.Dequeue() as WorkItem;
274 } 274 }
275 } 275 }
276 } 276 }
277 // On failure return null. 277 // On failure return null.
278 return workItem; 278 return workItem;
279 } 279 }
280 280
281 /// <summary> 281 /// <summary>
282 /// Cleanup the work items queue, hence no more work 282 /// Cleanup the work items queue, hence no more work
283 /// items are allowed to be queue 283 /// items are allowed to be queue
284 /// </summary> 284 /// </summary>
285 private void Cleanup() 285 private void Cleanup()
@@ -303,19 +303,19 @@ namespace Amib.Threading.Internal
303 // Clear the work items that are already queued 303 // Clear the work items that are already queued
304 _workItems.Clear(); 304 _workItems.Clear();
305 305
306 // Note: 306 // Note:
307 // I don't iterate over the queue and dispose of work items's states, 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 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. 309 // application then I must not dispose it.
310 310
311 // Tell the waiters that they were timed out. 311 // Tell the waiters that they were timed out.
312 // It won't signal them to exit, but to ignore their 312 // It won't signal them to exit, but to ignore their
313 // next work item. 313 // next work item.
314 while(_waitersCount > 0) 314 while(_waitersCount > 0)
315 { 315 {
316 WaiterEntry waiterEntry = PopWaiter(); 316 WaiterEntry waiterEntry = PopWaiter();
317 waiterEntry.Timeout(); 317 waiterEntry.Timeout();
318 } 318 }
319 } 319 }
320 } 320 }
321 321
@@ -334,275 +334,275 @@ namespace Amib.Threading.Internal
334 } 334 }
335 } 335 }
336 336
337 #endregion 337 #endregion
338 338
339 #region Private methods 339 #region Private methods
340 340
341 /// <summary> 341 /// <summary>
342 /// Returns the WaiterEntry of the current thread 342 /// Returns the WaiterEntry of the current thread
343 /// </summary> 343 /// </summary>
344 /// <returns></returns> 344 /// <returns></returns>
345 /// In order to avoid creation and destuction of WaiterEntry 345 /// In order to avoid creation and destuction of WaiterEntry
346 /// objects each thread has its own WaiterEntry object. 346 /// objects each thread has its own WaiterEntry object.
347 private static WaiterEntry GetThreadWaiterEntry() 347 private static WaiterEntry GetThreadWaiterEntry()
348 { 348 {
349 if (null == CurrentWaiterEntry) 349 if (null == CurrentWaiterEntry)
350 { 350 {
351 CurrentWaiterEntry = new WaiterEntry(); 351 CurrentWaiterEntry = new WaiterEntry();
352 } 352 }
353 CurrentWaiterEntry.Reset(); 353 CurrentWaiterEntry.Reset();
354 return CurrentWaiterEntry; 354 return CurrentWaiterEntry;
355 } 355 }
356 356
357 #region Waiters stack methods 357 #region Waiters stack methods
358 358
359 /// <summary> 359 /// <summary>
360 /// Push a new waiter into the waiter's stack 360 /// Push a new waiter into the waiter's stack
361 /// </summary> 361 /// </summary>
362 /// <param name="newWaiterEntry">A waiter to put in the stack</param> 362 /// <param name="newWaiterEntry">A waiter to put in the stack</param>
363 public void PushWaiter(WaiterEntry newWaiterEntry) 363 public void PushWaiter(WaiterEntry newWaiterEntry)
364 { 364 {
365 // Remove the waiter if it is already in the stack and 365 // Remove the waiter if it is already in the stack and
366 // update waiter's count as needed 366 // update waiter's count as needed
367 RemoveWaiter(newWaiterEntry, false); 367 RemoveWaiter(newWaiterEntry, false);
368 368
369 // If the stack is empty then newWaiterEntry is the new head of the stack 369 // If the stack is empty then newWaiterEntry is the new head of the stack
370 if (null == _headWaiterEntry._nextWaiterEntry) 370 if (null == _headWaiterEntry._nextWaiterEntry)
371 { 371 {
372 _headWaiterEntry._nextWaiterEntry = newWaiterEntry; 372 _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
373 newWaiterEntry._prevWaiterEntry = _headWaiterEntry; 373 newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
374 374
375 } 375 }
376 // If the stack is not empty then put newWaiterEntry as the new head 376 // If the stack is not empty then put newWaiterEntry as the new head
377 // of the stack. 377 // of the stack.
378 else 378 else
379 { 379 {
380 // Save the old first waiter entry 380 // Save the old first waiter entry
381 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; 381 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
382 382
383 // Update the links 383 // Update the links
384 _headWaiterEntry._nextWaiterEntry = newWaiterEntry; 384 _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
385 newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; 385 newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
386 newWaiterEntry._prevWaiterEntry = _headWaiterEntry; 386 newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
387 oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; 387 oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
388 } 388 }
389 389
390 // Increment the number of waiters 390 // Increment the number of waiters
391 ++_waitersCount; 391 ++_waitersCount;
392 } 392 }
393 393
394 /// <summary> 394 /// <summary>
395 /// Pop a waiter from the waiter's stack 395 /// Pop a waiter from the waiter's stack
396 /// </summary> 396 /// </summary>
397 /// <returns>Returns the first waiter in the stack</returns> 397 /// <returns>Returns the first waiter in the stack</returns>
398 private WaiterEntry PopWaiter() 398 private WaiterEntry PopWaiter()
399 { 399 {
400 // Store the current stack head 400 // Store the current stack head
401 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; 401 WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
402 402
403 // Store the new stack head 403 // Store the new stack head
404 WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; 404 WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
405 405
406 // Update the old stack head list links and decrement the number 406 // Update the old stack head list links and decrement the number
407 // waiters. 407 // waiters.
408 RemoveWaiter(oldFirstWaiterEntry, true); 408 RemoveWaiter(oldFirstWaiterEntry, true);
409 409
410 // Update the new stack head 410 // Update the new stack head
411 _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; 411 _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
412 if (null != newHeadWaiterEntry) 412 if (null != newHeadWaiterEntry)
413 { 413 {
414 newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; 414 newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
415 } 415 }
416 416
417 // Return the old stack head 417 // Return the old stack head
418 return oldFirstWaiterEntry; 418 return oldFirstWaiterEntry;
419 } 419 }
420 420
421 /// <summary> 421 /// <summary>
422 /// Remove a waiter from the stack 422 /// Remove a waiter from the stack
423 /// </summary> 423 /// </summary>
424 /// <param name="waiterEntry">A waiter entry to remove</param> 424 /// <param name="waiterEntry">A waiter entry to remove</param>
425 /// <param name="popDecrement">If true the waiter count is always decremented</param> 425 /// <param name="popDecrement">If true the waiter count is always decremented</param>
426 private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) 426 private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
427 { 427 {
428 // Store the prev entry in the list 428 // Store the prev entry in the list
429 WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; 429 WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
430 430
431 // Store the next entry in the list 431 // Store the next entry in the list
432 WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; 432 WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
433 433
434 // A flag to indicate if we need to decrement the waiters count. 434 // A flag to indicate if we need to decrement the waiters count.
435 // If we got here from PopWaiter then we must decrement. 435 // If we got here from PopWaiter then we must decrement.
436 // If we got here from PushWaiter then we decrement only if 436 // If we got here from PushWaiter then we decrement only if
437 // the waiter was already in the stack. 437 // the waiter was already in the stack.
438 bool decrementCounter = popDecrement; 438 bool decrementCounter = popDecrement;
439 439
440 // Null the waiter's entry links 440 // Null the waiter's entry links
441 waiterEntry._prevWaiterEntry = null; 441 waiterEntry._prevWaiterEntry = null;
442 waiterEntry._nextWaiterEntry = null; 442 waiterEntry._nextWaiterEntry = null;
443 443
444 // If the waiter entry had a prev link then update it. 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 445 // It also means that the waiter is already in the list and we
446 // need to decrement the waiters count. 446 // need to decrement the waiters count.
447 if (null != prevWaiterEntry) 447 if (null != prevWaiterEntry)
448 { 448 {
449 prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; 449 prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
450 decrementCounter = true; 450 decrementCounter = true;
451 } 451 }
452 452
453 // If the waiter entry had a next link then update it. 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 454 // It also means that the waiter is already in the list and we
455 // need to decrement the waiters count. 455 // need to decrement the waiters count.
456 if (null != nextWaiterEntry) 456 if (null != nextWaiterEntry)
457 { 457 {
458 nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; 458 nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
459 decrementCounter = true; 459 decrementCounter = true;
460 } 460 }
461 461
462 // Decrement the waiters count if needed 462 // Decrement the waiters count if needed
463 if (decrementCounter) 463 if (decrementCounter)
464 { 464 {
465 --_waitersCount; 465 --_waitersCount;
466 } 466 }
467 } 467 }
468 468
469 #endregion 469 #endregion
470 470
471 #endregion 471 #endregion
472 472
473 #region WaiterEntry class 473 #region WaiterEntry class
474 474
475 // A waiter entry in the _waiters queue. 475 // A waiter entry in the _waiters queue.
476 public sealed class WaiterEntry : IDisposable 476 public sealed class WaiterEntry : IDisposable
477 { 477 {
478 #region Member variables 478 #region Member variables
479 479
480 /// <summary> 480 /// <summary>
481 /// Event to signal the waiter that it got the work item. 481 /// Event to signal the waiter that it got the work item.
482 /// </summary> 482 /// </summary>
483 //private AutoResetEvent _waitHandle = new AutoResetEvent(false); 483 //private AutoResetEvent _waitHandle = new AutoResetEvent(false);
484 private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); 484 private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
485 485
486 /// <summary> 486 /// <summary>
487 /// Flag to know if this waiter already quited from the queue 487 /// Flag to know if this waiter already quited from the queue
488 /// because of a timeout. 488 /// because of a timeout.
489 /// </summary> 489 /// </summary>
490 private bool _isTimedout = false; 490 private bool _isTimedout = false;
491 491
492 /// <summary> 492 /// <summary>
493 /// Flag to know if the waiter was signaled and got a work item. 493 /// Flag to know if the waiter was signaled and got a work item.
494 /// </summary> 494 /// </summary>
495 private bool _isSignaled = false; 495 private bool _isSignaled = false;
496 496
497 /// <summary> 497 /// <summary>
498 /// A work item that passed directly to the waiter withou going 498 /// A work item that passed directly to the waiter withou going
499 /// through the queue 499 /// through the queue
500 /// </summary> 500 /// </summary>
501 private WorkItem _workItem = null; 501 private WorkItem _workItem = null;
502 502
503 private bool _isDisposed = false; 503 private bool _isDisposed = false;
504 504
505 // Linked list members 505 // Linked list members
506 internal WaiterEntry _nextWaiterEntry = null; 506 internal WaiterEntry _nextWaiterEntry = null;
507 internal WaiterEntry _prevWaiterEntry = null; 507 internal WaiterEntry _prevWaiterEntry = null;
508 508
509 #endregion 509 #endregion
510 510
511 #region Construction 511 #region Construction
512 512
513 public WaiterEntry() 513 public WaiterEntry()
514 { 514 {
515 Reset(); 515 Reset();
516 } 516 }
517 517
518 #endregion 518 #endregion
519 519
520 #region Public methods 520 #region Public methods
521 521
522 public WaitHandle WaitHandle 522 public WaitHandle WaitHandle
523 { 523 {
524 get { return _waitHandle; } 524 get { return _waitHandle; }
525 } 525 }
526 526
527 public WorkItem WorkItem 527 public WorkItem WorkItem
528 { 528 {
529 get 529 get
530 { 530 {
531 return _workItem; 531 return _workItem;
532 } 532 }
533 } 533 }
534 534
535 /// <summary> 535 /// <summary>
536 /// Signal the waiter that it got a work item. 536 /// Signal the waiter that it got a work item.
537 /// </summary> 537 /// </summary>
538 /// <returns>Return true on success</returns> 538 /// <returns>Return true on success</returns>
539 /// The method fails if Timeout() preceded its call 539 /// The method fails if Timeout() preceded its call
540 public bool Signal(WorkItem workItem) 540 public bool Signal(WorkItem workItem)
541 { 541 {
542 lock(this) 542 lock(this)
543 { 543 {
544 if (!_isTimedout) 544 if (!_isTimedout)
545 { 545 {
546 _workItem = workItem; 546 _workItem = workItem;
547 _isSignaled = true; 547 _isSignaled = true;
548 _waitHandle.Set(); 548 _waitHandle.Set();
549 return true; 549 return true;
550 } 550 }
551 } 551 }
552 return false; 552 return false;
553 } 553 }
554 554
555 /// <summary> 555 /// <summary>
556 /// Mark the wait entry that it has been timed out 556 /// Mark the wait entry that it has been timed out
557 /// </summary> 557 /// </summary>
558 /// <returns>Return true on success</returns> 558 /// <returns>Return true on success</returns>
559 /// The method fails if Signal() preceded its call 559 /// The method fails if Signal() preceded its call
560 public bool Timeout() 560 public bool Timeout()
561 { 561 {
562 lock(this) 562 lock(this)
563 { 563 {
564 // Time out can happen only if the waiter wasn't marked as 564 // Time out can happen only if the waiter wasn't marked as
565 // signaled 565 // signaled
566 if (!_isSignaled) 566 if (!_isSignaled)
567 { 567 {
568 // We don't remove the waiter from the queue, the DequeueWorkItem 568 // We don't remove the waiter from the queue, the DequeueWorkItem
569 // method skips _waiters that were timed out. 569 // method skips _waiters that were timed out.
570 _isTimedout = true; 570 _isTimedout = true;
571 return true; 571 return true;
572 } 572 }
573 } 573 }
574 return false; 574 return false;
575 } 575 }
576 576
577 /// <summary> 577 /// <summary>
578 /// Reset the wait entry so it can be used again 578 /// Reset the wait entry so it can be used again
579 /// </summary> 579 /// </summary>
580 public void Reset() 580 public void Reset()
581 { 581 {
582 _workItem = null; 582 _workItem = null;
583 _isTimedout = false; 583 _isTimedout = false;
584 _isSignaled = false; 584 _isSignaled = false;
585 _waitHandle.Reset(); 585 _waitHandle.Reset();
586 } 586 }
587 587
588 /// <summary> 588 /// <summary>
589 /// Free resources 589 /// Free resources
590 /// </summary> 590 /// </summary>
591 public void Close() 591 public void Close()
592 { 592 {
593 if (null != _waitHandle) 593 if (null != _waitHandle)
594 { 594 {
595 _waitHandle.Close(); 595 _waitHandle.Close();
596 _waitHandle = null; 596 _waitHandle = null;
597 } 597 }
598 } 598 }
599 599
600 #endregion 600 #endregion
601 601
602 #region IDisposable Members 602 #region IDisposable Members
603 603
604 public void Dispose() 604 public void Dispose()
605 { 605 {
606 lock (this) 606 lock (this)
607 { 607 {
608 if (!_isDisposed) 608 if (!_isDisposed)
@@ -613,10 +613,10 @@ namespace Amib.Threading.Internal
613 } 613 }
614 } 614 }
615 615
616 #endregion 616 #endregion
617 } 617 }
618 618
619 #endregion 619 #endregion
620 620
621 #region IDisposable Members 621 #region IDisposable Members
622 622
@@ -625,6 +625,7 @@ namespace Amib.Threading.Internal
625 if (!_isDisposed) 625 if (!_isDisposed)
626 { 626 {
627 Cleanup(); 627 Cleanup();
628 _headWaiterEntry.Close();
628 } 629 }
629 _isDisposed = true; 630 _isDisposed = true;
630 } 631 }
@@ -640,6 +641,6 @@ namespace Amib.Threading.Internal
640 #endregion 641 #endregion
641 } 642 }
642 643
643 #endregion 644 #endregion
644} 645}
645 646