1678 |
|
implements ForkJoinPool.ManagedBlocker { |
1679 |
|
long nanos; // remaining wait time if timed |
1680 |
|
final long deadline; // non-zero if timed |
1681 |
< |
volatile int interruptControl; // > 0: interruptible, < 0: interrupted |
1681 |
> |
final boolean interruptible; |
1682 |
> |
boolean interrupted; |
1683 |
|
volatile Thread thread; |
1684 |
|
|
1685 |
|
Signaller(boolean interruptible, long nanos, long deadline) { |
1686 |
|
this.thread = Thread.currentThread(); |
1687 |
< |
this.interruptControl = interruptible ? 1 : 0; |
1687 |
> |
this.interruptible = interruptible; |
1688 |
|
this.nanos = nanos; |
1689 |
|
this.deadline = deadline; |
1690 |
|
} |
1697 |
|
return null; |
1698 |
|
} |
1699 |
|
public boolean isReleasable() { |
1700 |
< |
if (thread == null) |
1701 |
< |
return true; |
1702 |
< |
if (Thread.interrupted()) { |
1703 |
< |
int i = interruptControl; |
1704 |
< |
interruptControl = -1; |
1705 |
< |
if (i > 0) |
1706 |
< |
return true; |
1706 |
< |
} |
1707 |
< |
if (deadline != 0L && |
1708 |
< |
(nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) { |
1709 |
< |
thread = null; |
1710 |
< |
return true; |
1711 |
< |
} |
1712 |
< |
return false; |
1700 |
> |
if (Thread.interrupted()) |
1701 |
> |
interrupted = true; |
1702 |
> |
return ((interrupted && interruptible) || |
1703 |
> |
(deadline != 0L && |
1704 |
> |
(nanos <= 0L || |
1705 |
> |
(nanos = deadline - System.nanoTime()) <= 0L)) || |
1706 |
> |
thread == null); |
1707 |
|
} |
1708 |
|
public boolean block() { |
1709 |
< |
if (isReleasable()) |
1710 |
< |
return true; |
1711 |
< |
else if (deadline == 0L) |
1712 |
< |
LockSupport.park(this); |
1713 |
< |
else if (nanos > 0L) |
1714 |
< |
LockSupport.parkNanos(this, nanos); |
1715 |
< |
return isReleasable(); |
1709 |
> |
while (!isReleasable()) { |
1710 |
> |
if (deadline == 0L) |
1711 |
> |
LockSupport.park(this); |
1712 |
> |
else |
1713 |
> |
LockSupport.parkNanos(this, nanos); |
1714 |
> |
} |
1715 |
> |
return true; |
1716 |
|
} |
1717 |
|
final boolean isLive() { return thread != null; } |
1718 |
|
} |
1738 |
|
q = new Signaller(interruptible, 0L, 0L); |
1739 |
|
else if (!queued) |
1740 |
|
queued = tryPushStack(q); |
1741 |
< |
else if (interruptible && q.interruptControl < 0) { |
1748 |
< |
q.thread = null; |
1749 |
< |
cleanStack(); |
1750 |
< |
return null; |
1751 |
< |
} |
1752 |
< |
else if (q.thread != null && result == null) { |
1741 |
> |
else { |
1742 |
|
try { |
1743 |
|
ForkJoinPool.managedBlock(q); |
1744 |
|
} catch (InterruptedException ie) { |
1745 |
< |
q.interruptControl = -1; |
1745 |
> |
q.interrupted = true; |
1746 |
|
} |
1747 |
+ |
if (q.interrupted && interruptible) |
1748 |
+ |
break; |
1749 |
|
} |
1750 |
|
} |
1751 |
|
if (q != null) { |
1752 |
|
q.thread = null; |
1753 |
< |
if (q.interruptControl < 0) { |
1753 |
> |
if (q.interrupted) { |
1754 |
|
if (interruptible) |
1755 |
< |
r = null; // report interruption |
1755 |
> |
cleanStack(); |
1756 |
|
else |
1757 |
|
Thread.currentThread().interrupt(); |
1758 |
|
} |
1759 |
|
} |
1760 |
< |
postComplete(); |
1760 |
> |
if (r != null) |
1761 |
> |
postComplete(); |
1762 |
|
return r; |
1763 |
|
} |
1764 |
|
|
1769 |
|
private Object timedGet(long nanos) throws TimeoutException { |
1770 |
|
if (Thread.interrupted()) |
1771 |
|
return null; |
1772 |
< |
if (nanos <= 0L) |
1773 |
< |
throw new TimeoutException(); |
1774 |
< |
long d = System.nanoTime() + nanos; |
1775 |
< |
Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0 |
1776 |
< |
boolean queued = false; |
1777 |
< |
Object r; |
1778 |
< |
// We intentionally don't spin here (as waitingGet does) because |
1779 |
< |
// the call to nanoTime() above acts much like a spin. |
1780 |
< |
while ((r = result) == null) { |
1781 |
< |
if (!queued) |
1782 |
< |
queued = tryPushStack(q); |
1783 |
< |
else if (q.interruptControl < 0 || q.nanos <= 0L) { |
1784 |
< |
q.thread = null; |
1785 |
< |
cleanStack(); |
1786 |
< |
if (q.interruptControl < 0) |
1787 |
< |
return null; |
1788 |
< |
throw new TimeoutException(); |
1789 |
< |
} |
1790 |
< |
else if (q.thread != null && result == null) { |
1791 |
< |
try { |
1792 |
< |
ForkJoinPool.managedBlock(q); |
1801 |
< |
} catch (InterruptedException ie) { |
1802 |
< |
q.interruptControl = -1; |
1772 |
> |
if (nanos > 0L) { |
1773 |
> |
long d = System.nanoTime() + nanos; |
1774 |
> |
long deadline = (d == 0L) ? 1L : d; // avoid 0 |
1775 |
> |
Signaller q = null; |
1776 |
> |
boolean queued = false; |
1777 |
> |
Object r; |
1778 |
> |
while ((r = result) == null) { // similar to untimed, without spins |
1779 |
> |
if (q == null) |
1780 |
> |
q = new Signaller(true, nanos, deadline); |
1781 |
> |
else if (!queued) |
1782 |
> |
queued = tryPushStack(q); |
1783 |
> |
else if (q.nanos <= 0) |
1784 |
> |
break; |
1785 |
> |
else { |
1786 |
> |
try { |
1787 |
> |
ForkJoinPool.managedBlock(q); |
1788 |
> |
} catch (InterruptedException ie) { |
1789 |
> |
q.interrupted = true; |
1790 |
> |
} |
1791 |
> |
if (q.interrupted) |
1792 |
> |
break; |
1793 |
|
} |
1794 |
|
} |
1795 |
+ |
if (q != null) |
1796 |
+ |
q.thread = null; |
1797 |
+ |
if (r != null) |
1798 |
+ |
postComplete(); |
1799 |
+ |
else |
1800 |
+ |
cleanStack(); |
1801 |
+ |
if (r != null || (q != null && q.interrupted)) |
1802 |
+ |
return r; |
1803 |
|
} |
1804 |
< |
if (q.interruptControl < 0) |
1807 |
< |
r = null; |
1808 |
< |
q.thread = null; |
1809 |
< |
postComplete(); |
1810 |
< |
return r; |
1804 |
> |
throw new TimeoutException(); |
1805 |
|
} |
1806 |
|
|
1807 |
|
/* ------------- public methods -------------- */ |