internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) { var localQueue = Current; if (TryTake(out di, localQueue)) { if (pk.TryLock()) { pk.UnparkSelf(key); } else { localQueue.TryAdd(di); } return(null); } var wn = new WaitNode(pk, key); waitQueue.Enqueue(wn); if (!pk.IsLocked && TryTake(out di, localQueue)) { if (pk.TryLock()) { waitQueue.Unlink(wn, hint); pk.UnparkSelf(key); return(null); } localQueue.TryAdd(di); } return(wn); }
// // Executes the prologue of the TryAdd operation. // internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode ignored) { if (pk.TryLock()) { pk.UnparkSelf(key); } AddWorker(di); return(null); }
// // Executes the prologue of the TryAdd operation. // internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode hint) { if (TryReserveSlot()) { if (pk.TryLock()) { AddWorker(di); pk.UnparkSelf(key); } else { FreeSlot(); } return null; } // // ... // WaitNode wn; hint = waitQueue.Enqueue(wn = new WaitNode(pk, key, di)); // // As a slot could have been free after the check done // above, but before we insert the wait block in the wait queue, // we must retry to reserve a free slot. // if (TryReserveSlot()) { if (pk.TryLock()) { AddWorker(di); pk.UnparkSelf(key); } else { waitQueue.Unlink(wn, hint); FreeSlot(); } return null; } return wn; }
internal static bool WaitAllInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } int nevts; int len = ws.Length; StWaitable[] sws = new StWaitable[len]; WaitHandle[] shs = null; int waitHint = SortAndCheckAllowAcquire(ws, sws, out nevts); if (waitHint < 0) { throw new ArgumentException("There are duplicate waitables", "ws"); } if (hs != null) { shs = Sort(hs); if (shs == null) { throw new ArgumentException("There are duplicate wait handles", "hs"); } } if (waitHint != 0 && shs != null && !WaitHandle.WaitAll(shs, 0)) { waitHint = 0; } // // Return success if all synchronizers are notification events and are set. // if (waitHint != 0 && nevts == 0) { return(true); } if (waitHint == 0 && cargs.Timeout == 0) { return(false); } // // If a timeout was specified, get the current time in order // to adjust the timeout value later, if we re-wait. // int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; WaitBlock[] wbs = null; WaitBlock[] hints = null; do { if (waitHint == 0) { // // Create the wait block arrays if this is the first time // that we execute the acquire-all prologue. // if (wbs == null) { wbs = new WaitBlock[len]; hints = new WaitBlock[len]; } // // Create a parker for cooperative release, specifying as many // releasers as the number of waitables. The parker because is // not reused because other threads may have references to it. // StParker pk = shs != null ? new StParker(len, EventBasedParkSpotFactory.Current. Create(new WaitAllBehavior(shs))) : new StParker(len); int gsc = 1; int sc = 0; for (int i = 0; i < len; i++) { if ((wbs[i] = sws[i]._WaitAllPrologue(pk, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(StParkStatus.StateChange); } } else if (gsc != 0) { if (sc == 0) { gsc = 0; } else if (sc > gsc) { gsc = sc; } } } int wst = pk.Park(gsc, cargs); // // If the wait was cancelled due to timeout, alert or interrupt, // cancel the acquire attempt on all waitables where we actually // inserted wait blocks. // if (wst != StParkStatus.StateChange) { for (int i = 0; i < len; i++) { WaitBlock wb = wbs[i]; if (wb != null) { sws[i]._CancelAcquire(wb, hints[i]); } } StCancelArgs.ThrowIfException(wst); return(false); } } // // All waitables where we inserted wait blocks seem to allow // an immediate acquire operation; so, try to acquire all of // them that are not notification events. // int idx; for (idx = 0; idx < nevts; idx++) { if (!sws[idx]._TryAcquire()) { break; } } // // If all synchronizers were acquired, return success. // if (idx == nevts) { return(true); } // // We failed to acquire all waitables, so undo the acquires // that we did above. // while (--idx >= 0) { sws[idx]._UndoAcquire(); } if (shs != null) { for (int i = 0; i < shs.Length; i++) { shs[i].UndoAcquire(); } } // // If a timeout was specified, adjust the timeout value // that will be used on the next wait. // if (!cargs.AdjustTimeout(ref lastTime)) { return(false); } waitHint = 0; } while (true); }
internal static int WaitAnyInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { int len = ws.Length; // // First, we scan the *ws* array trying to acquire one of the // synchronizers. // for (int i = 0; i < len; i++) { if (ws[i]._TryAcquire()) { return(StParkStatus.Success + i); } } if (cargs.Timeout == 0) { return(StParkStatus.Timeout); } // // Create a parker and execute the WaitAny prologue on all // waitables. We stop executing prologues as soon as we detect // that the acquire operation was accomplished. // StParker pk = hs != null ? new StParker(EventBasedParkSpotFactory.Current. Create(new WaitAnyBehavior(hs, len))) : new StParker(1); WaitBlock[] wbs = new WaitBlock[len]; WaitBlock[] hints = new WaitBlock[len]; int lv = -1; int sc = 0; int gsc = 0; for (int i = 0; !pk.IsLocked && i < len; i++) { StWaitable w = ws[i]; if ((wbs[i] = w._WaitAnyPrologue(pk, i, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(i); } else { w._UndoAcquire(); } break; } // // Adjust the global spin count. // if (gsc < sc) { gsc = sc; } lv = i; } int wst = pk.Park(gsc, cargs); StWaitable acq = wst >= StParkStatus.Success && wst < len ? ws[wst] : null; // // Cancel the acquire attempt on all waitables where we executed // the WaitAny prologue, except the one we acquired. // for (int i = 0; i <= lv; i++) { StWaitable w = ws[i]; if (w != acq) { w._CancelAcquire(wbs[i], hints[i]); } } if (wst >= StParkStatus.Success && wst < len + (hs != null ? hs.Length : 0)) { if (acq != null) { acq._WaitEpilogue(); } return(wst); } StCancelArgs.ThrowIfException(wst); return(StParkStatus.Timeout); }
// // Executes the prologue of the BlockingQueue<T>.TryTake method. // internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode ignored) { // // Acquire the queue's lock and check if the queue's is empty. // qlock.Enter(); if (count != 0) { // // The queue isn't empty; so, ... // if (!pk.TryLock()) { qlock.Exit(); di = default(T); return(null); } pk.UnparkSelf(key); // // Retrieve a data item from the queue. // di = items[head]; if (++head == length) { head = 0; } count--; // // If the wait queue isn't empty, try to use the freed // slot to release one of the waiter threads. // if (!waitQueue.IsEmpty) { do { WaitNode w = waitQueue.Dequeue(); StParker pk2 = w.parker; if (pk2.TryLock()) { items[tail] = w.channel; if (++tail == length) { tail = 0; } count++; qlock.Exit(); pk2.Unpark(w.waitKey); return(null); } } while (!waitQueue.IsEmpty); } // // Release the queue's lock and return null to signal that the // take operation was accomplished. // qlock.Exit(); return(null); } // // The queue's buffer is empty; so, create ... // WaitNode wn = new WaitNode(pk, key); if (lifoQueue) { waitQueue.EnqueueHead(wn); } else { waitQueue.Enqueue(wn); } // // Release the queue's lock and return the wait node // inserted in the wait queue. // qlock.Exit(); di = default(T); return(wn); }
// // Executes the prologue of the BlockingQueue<T>.TryAddXxx method. // internal override WaitNode TryAddPrologue(StParker pk, int key, T di, ref WaitNode ignored) { // // Acquire the queue's lock. // qlock.Enter(); // // ... // if (count < length) { if (!pk.TryLock()) { qlock.Exit(); return(null); } pk.UnparkSelf(key); // // If the wait queue isn't empty, try to deliver the data item // directly to a waiting thread. // if (!waitQueue.IsEmpty) { do { WaitNode w = waitQueue.Dequeue(); StParker wpk = w.parker; if (wpk.TryLock()) { // // Release the queue's lock, pass the data item through // the wait node, unpark the waiter thread and return // success. // qlock.Exit(); w.channel = di; wpk.Unpark(w.waitKey); return(null); } } while (!waitQueue.IsEmpty); } // // Add the data item to the non-full queue and return null. // items[tail] = di; if (++tail == length) { tail = 0; } count++; qlock.Exit(); return(null); } // // The queue's buffer is full, so, ... // WaitNode wn; waitQueue.Enqueue(wn = new WaitNode(pk, key, di)); // // Release the queue's lock and return the inserted wait block. // qlock.Exit(); return(wn); }
public void Wait(StParker pk, StCancelArgs cargs) { bool interrupted = false; int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; int ws; do { try { ws = waitBehavior.Park(psevent, cargs.Timeout); break; } catch (ThreadInterruptedException) { if (cargs.Interruptible) { ws = StParkStatus.Interrupted; break; } interrupted = true; cargs.AdjustTimeout(ref lastTime); } } while (true); // // If the wait was cancelled due to an internal canceller, try // to cancel the park operation. If we fail, wait unconditionally // until the park spot is signalled. // if (ws != StParkStatus.Success) { if (pk.TryCancel()) { pk.UnparkSelf(waitBehavior.ParkerCancelled(ws)); } else { if (ws == StParkStatus.Interrupted) { interrupted = true; } waitBehavior.ParkerNotCancelled(ws); do { try { psevent.WaitOne(); break; } catch (ThreadInterruptedException) { interrupted = true; } } while (true); } } // // If we were interrupted but can't return the *interrupted* // wait status, reassert the interrupt on the current thread. // if (interrupted) { Thread.CurrentThread.Interrupt(); } factory.Free(this); }
// // Only one thread act as a releaser at any given time. // private void ReleaseWaitersAndUnlockQueue(WaitBlock self) { do { WaitBlock qh = queue.head; WaitBlock w; while (state > 0 && (w = qh.next) != null) { StParker pk = w.parker; if (w.waitType == WaitType.WaitAny) { if (!TryAcquireInternalQueued(w.request)) { break; } if (pk.TryLock()) { if (w == self) { pk.UnparkSelf(w.waitKey); } else { pk.Unpark(w.waitKey); } } else { UndoAcquire(w.request); } } else if (pk.TryLock()) { if (w == self) { pk.UnparkSelf(w.waitKey); } else { pk.Unpark(w.waitKey); } } // // Remove the wait block from the semaphore's queue, // marking the previous head as unlinked, and advance // the local queues's head. // qh.next = qh; qh = w; } // // It seems that no more waiters can be released; so, // set the new semaphore queue's head and unlock it. // queue.SetHeadAndUnlock(qh); // // If after the semaphore's queue is unlocked, it seems that // more waiters can be released, repeat the release processing. // if (!IsReleasePending) { return; } } while (true); }
// // Executes the prologue of the TryTake operation. // internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) { if (dataQueue.TryDequeue(out di)) { if (pk.TryLock()) { pk.UnparkSelf(key); } else { // // ... // AddWorker(di); } return(null); } // // There are no data items available on the queue, ... // WaitNode wn = new WaitNode(pk, key); hint = waitQueue.Enqueue(wn); // // Since that a data item could have arrived after we check // the data queue but before we inserted our wait block in // the wait queue, we must retry to dequeue a data item from // the data queue if the parker is still unlocked. // if (!pk.IsLocked && dataQueue.TryDequeue(out di)) { // // We got a data item, so try to lock the parker and, if succeed, // unlink our wait node from the wait queue and self unpark the // current thread. // if (pk.TryLock()) { waitQueue.Unlink(wn, hint); pk.UnparkSelf(key); return(null); } // // If the parker is locked, someone else will give as a data // item. So, return the data item retrieved from the data queue, // undoing the previous take. // AddWorker(di); } // // Return the wait node inserted in the wait queue. // return(wn); }