/// <summary> /// Awaits completion or aborts on interrupt or timeout. /// </summary> /// <param name="timed"> true if use timed waits </param> /// <param name="nanos"> time to wait, if timed </param> /// <returns> state upon completion </returns> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: private int awaitDone(boolean timed, long nanos) throws InterruptedException private int AwaitDone(bool timed, long nanos) { //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final long deadline = timed ? System.nanoTime() + nanos : 0L; long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; bool queued = false; for (;;) { if (Thread.Interrupted()) { RemoveWaiter(q); throw new InterruptedException(); } int s = State; if (s > COMPLETING) { if (q != null) { q.Thread = null; } return(s); } else if (s == COMPLETING) // cannot time out yet { Thread.@yield(); } else if (q == null) { q = new WaitNode(); } else if (!queued) { queued = UNSAFE.compareAndSwapObject(this, WaitersOffset, q.Next = Waiters, q); } else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { RemoveWaiter(q); return(State); } LockSupport.ParkNanos(this, nanos); } else { LockSupport.Park(this); } } }
/// <summary> /// Ensures that any interrupt from a possible cancel(true) is only /// delivered to a task while in run or runAndReset. /// </summary> private void HandlePossibleCancellationInterrupt(int s) { // It is possible for our interrupter to stall before getting a // chance to interrupt us. Let's spin-wait patiently. if (s == INTERRUPTING) { while (State == INTERRUPTING) { Thread.@yield(); // wait out pending interrupt } } // assert state == INTERRUPTED; // We want to clear any interrupt we may have received from // cancel(true). However, it is permissible to use interrupts // as an independent mechanism for a task to communicate with // its caller, and there is no way to clear only the // cancellation interrupt. // // Thread.interrupted(); }
/// <summary> /// Exchange function used until arenas enabled. See above for explanation. /// </summary> /// <param name="item"> the item to exchange </param> /// <param name="timed"> true if the wait is timed </param> /// <param name="ns"> if timed, the maximum wait time, else 0L </param> /// <returns> the other thread's item; or null if either the arena /// was enabled or the thread was interrupted before completion; or /// TIMED_OUT if timed and timed out </returns> private Object SlotExchange(Object item, bool timed, long ns) { Node p = Participant.Get(); Thread t = Thread.CurrentThread; if (t.Interrupted) // preserve interrupt status so caller can recheck { return(null); } for (Node q;;) { if ((q = Slot) != null) { if (U.compareAndSwapObject(this, SLOT,q,null)) { Object v = q.item; q.match = item; Thread w = q.parked; if (w != null) { U.unpark(w); } return(v); } // create arena on contention, but continue until slot null if (NCPU > 1 && Bound == 0 && U.compareAndSwapInt(this,BOUND,0,SEQ)) { Arena = new Node[(FULL + 2) << ASHIFT]; } } else if (Arena != null) { return(null); // caller must reroute to arenaExchange } else { p.Item = item; if (U.compareAndSwapObject(this,SLOT,null,p)) { break; } p.Item = null; } } // await release int h = p.Hash; long end = timed ? System.nanoTime() + ns : 0L; int spins = (NCPU > 1) ? SPINS : 1; Object v; while ((v = p.Match) == null) { if (spins > 0) { h ^= h << 1; h ^= (int)((uint)h >> 3); h ^= h << 10; if (h == 0) { h = SPINS | (int)t.Id; } else if (h < 0 && (--spins & (((int)((uint)SPINS >> 1)) - 1)) == 0) { Thread.@yield(); } } else if (Slot != p) { spins = SPINS; } else if (!t.Interrupted && Arena == null && (!timed || (ns = end - System.nanoTime()) > 0L)) { U.putObject(t,BLOCKER,this); p.Parked = t; if (Slot == p) { U.park(false,ns); } p.Parked = null; U.putObject(t,BLOCKER,null); } else if (U.compareAndSwapObject(this,SLOT,p,null)) { v = timed && ns <= 0L && !t.Interrupted ? TIMED_OUT : null; break; } } U.putOrderedObject(p,MATCH,null); p.Item = null; p.Hash = h; return(v); }
/// <summary> /// Exchange function when arenas enabled. See above for explanation. /// </summary> /// <param name="item"> the (non-null) item to exchange </param> /// <param name="timed"> true if the wait is timed </param> /// <param name="ns"> if timed, the maximum wait time, else 0L </param> /// <returns> the other thread's item; or null if interrupted; or /// TIMED_OUT if timed and timed out </returns> private Object ArenaExchange(Object item, bool timed, long ns) { Node[] a = Arena; Node p = Participant.Get(); for (int i = p.Index;;) // access slot at i { int b, m, c; // j is raw array offset long j; Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE); if (q != null && U.compareAndSwapObject(a, j, q, null)) { Object v = q.Item; // release q.Match = item; Thread w = q.Parked; if (w != null) { U.unpark(w); } return(v); } else if (i <= (m = (b = Bound) & MMASK) && q == null) { p.Item = item; // offer if (U.compareAndSwapObject(a, j, null, p)) { long end = (timed && m == 0) ? System.nanoTime() + ns : 0L; Thread t = Thread.CurrentThread; // wait for (int h = p.Hash, spins = SPINS;;) { Object v = p.Match; if (v != null) { U.putOrderedObject(p, MATCH, null); p.Item = null; // clear for next use p.Hash = h; return(v); } else if (spins > 0) { h ^= h << 1; // xorshift h ^= (int)((uint)h >> 3); h ^= h << 10; if (h == 0) // initialize hash { h = SPINS | (int)t.Id; } else if (h < 0 && (--spins & (((int)((uint)SPINS >> 1)) - 1)) == 0) // approx 50% true { Thread.@yield(); // two yields per wait } } else if (U.getObjectVolatile(a, j) != p) { spins = SPINS; // releaser hasn't set match yet } else if (!t.Interrupted && m == 0 && (!timed || (ns = end - System.nanoTime()) > 0L)) { U.putObject(t, BLOCKER, this); // emulate LockSupport p.Parked = t; // minimize window if (U.getObjectVolatile(a, j) == p) { U.park(false, ns); } p.Parked = null; U.putObject(t, BLOCKER, null); } else if (U.getObjectVolatile(a, j) == p && U.compareAndSwapObject(a, j, p, null)) { if (m != 0) // try to shrink { U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1); } p.Item = null; p.Hash = h; i = p.Index = (int)((uint)p.Index >> 1); // descend if (Thread.Interrupted()) { return(null); } if (timed && m == 0 && ns <= 0L) { return(TIMED_OUT); } break; // expired; restart } } } else { p.Item = null; // clear offer } } else { if (p.Bound != b) // stale; reset { p.Bound = b; p.Collides = 0; i = (i != m || m == 0) ? m : m - 1; } else if ((c = p.Collides) < m || m == FULL || !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) { p.Collides = c + 1; i = (i == 0) ? m : i - 1; // cyclically traverse } else { i = m + 1; // grow } p.Index = i; } } }