// // Executes the prologue of the TryTake operation. // internal override WaitNode TryTakePrologue(StParker pk, int key, out T di, ref WaitNode hint) { WaitNode wn = base.TryTakePrologue(pk, key, out di, ref hint); if (wn == null) { FreeSlot(); } return wn; }
public static void WaitNode() { var a = new WaitNode(); var b = SerializationUtil.Reserialize(a); Assert.AreEqual(a, b); }
// // Tries to take a data item from the queue, activating the // specified cancellers. // public bool TryTake(out T di, StCancelArgs cargs) { if (TryTake(out di)) { return(true); } if (cargs.Timeout == 0) { return(false); } StParker pk = new StParker(); WaitNode wn, hint = null; if ((wn = TryTakePrologue(pk, StParkStatus.Success, out di, ref hint)) == null) { return(true); } int ws = pk.Park(cargs); if (ws == StParkStatus.Success) { TakeEpilogue(); di = wn.channel; return(true); } // // The take was cancelled; so, cancel the take attempt and // report the failure appropriately. // CancelTakeAttempt(wn, hint); StCancelArgs.ThrowIfException(ws); return(false); }
/*++ * * Generic API * * --*/ // // Tries to add a data item to the queue, activating the specified // cancellers. // public bool TryAdd(T di, StCancelArgs cargs) { if (TryAdd(di)) { return(true); } if (cargs.Timeout == 0) { return(false); } WaitNode hint = null; WaitNode wn; StParker pk = new StParker(); if ((wn = TryAddPrologue(pk, StParkStatus.Success, di, ref hint)) == null) { return(true); } int ws = pk.Park(cargs); if (ws == StParkStatus.Success) { return(true); } // // The add operation was cancelled; so, cancel the add attempt // and report the failure appropriately. // CancelAddAttempt(wn, hint); StCancelArgs.ThrowIfException(ws); return(false); }
// // Tries to wakeup a waiting writer. // // NOTE: This method is called with the spinlock held // and when the r/w lock is in the NonEntered state. // If a waiter is woken, the method releases the spin lock // and returns true; otherwise, the method returns false and // with the spinlock held. // private bool TryWakeupWriter() { while (!wrQueue.IsEmpty) { WaitNode w = wrQueue.Dequeue(); if (w.TryLock()) { // // Become the waiter the next owner of the write lock, // release the spinlock, unpark the waiter and return true. // writer = w.tid; slock.Exit(); w.Unpark(StParkStatus.Success); return(true); } } // // No writer can be released; so, return false with the // spinlock held. // return(false); }
/** * Removes and signals all waiting threads, invokes done(), and * nulls out callable. */ private void finishCompletion() { // assert state > COMPLETING; for (WaitNode q; (q = waiters) != null;) { if (Interlocked.CompareExchange(ref waiters, null, q) == q) { for (;;) { Thread t = q.Thread; if (t != null) { q.Thread = null; } WaitNode next = q.Next; if (next == null) { break; } q.Next = null; // unlink to help gc q = next; } break; } } done(); callable = null; // to reduce footprint }
private void DoWait(Action <WaitNode> action) { int holdCount = Lock.HoldCount; if (holdCount == 0) { throw new SynchronizationLockException(); } WaitNode n = new WaitNode(); _wq.Enqueue(n); for (int i = holdCount; i > 0; i--) { Lock.Unlock(); } try { action(n); } finally { for (int i = holdCount; i > 0; i--) { Lock.Lock(); } } }
private static void ParseWait(Node root, TokenStream stream) { var node = new WaitNode(); root.AddChildNode(node); while (stream.GetCurrent().TokenType == SemanticTokenType.NodeParameter) { var parameter = stream.Pop(); if (parameter.TokenValue == "time:") { var value = stream.Pop(); if (value.TokenType == SemanticTokenType.DecimalLiteral16 || value.TokenType == SemanticTokenType.DecimalLiteral32 || value.TokenType == SemanticTokenType.DecimalLiteral8) { node.WaitTimeMilliseconds = Int32.Parse(value.TokenValue); } else { throw new Exception("Invalid token parameter value"); } } else { throw new Exception("Unknown parameter:" + parameter.TokenValue); } } }
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); }
/// <summary> /// Tries to unlink a timed-out or interrupted wait node to avoid /// accumulating garbage. Internal nodes are simply unspliced /// without CAS since it is harmless if they are traversed anyway /// by releasers. To avoid effects of unsplicing from already /// removed nodes, the list is retraversed in case of an apparent /// race. This is slow when there are a lot of nodes, but we don't /// expect lists to be long enough to outweigh higher-overhead /// schemes. /// </summary> private void RemoveWaiter(WaitNode node) { if (node != null) { node.Thread = null; for (;;) // restart on removeWaiter race { for (WaitNode pred = null, q = Waiters, s; q != null; q = s) { s = q.next; if (q.thread != null) { pred = q; } else if (pred != null) { pred.next = s; if (pred.thread == null) // check for race { goto retryContinue; } } else if (!UNSAFE.compareAndSwapObject(this, WaitersOffset, q, s)) { goto retryContinue; } } break; retryContinue :; } retryBreak :; } }
// // Exchanges a data item, activating the specified cancellers. // public bool Exchange(T myData, out T yourData, StCancelArgs cargs) { if (TryExchange(myData, out yourData)) { return(true); } var pk = new StParker(); var wn = new WaitNode(pk, myData); if (TryExchange(wn, myData, out yourData)) { return(true); } int ws = pk.Park(spinCount, cargs); if (ws == StParkStatus.Success) { yourData = wn.Channel; return(true); } CancelExchange(wn); StCancelArgs.ThrowIfException(ws); return(false); }
// // Enqueues the specified wait node. // internal override WaitNode Enqueue(WaitNode wn) { do { WaitNode t = tail; WaitNode tn = t.next; // // If the queue is in the intermediate state, try to advance // the its tail. // if (tn != null) { AdvanceTail(t, tn); continue; } // // Queue in quiescent state, so try to insert the new node. // if (t.CasNext(null, wn)) { // // Advance the tail and return the previous wait block. // AdvanceTail(t, wn); return(t); } } while (true); }
/// <summary> /// Removes and signals all waiting threads, invokes done(), and /// nulls out callable. /// </summary> private void FinishCompletion() { // assert state > COMPLETING; for (WaitNode q; (q = Waiters) != null;) { if (UNSAFE.compareAndSwapObject(this, WaitersOffset, q, null)) { for (;;) { Thread t = q.thread; if (t != null) { q.thread = null; LockSupport.Unpark(t); } WaitNode next = q.next; if (next == null) { break; } q.next = null; // unlink to help gc q = next; } break; } } Done(); Callable = null; // to reduce footprint }
/// <summary> /// 移除等待节点 /// </summary> /// <param name="node"></param> private void removeWaiter(WaitNode node) { if (node != null) { node.thread = null; retry: for (; ;) { // restart on removeWaiter race for (WaitNode pred = null, q = waiters, s; q != null; q = s) { s = q.next; if (q.thread != null) { pred = q; } else if (pred != null) { pred.next = s; if (pred.thread == null) // check for race { goto retry; } } if (!(Interlocked.CompareExchange <WaitNode>(ref waiters, s, q) == q)) { goto retry; } } break; } } }
protected override IEnumerator ExecuteStep() { WaitNode.UnwaitGroupId(GroupId); Router.FireEvent(EndEventName); yield return(null); }
public void TakeOver(WaitNode node) { lock (this) { Debug.Assert(_holds == 1 && _owner == Thread.CurrentThread); _owner = node.Owner; } }
internal Task <bool> ForceReplicationAsync(TimeSpan timeout, CancellationToken token) { var waiter = new WaitNode(); ImmutableInterlocked.Enqueue(ref replicationQueue, waiter); forcedReplication.Set(true); return(waiter.Task.WaitAsync(timeout, token)); }
// // Enqueues a wait node at the front of the queue. // internal void EnqueueHead(WaitNode wn) { if ((wn.next = head) == null) { tail = wn; } head = wn; }
static public void CreateWaitNodeOfMenu( ) { Transform parentNodeTra = (Selection.activeGameObject != null) ? Selection.activeGameObject.transform : null; WaitNode node = ViNoToolUtil.AddViNodeGameObject <WaitNode>("Wait", parentNodeTra); EditorGUIUtility.PingObject(node.gameObject); }
/// <summary> /// This method visits a wait node /// First assigns a string that prints delay, and then accepts the amount of time and the time modifier /// Then closes the parenthesis /// </summary> /// <param name="waitNode">The name of the node</param> /// <returns>It returns delay(Time amount and modifier)</returns> public override object Visit(WaitNode waitNode) { string delay = "delay("; delay += waitNode.TimeAmount.Accept(this); delay += waitNode.TimeModifier.Accept(this); delay += ");"; return(delay); }
// // Advances the queue's head. // private bool AdvanceHead(WaitNode h, WaitNode nh) { if (head == h && Interlocked.CompareExchange <WaitNode>(ref head, nh, h) == h) { h.next = h; // mark the previous head wait node as unlinked. return(true); } return(false); }
// // 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); }
/// <summary> /// This method prints the waitNode and make an indentation /// It accepts a visit of TimeAmount and Timemodifier /// Then outdent /// </summary> /// <param name="waitNode">The node to print.</param> /// <returns>Returns null</returns> public override object Visit(WaitNode waitNode) { Print("WaitNode"); Indent++; waitNode.TimeAmount.Accept(this); waitNode.TimeModifier.Accept(this); Indent--; return(null); }
// // Advances the queue's head. // private bool AdvanceHead(WaitNode h, WaitNode nh) { if (head == h && Interlocked.CompareExchange <WaitNode>(ref head, nh, h) == h) { h.next = h; // Forget next. return(true); } return(false); }
// // Cancels the specified take operation. // internal override void CancelTakeAttempt(WaitNode wn, WaitNode ignored) { if (wn.next != wn) { qlock.Enter(); waitQueue.Remove(wn); qlock.Exit(); } }
// // Unlinks the specified wait node from the stack. // internal override void Unlink(WaitNode wn, WaitNode ignored) { // // Absorb the cancelled wait nodes at the top of the stack. // WaitNode p; do { if ((p = top) == null) { return; } if (p.parker.IsLocked && Interlocked.CompareExchange <WaitNode>(ref top, p.next, p) == p) { // // If the wait block was at the top of the stack, return. // if (p == wn) { return; } } else { break; } } while (true); // // Compute a wait node that follows "wn" and try to unsplice // the wait node. // WaitNode past; if ((past = wn.next) != null && past.parker.IsLocked) { past = past.next; } while (p != null && p != past) { WaitNode n = p.next; if (n != null && n.parker.IsLocked) { p.CasNext(n, n.next); } else { p = n; } } }
internal override void Insert(WaitNode w) { int idx = (System.Int32)Thread.CurrentThread.Priority - (int)System.Threading.ThreadPriority.Lowest; cells_[idx].Insert(w); if (idx > maxIndex_) { maxIndex_ = idx; } }
// // Unparks all the wait nodes in the queue. // internal void UnparkAll() { WaitNode <Q> p = head; while (p != null) { p.Unpark(StParkStatus.Success); p = p.next; } }
public WorkQueueLocals(CustomWorkQueueBase <TWorkItem> workQueue) { _workQueue = workQueue; Random = new FastRandom(Thread.CurrentThread.ManagedThreadId); Queue = new WorkStealingQueue <TWorkItem>(); Semaphore = new SemaphoreSlim(0, 1); WaitNode = new WaitNode(Semaphore); WorkStealingQueueList.Add(ref _workQueue._localQueues, Queue); }
// // Dequeues a wait node from a non-empty queue. // internal WaitNode <Q> Dequeue() { WaitNode <Q> n = head; if ((head = n.next) == null) { tail = null; } n.next = n; // Mark the wait node as unlinked. return(n); }
internal override void Insert(WaitNode w) { int idx = (System.Int32) Thread.CurrentThread.Priority - (int) System.Threading.ThreadPriority.Lowest; cells_[idx].Insert(w); if (idx > maxIndex_) maxIndex_ = idx; }
/// <summary> /// assumed not to block /// </summary> internal abstract void Insert(WaitNode w);
internal override void Insert(WaitNode w) { if (tail_ == null) head_ = tail_ = w; else { tail_.next = w; tail_ = w; } }
internal override WaitNode Extract() { if (head_ == null) return null; else { WaitNode w = head_; head_ = w.next; if (head_ == null) tail_ = null; w.next = null; return w; } }
/// <summary> /// clone /// </summary> /// <returns></returns> public IBehaviourNode Clone() { var behaviourNode = new WaitNode(this.duration, this.variation); base.CopyTo(behaviourNode); return behaviourNode; }
// // Enqueues a wait node at the tail of the queue. // internal void Enqueue(WaitNode wn) { if (head == null) { head = wn; } else { tail.next = wn; } tail = wn; }
// // Removes the specified wait node from the queue. // internal void Remove(WaitNode wn) { // // If the wait node was already removed, return. // if (wn.next == wn) { return; } // // Compute the previous wait node and perform the remove. // WaitNode p = head; WaitNode pv = null; while (p != null) { if (p == wn) { if (pv == null) { if ((head = wn.next) == null) { tail = null; } } else { if ((pv.next = wn.next) == null) tail = pv; } return; } pv = p; p = p.next; } throw new InvalidOperationException("WaitOne node not found in the queue!"); }
// // Dequeues a wait node from a non-empty queue. // internal WaitNode Dequeue() { WaitNode wn; if ((head = (wn = head).next) == null) { tail = null; } wn.next = wn; // mark wait node as unlinked. return wn; }
/*++ * * The following methods are used when the queue is used as a * wake up list holding locked wait nodes. * --*/ // // Adds the wait node at the tail of the queue. // internal void AddToWakeList(WaitNode wn) { if (!wn.UnparkInProgress(StParkStatus.Success)) { if (head == null) { head = wn; } else { tail.next = wn; } wn.next = null; tail = wn; } }
// // Tries to enter the read lock, activating the // specified cancellers. // public bool TryEnterRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Read after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Recursive read not allowed"); } } else { // // If this is a recursive enter, increment the recursive // acquisition counter and return. // if (rc != null) { rc.count++; return true; } } // // Acquire the spinlock that protected the r/u/w lock shared state. // slock.Enter(); // // If the current thread is the upgrader, it can also enter // the read lock. So, add an entry to the readers table, // release the spinlock and return success. // if (tid == upgrader) { rdCounts.Add(tid); slock.Exit(); upgraderIsReader = true; return true; } // // The read lock can be entered, if the r/w lock isn't in write // mode and no thread is waiting to enter the writer mode. // If these conditions are met, increment the number of lock // readers, add an entry to the readers table, release the // spinlock and return success. // if (writer == UNOWNED && wrQueue.IsEmpty && upgToWrWaiter == null) { readers++; rdCounts.Add(tid); slock.Exit(); return true; } // // If the r/w lock is reentrant and the current thread is the // current writer, it can also to become a reader. So, increment // the number of lock readers, add an entry to the readers table, // release the spinlock and return success. // if (isReentrant && tid == writer) { readers++; rdCounts.Add(tid); slock.Exit(); return true; } // // The current thread can't enter the read lock immediately. // So, if a null timeout was specified, release the spinlock // and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the readers queue. // Compute also the amount of spinning. // int sc = rdQueue.IsEmpty ? spinCount : 0; WaitNode wn; rdQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread, activating // the specified cancellers and spinning if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we entered the read lock, return success. // if (ws == StParkStatus.Success) { return true; } // // The enter attempt was cancelled. So, ensure that the wait node // is unlinked from the queue and report the failure appropriately. // if (wn.next != wn) { slock.Enter(); rdQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return false; }
// // Exits the read lock. // public void ExitRead() { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (rc == null) { throw new StSynchronizationLockException("Mismatched read"); } // // If this is a recursive exit of the read lock, decrement // the recursive acquisition count and return. // if (--rc.count > 0) { return; } // // The read lock was exited by the current thread. So, if the current // thread is also the upgrader clear the *upgraderIsReader* flag // and return, because no other waiter thread can be released. // if (tid == upgrader) { upgraderIsReader = false; return; } // // Acquire the spinlock that protecteds the r/u/w lock shared state. // Then, decrement the number of active readers; if this is not the // unique lock reader, release the spin lock and return. // slock.Enter(); if (--readers > 0) { slock.Exit(); return; } // // Here, we know that the r/u/w lock doesn't have readers. // First, check the current upgarder is waiting to enter the write lock, // and, if so, try to release it. // WaitNode w; if ((w = upgToWrWaiter) != null) { upgToWrWaiter = null; if (w.TryLock()) { writer = w.tid; slock.Exit(); w.Unpark(StParkStatus.Success); return; } } // // If the r/w lock isn't in the upgrade read mode nor in write // mode, try to wake up a waiting writer; failing that, try to // wake up a waiting upgrader and/or all waiting readers. // if (!(upgrader == UNOWNED && writer == UNOWNED && (TryWakeupWriter() || TryWakeupUpgraderAndReaders()))) { slock.Exit(); } }
// // Tries to enter the lock in upgrade read mode, activating // the specified cancellers. // public bool TryEnterUpgradeableRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == upgrader) { throw new StLockRecursionException("Recursive upgrade not allowed"); } if (tid == writer) { throw new StLockRecursionException("Upgrade after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } else { // // If the current thread is the current upgrader, increment the // recursive acquisition counter and return. // if (tid == upgrader) { upCount++; return true; } // // If the current thread is the current writer, it can also // becomes the upgrader. If it is also a reader, it will be // accounted as reader on the *upgraderIsReader* flag. // if (tid == writer) { upgrader = tid; upCount = 1; if (rc != null) { upgraderIsReader = true; } return true; } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the lock isn't in write or upgrade read mode, the // current thread becomes the current upgrader. Then, release // the spinlock and return success. // if (writer == UNOWNED && upgrader == UNOWNED) { upgrader = tid; slock.Exit(); upgraderIsReader = false; upCount = 1; return true; } // // The upgrade read lock can't be acquired immediately. // So, if a null timeout was specified, return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the upgrader's queue. // int sc = (upQueue.IsEmpty && wrQueue.IsEmpty) ? spinCount : 0; WaitNode wn; upQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we acquired the upgrade lock, initialize the recursive // acquisition count and the *upgraderIsReader flag and return // success. // if (ws == StParkStatus.Success) { upCount = 1; upgraderIsReader = false; return true; } // // The acquire attemptwas cancelled. So, ensure that the // wait node is unlinked from the wait queue and report // the failure appropriately. // if (wn.next != wn) { slock.Enter(); upQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return false; }
// // Tries to enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Recursive enter write not allowed"); } if (rdCounts.Lookup(tid) != null) { throw new StLockRecursionException("Write after read not allowed"); } } else { // // If this is a recursive enter, increment the recursive acquisition // counter and return success. // if (tid == writer) { wrCount++; return true; } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the write lock can be entered - this is, there are no lock // readers, no lock writer or upgrader or the current thread is the // upgrader -, enter the write lock, release the spinlock and // return success. // if (readers == 0 && writer == UNOWNED && (upgrader == tid || upgrader == UNOWNED)) { writer = tid; slock.Exit(); wrCount = 1; return true; } // // If the current thread isn't the current upgrader but is reader, // release the spinlock and throw the appropriate exception. // if (tid != upgrader && rdCounts.Lookup(tid) != null) { slock.Exit(); throw new StLockRecursionException("Write after read not allowed"); } // // The write lock can't be entered immediately. So, if a null timeout // was specified, release the spinlock and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the writers queue. // If the current thread isn't the current upgrader, the wait // node is inserted in the writer's queue; otherwise, the wait // node becomes referenced by the *upgradeToWriteWaiter* field. // int sc; WaitNode wn = new WaitNode(tid); if (tid == upgrader) { upgToWrWaiter = wn; sc = spinCount; } else { sc = wrQueue.IsEmpty ? spinCount : 0; wrQueue.Enqueue(wn); } // // Release spin the lock and park the current thread, activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If the thread entered the write lock, initialize the recursive // acquisition counter and return success. // if (ws == StParkStatus.Success) { wrCount = 1; return true; } // // The enter attempted was cancelled. So, if the wait node was // already remove from the respective queue, report the failure // appropriately. Otherwise, unlink the wait node and, if appropriate, // taking into account the other waiters. // if (wn.next == wn) { goto ReportFailure; } slock.Enter(); if (wn.next != wn) { if (wn == upgToWrWaiter) { upgToWrWaiter = null; } else { wrQueue.Remove(wn); // // If the writers queue becomes empty, it is possible that there // is a waiting upgrader or waiting reader threads that can now // proceed. // if (writer == UNOWNED && upgrader == UNOWNED && wrQueue.IsEmpty && TryWakeupUpgraderAndReaders()) { goto ReportFailure; } } } slock.Exit(); ReportFailure: StCancelArgs.ThrowIfException(ws); return false; }