/// <summary> /// Returns the WaitEntry of the current thread /// </summary> /// <returns></returns> /// In order to avoid creation and destuction of WaitEntry /// objects each thread has its own WaitEntry object. private WaitEntry GetThreadWaitEntry() { if (null == _waitEntry) { _waitEntry = new WaitEntry(); } _waitEntry.Reset(); return(_waitEntry); }
private WaitEntry PopWaiter() { WaitEntry waitEntry = this._headWaitEntry._nextWaiterEntry; WaitEntry entry2 = waitEntry._nextWaiterEntry; this.RemoveWaiter(waitEntry, true); this._headWaitEntry._nextWaiterEntry = entry2; if (null != entry2) { entry2._prevWaiterEntry = this._headWaitEntry; } return(waitEntry); }
public WaitEntry CreateWaitHandle(ServerCommand condition) { if (!_waitEntryPool.TryPop(out var entry)) { entry = new WaitEntry(this); } entry.Prepare(condition); lock (_waitHandles) { _waitHandles.AddLast(entry); } return(entry); }
public void PushWaitEntry(WaitEntry newWaiterEntry) { this.RemoveWaiter(newWaiterEntry, false); if (null == this._headWaitEntry._nextWaiterEntry) { this._headWaitEntry._nextWaiterEntry = newWaiterEntry; newWaiterEntry._prevWaiterEntry = this._headWaitEntry; } else { WaitEntry entry = this._headWaitEntry._nextWaiterEntry; this._headWaitEntry._nextWaiterEntry = newWaiterEntry; newWaiterEntry._nextWaiterEntry = entry; newWaiterEntry._prevWaiterEntry = this._headWaitEntry; entry._prevWaiterEntry = newWaiterEntry; } this._waitersCount++; }
public WorkItem DequeueWorkItem(int millisecondsTimeout, WaitHandle cancelEvent) { WaitEntry newWaiterEntry = null; WorkItem workItem = null; WorkItemsQueue queue; lock ((queue = this)) { this.CheckDisposed(); if (this._workItems.Count > 0) { return(this._workItems.Dequeue() as WorkItem); } newWaiterEntry = this.GetThreadWaitEntry(); this.PushWaitEntry(newWaiterEntry); } WaitHandle[] waitHandles = new WaitHandle[] { newWaiterEntry.WaitHandle, cancelEvent }; int num = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, true); lock ((queue = this)) { bool flag = 0 == num; if (!flag) { bool flag2 = newWaiterEntry.Timeout(); if (flag2) { this.RemoveWaiter(newWaiterEntry, false); } flag = !flag2; } if (flag) { workItem = newWaiterEntry.WorkItem; if (workItem == null) { workItem = this._workItems.Dequeue() as WorkItem; } } } return(workItem); }
/// <summary> /// Enqueue a work item to the queue. /// </summary> public bool EnqueueWorkItem(WorkItem workItem) { // A work item cannot be null, since null is used in the WaitForWorkItem() method to indicate timeout or cancel if (workItem == null) { throw new ArgumentNullException("workItem"); } bool enqueue = true; // First check if there is a wait entry waiting for work item. During // the check, timed out waiters are ignored. If there is no waiter then the work item is queued. lock (this) { CheckDisposed(); if (!_isWorkItemsQueueActive) { return(false); } while (_waitersCount > 0) { // Dequeue a waiter. WaitEntry waitEntry = PopWaiter(); // Signal the waiter. On success break the loop if (waitEntry.Signal(workItem)) { enqueue = false; break; } } if (enqueue) { // Enqueue the work item _workItems.Enqueue(workItem); } } return(true); }
/// <summary> /// Pop a waiter from the waiter's stack /// </summary> /// <returns>Returns the first waiter in the stack</returns> private WaitEntry PopWaiter() { // Store the current stack head WaitEntry oldFirstWaiterEntry = _headWaitEntry._nextWaiterEntry; // Store the new stack head WaitEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; // Update the old stack head list links and decrement the number waiters. RemoveWaiter(oldFirstWaiterEntry, true); // Update the new stack head _headWaitEntry._nextWaiterEntry = newHeadWaiterEntry; if (null != newHeadWaiterEntry) { newHeadWaiterEntry._prevWaiterEntry = _headWaitEntry; } // Return the old stack head return(oldFirstWaiterEntry); }
/// <summary> /// Remove a waiter from the stack /// </summary> /// <param name="WaitEntry">A waiter entry to remove</param> /// <param name="popDecrement">If true the waiter count is always decremented</param> private void RemoveWaiter(WaitEntry WaitEntry, bool popDecrement) { // Store the prev entry in the list WaitEntry prevWaiterEntry = WaitEntry._prevWaiterEntry; // Store the next entry in the list WaitEntry nextWaiterEntry = WaitEntry._nextWaiterEntry; // A flag to indicate if we need to decrement the waiters count. // If we got here from PopWaiter then we must decrement. // If we got here from PushWaitEntry then we decrement only if // the waiter was already in the stack. bool decrementCounter = popDecrement; // Null the waiter's entry links WaitEntry._prevWaiterEntry = null; WaitEntry._nextWaiterEntry = null; // If the waiter entry had a prev link then update it. // It also means that the waiter is already in the list and we // need to decrement the waiters count. if (null != prevWaiterEntry) { prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; decrementCounter = true; } // If the waiter entry had a next link then update it. // It also means that the waiter is already in the list and we // need to decrement the waiters count. if (null != nextWaiterEntry) { nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; decrementCounter = true; } if (decrementCounter) { --_waitersCount; } }
private void RemoveWaiter(WaitEntry WaitEntry, bool popDecrement) { WorkItemsQueue.WaitEntry entry = WaitEntry._prevWaiterEntry; WorkItemsQueue.WaitEntry entry2 = WaitEntry._nextWaiterEntry; bool flag = popDecrement; WaitEntry._prevWaiterEntry = null; WaitEntry._nextWaiterEntry = null; if (null != entry) { entry._nextWaiterEntry = entry2; flag = true; } if (null != entry2) { entry2._prevWaiterEntry = entry; flag = true; } if (flag) { this._waitersCount--; } }
/// <summary> /// Cleanup the work items queue, hence no more work items are allowed to be queued. /// </summary> private void Cleanup() { lock (this) { // Deactivate only once if (!_isWorkItemsQueueActive) { return; } // Don't queue more work items _isWorkItemsQueueActive = false; foreach (WorkItem workItem in _workItems) { workItem.DisposeState(); } // Clear the work items that are already queued _workItems.Clear(); while (_waitersCount > 0) { WaitEntry WaitEntry = PopWaiter(); WaitEntry.Timeout(); } } }
/// <summary> /// Remove a waiter from the stack /// </summary> /// <param name="WaitEntry">A waiter entry to remove</param> /// <param name="popDecrement">If true the waiter count is always decremented</param> private void RemoveWaiter(WaitEntry WaitEntry, bool popDecrement) { // Store the prev entry in the list WaitEntry prevWaiterEntry = WaitEntry._prevWaiterEntry; // Store the next entry in the list WaitEntry nextWaiterEntry = WaitEntry._nextWaiterEntry; // A flag to indicate if we need to decrement the waiters count. // If we got here from PopWaiter then we must decrement. // If we got here from PushWaitEntry then we decrement only if // the waiter was already in the stack. bool decrementCounter = popDecrement; // Null the waiter's entry links WaitEntry._prevWaiterEntry = null; WaitEntry._nextWaiterEntry = null; // If the waiter entry had a prev link then update it. // It also means that the waiter is already in the list and we // need to decrement the waiters count. if (null != prevWaiterEntry) { prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; decrementCounter = true; } // If the waiter entry had a next link then update it. // It also means that the waiter is already in the list and we // need to decrement the waiters count. if (null != nextWaiterEntry) { nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; decrementCounter = true; } if (decrementCounter) --_waitersCount; }
/// <summary> /// Push a new waiter into the waiter's stack /// </summary> /// <param name="newWaiterEntry">A waiter to put in the stack</param> public void PushWaitEntry(WaitEntry newWaiterEntry) { // Remove the waiter if it is already in the stack and // update waiter's count as needed RemoveWaiter(newWaiterEntry, false); // If the stack is empty then newWaiterEntry is the new head of the stack if (null == _headWaitEntry._nextWaiterEntry) { _headWaitEntry._nextWaiterEntry = newWaiterEntry; newWaiterEntry._prevWaiterEntry = _headWaitEntry; } else { // If the stack is not empty then put newWaiterEntry as the new head of the stack. // Save the old first waiter entry WaitEntry oldFirstWaiterEntry = _headWaitEntry._nextWaiterEntry; // Update the links _headWaitEntry._nextWaiterEntry = newWaiterEntry; newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; newWaiterEntry._prevWaiterEntry = _headWaitEntry; oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; } // Increment the number of waiters ++_waitersCount; }
/// <summary> /// Returns the WaitEntry of the current thread /// </summary> /// <returns></returns> /// In order to avoid creation and destuction of WaitEntry /// objects each thread has its own WaitEntry object. private WaitEntry GetThreadWaitEntry() { if (null == _waitEntry) { _waitEntry = new WaitEntry(); } _waitEntry.Reset(); return _waitEntry; }
private bool WaitCore(int timeoutMs) { WaitEntry wait_entry = new WaitEntry(); bool mutexLocked = false; bool waitEntryLocked = false; try { Monitor.try_enter_with_atomic_var(mutex, Timeout.Infinite, false, ref mutexLocked); if (pending_signals > 0) { --pending_signals; return(true); } wait_entry.condition = new object(); wait_entry.previous = null; wait_entry.next = head; if (head != null) { Unsafe.AsRef <WaitEntry> (head).previous = Unsafe.AsPointer <WaitEntry> (ref wait_entry); } head = Unsafe.AsPointer <WaitEntry> (ref wait_entry); } finally { if (mutexLocked) { Monitor.Exit(mutex); } } try { Monitor.try_enter_with_atomic_var(wait_entry.condition, Timeout.Infinite, false, ref waitEntryLocked); if (!wait_entry.signaled) { Monitor.Monitor_wait(wait_entry.condition, timeoutMs, false); } } finally { if (waitEntryLocked) { Monitor.Exit(wait_entry.condition); } } mutexLocked = false; try { Monitor.try_enter_with_atomic_var(mutex, Timeout.Infinite, false, ref mutexLocked); if (!wait_entry.signaled) { if (head == Unsafe.AsPointer <WaitEntry> (ref wait_entry)) { head = wait_entry.next; } if (wait_entry.next != null) { Unsafe.AsRef <WaitEntry> (wait_entry.next).previous = wait_entry.previous; } if (wait_entry.previous != null) { Unsafe.AsRef <WaitEntry> (wait_entry.previous).next = wait_entry.next; } } } finally { if (mutexLocked) { Monitor.Exit(mutex); } } return(wait_entry.signaled); }