413 |
|
* unblocked threads to the point that we know they are available) |
414 |
|
* leading to more situations requiring more threads, and so |
415 |
|
* on. This aspect of control can be seen as an (analytically |
416 |
< |
* intractible) game with an opponent that may choose the worst |
416 |
> |
* intractable) game with an opponent that may choose the worst |
417 |
|
* (for us) active thread to stall at any time. We take several |
418 |
|
* precautions to bound losses (and thus bound gains), mainly in |
419 |
|
* methods tryCompensate and awaitJoin: (1) We only try |
629 |
|
final ForkJoinPool pool; // the containing pool (may be null) |
630 |
|
final ForkJoinWorkerThread owner; // owning thread or null if shared |
631 |
|
volatile Thread parker; // == owner during call to park; else null |
632 |
< |
ForkJoinTask<?> currentJoin; // task being joined in awaitJoin |
632 |
> |
volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin |
633 |
|
ForkJoinTask<?> currentSteal; // current non-local task being executed |
634 |
|
// Heuristic padding to ameliorate unfortunate memory placements |
635 |
|
Object p00, p01, p02, p03, p04, p05, p06, p07; |
721 |
|
* version of this method because it is never needed.) |
722 |
|
*/ |
723 |
|
final ForkJoinTask<?> pop() { |
724 |
< |
ForkJoinTask<?> t; int m; |
725 |
< |
ForkJoinTask<?>[] a = array; |
726 |
< |
if (a != null && (m = a.length - 1) >= 0) { |
724 |
> |
ForkJoinTask<?>[] a; ForkJoinTask<?> t; int m; |
725 |
> |
if ((a = array) != null && (m = a.length - 1) >= 0) { |
726 |
|
for (int s; (s = top - 1) - base >= 0;) { |
727 |
< |
int j = ((m & s) << ASHIFT) + ABASE; |
728 |
< |
if ((t = (ForkJoinTask<?>)U.getObjectVolatile(a, j)) == null) |
727 |
> |
long j = ((m & s) << ASHIFT) + ABASE; |
728 |
> |
if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null) |
729 |
|
break; |
730 |
|
if (U.compareAndSwapObject(a, j, t, null)) { |
731 |
|
top = s; |
829 |
|
} |
830 |
|
|
831 |
|
/** |
833 |
– |
* If present, removes from queue and executes the given task, or |
834 |
– |
* any other cancelled task. Returns (true) immediately on any CAS |
835 |
– |
* or consistency check failure so caller can retry. |
836 |
– |
* |
837 |
– |
* @return false if no progress can be made |
838 |
– |
*/ |
839 |
– |
final boolean tryRemoveAndExec(ForkJoinTask<?> task) { |
840 |
– |
boolean removed = false, empty = true, progress = true; |
841 |
– |
ForkJoinTask<?>[] a; int m, s, b, n; |
842 |
– |
if ((a = array) != null && (m = a.length - 1) >= 0 && |
843 |
– |
(n = (s = top) - (b = base)) > 0) { |
844 |
– |
for (ForkJoinTask<?> t;;) { // traverse from s to b |
845 |
– |
int j = ((--s & m) << ASHIFT) + ABASE; |
846 |
– |
t = (ForkJoinTask<?>)U.getObjectVolatile(a, j); |
847 |
– |
if (t == null) // inconsistent length |
848 |
– |
break; |
849 |
– |
else if (t == task) { |
850 |
– |
if (s + 1 == top) { // pop |
851 |
– |
if (!U.compareAndSwapObject(a, j, task, null)) |
852 |
– |
break; |
853 |
– |
top = s; |
854 |
– |
removed = true; |
855 |
– |
} |
856 |
– |
else if (base == b) // replace with proxy |
857 |
– |
removed = U.compareAndSwapObject(a, j, task, |
858 |
– |
new EmptyTask()); |
859 |
– |
break; |
860 |
– |
} |
861 |
– |
else if (t.status >= 0) |
862 |
– |
empty = false; |
863 |
– |
else if (s + 1 == top) { // pop and throw away |
864 |
– |
if (U.compareAndSwapObject(a, j, t, null)) |
865 |
– |
top = s; |
866 |
– |
break; |
867 |
– |
} |
868 |
– |
if (--n == 0) { |
869 |
– |
if (!empty && base == b) |
870 |
– |
progress = false; |
871 |
– |
break; |
872 |
– |
} |
873 |
– |
} |
874 |
– |
} |
875 |
– |
if (removed) |
876 |
– |
task.doExec(); |
877 |
– |
return progress; |
878 |
– |
} |
879 |
– |
|
880 |
– |
/** |
832 |
|
* Initializes or doubles the capacity of array. Call either |
833 |
|
* by owner or with lock held -- it is OK for base, but not |
834 |
|
* top, to move while resizings are in progress. |
890 |
|
// Execution methods |
891 |
|
|
892 |
|
/** |
893 |
< |
* Removes and runs tasks until empty, using local mode |
894 |
< |
* ordering. Normally called only after checking for apparent |
895 |
< |
* non-emptiness. |
896 |
< |
*/ |
897 |
< |
final void runLocalTasks() { |
898 |
< |
// hoist checks from repeated pop/poll |
899 |
< |
ForkJoinTask<?>[] a; int m; |
900 |
< |
if ((a = array) != null && (m = a.length - 1) >= 0) { |
901 |
< |
if (mode == 0) { |
902 |
< |
for (int s; (s = top - 1) - base >= 0;) { |
903 |
< |
int j = ((m & s) << ASHIFT) + ABASE; |
904 |
< |
ForkJoinTask<?> t = |
905 |
< |
(ForkJoinTask<?>)U.getObjectVolatile(a, j); |
955 |
< |
if (t != null) { |
956 |
< |
if (U.compareAndSwapObject(a, j, t, null)) { |
957 |
< |
top = s; |
958 |
< |
t.doExec(); |
959 |
< |
} |
960 |
< |
} |
961 |
< |
else |
962 |
< |
break; |
963 |
< |
} |
893 |
> |
* Pops and runs tasks until empty. |
894 |
> |
*/ |
895 |
> |
private void popAndExecAll() { |
896 |
> |
// A bit faster than repeated pop calls |
897 |
> |
ForkJoinTask<?>[] a; int m, s; long j; ForkJoinTask<?> t; |
898 |
> |
while ((a = array) != null && (m = a.length - 1) >= 0 && |
899 |
> |
(s = top - 1) - base >= 0 && |
900 |
> |
(t = ((ForkJoinTask<?>) |
901 |
> |
U.getObject(a, j = ((m & s) << ASHIFT) + ABASE))) |
902 |
> |
!= null) { |
903 |
> |
if (U.compareAndSwapObject(a, j, t, null)) { |
904 |
> |
top = s; |
905 |
> |
t.doExec(); |
906 |
|
} |
907 |
< |
else { |
908 |
< |
for (int b; (b = base) - top < 0;) { |
909 |
< |
int j = ((m & b) << ASHIFT) + ABASE; |
910 |
< |
ForkJoinTask<?> t = |
911 |
< |
(ForkJoinTask<?>)U.getObjectVolatile(a, j); |
912 |
< |
if (t != null) { |
913 |
< |
if (base == b && |
914 |
< |
U.compareAndSwapObject(a, j, t, null)) { |
915 |
< |
base = b + 1; |
916 |
< |
t.doExec(); |
917 |
< |
} |
918 |
< |
} else if (base == b) { |
919 |
< |
if (b + 1 == top) |
907 |
> |
} |
908 |
> |
} |
909 |
> |
|
910 |
> |
/** |
911 |
> |
* Polls and runs tasks until empty. |
912 |
> |
*/ |
913 |
> |
private void pollAndExecAll() { |
914 |
> |
for (ForkJoinTask<?> t; (t = poll()) != null;) |
915 |
> |
t.doExec(); |
916 |
> |
} |
917 |
> |
|
918 |
> |
/** |
919 |
> |
* If present, removes from queue and executes the given task, or |
920 |
> |
* any other cancelled task. Returns (true) immediately on any CAS |
921 |
> |
* or consistency check failure so caller can retry. |
922 |
> |
* |
923 |
> |
* @return 0 if no progress can be made, else positive |
924 |
> |
* (this unusual convention simplifies use with tryHelpStealer.) |
925 |
> |
*/ |
926 |
> |
final int tryRemoveAndExec(ForkJoinTask<?> task) { |
927 |
> |
int stat = 1; |
928 |
> |
boolean removed = false, empty = true; |
929 |
> |
ForkJoinTask<?>[] a; int m, s, b, n; |
930 |
> |
if ((a = array) != null && (m = a.length - 1) >= 0 && |
931 |
> |
(n = (s = top) - (b = base)) > 0) { |
932 |
> |
for (ForkJoinTask<?> t;;) { // traverse from s to b |
933 |
> |
int j = ((--s & m) << ASHIFT) + ABASE; |
934 |
> |
t = (ForkJoinTask<?>)U.getObjectVolatile(a, j); |
935 |
> |
if (t == null) // inconsistent length |
936 |
> |
break; |
937 |
> |
else if (t == task) { |
938 |
> |
if (s + 1 == top) { // pop |
939 |
> |
if (!U.compareAndSwapObject(a, j, task, null)) |
940 |
|
break; |
941 |
< |
Thread.yield(); // wait for lagging update |
941 |
> |
top = s; |
942 |
> |
removed = true; |
943 |
|
} |
944 |
+ |
else if (base == b) // replace with proxy |
945 |
+ |
removed = U.compareAndSwapObject(a, j, task, |
946 |
+ |
new EmptyTask()); |
947 |
+ |
break; |
948 |
+ |
} |
949 |
+ |
else if (t.status >= 0) |
950 |
+ |
empty = false; |
951 |
+ |
else if (s + 1 == top) { // pop and throw away |
952 |
+ |
if (U.compareAndSwapObject(a, j, t, null)) |
953 |
+ |
top = s; |
954 |
+ |
break; |
955 |
+ |
} |
956 |
+ |
if (--n == 0) { |
957 |
+ |
if (!empty && base == b) |
958 |
+ |
stat = 0; |
959 |
+ |
break; |
960 |
|
} |
961 |
|
} |
962 |
|
} |
963 |
+ |
if (removed) |
964 |
+ |
task.doExec(); |
965 |
+ |
return stat; |
966 |
|
} |
967 |
|
|
968 |
|
/** |
969 |
|
* Executes a top-level task and any local tasks remaining |
970 |
|
* after execution. |
989 |
– |
* |
990 |
– |
* @return true unless terminating |
971 |
|
*/ |
972 |
< |
final boolean runTask(ForkJoinTask<?> t) { |
993 |
< |
boolean alive = true; |
972 |
> |
final void runTask(ForkJoinTask<?> t) { |
973 |
|
if (t != null) { |
974 |
|
currentSteal = t; |
975 |
|
t.doExec(); |
976 |
< |
if (top != base) // conservative guard |
977 |
< |
runLocalTasks(); |
976 |
> |
if (top != base) { // process remaining local tasks |
977 |
> |
if (mode == 0) |
978 |
> |
popAndExecAll(); |
979 |
> |
else |
980 |
> |
pollAndExecAll(); |
981 |
> |
} |
982 |
|
++nsteals; |
983 |
|
currentSteal = null; |
984 |
|
} |
1002 |
– |
else if (runState < 0) // terminating |
1003 |
– |
alive = false; |
1004 |
– |
return alive; |
985 |
|
} |
986 |
|
|
987 |
|
/** |
1047 |
|
ASHIFT = 31 - Integer.numberOfLeadingZeros(s); |
1048 |
|
} |
1049 |
|
} |
1070 |
– |
|
1050 |
|
/** |
1051 |
|
* Per-thread records for threads that submit to pools. Currently |
1052 |
|
* holds only pseudo-random seed / index that is used to choose |
1139 |
|
* traversal parameters at the expense of sometimes blocking when |
1140 |
|
* we could be helping. |
1141 |
|
*/ |
1142 |
< |
private static final int MAX_HELP = 32; |
1142 |
> |
private static final int MAX_HELP = 64; |
1143 |
|
|
1144 |
|
/** |
1145 |
|
* Secondary time-based bound (in nanosecs) for helping attempts |
1149 |
|
* value should roughly approximate the time required to create |
1150 |
|
* and/or activate a worker thread. |
1151 |
|
*/ |
1152 |
< |
private static final long COMPENSATION_DELAY = 100L * 1000L; // 0.1 millisec |
1152 |
> |
private static final long COMPENSATION_DELAY = 1L << 18; // ~0.25 millisec |
1153 |
|
|
1154 |
|
/** |
1155 |
|
* Increment for seed generators. See class ThreadLocal for |
1300 |
|
* |
1301 |
|
* @param w the worker's queue |
1302 |
|
*/ |
1303 |
+ |
|
1304 |
|
final void registerWorker(WorkQueue w) { |
1305 |
|
Mutex lock = this.lock; |
1306 |
|
lock.lock(); |
1307 |
|
try { |
1308 |
|
WorkQueue[] ws = workQueues; |
1309 |
|
if (w != null && ws != null) { // skip on shutdown/failure |
1310 |
< |
int rs, n; |
1331 |
< |
while ((n = ws.length) < // ensure can hold total |
1332 |
< |
(parallelism + (short)(ctl >>> TC_SHIFT) << 1)) |
1333 |
< |
workQueues = ws = Arrays.copyOf(ws, n << 1); |
1334 |
< |
int m = n - 1; |
1310 |
> |
int rs, n = ws.length, m = n - 1; |
1311 |
|
int s = nextSeed += SEED_INCREMENT; // rarely-colliding sequence |
1312 |
|
w.seed = (s == 0) ? 1 : s; // ensure non-zero seed |
1313 |
|
int r = (s << 1) | 1; // use odd-numbered indices |
1314 |
< |
while (ws[r &= m] != null) // step by approx half size |
1315 |
< |
r += ((n >>> 1) & SQMASK) + 2; |
1314 |
> |
if (ws[r &= m] != null) { // collision |
1315 |
> |
int probes = 0; // step by approx half size |
1316 |
> |
int step = (n <= 4) ? 2 : ((n >>> 1) & SQMASK) + 2; |
1317 |
> |
while (ws[r = (r + step) & m] != null) { |
1318 |
> |
if (++probes >= n) { |
1319 |
> |
workQueues = ws = Arrays.copyOf(ws, n <<= 1); |
1320 |
> |
m = n - 1; |
1321 |
> |
probes = 0; |
1322 |
> |
} |
1323 |
> |
} |
1324 |
> |
} |
1325 |
|
w.eventCount = w.poolIndex = r; // establish before recording |
1326 |
|
ws[r] = w; // also update seq |
1327 |
|
runState = ((rs = runState) & SHUTDOWN) | ((rs + 2) & ~SHUTDOWN); |
1384 |
|
* range). If no queue exists at the index, one is created. If |
1385 |
|
* the queue is busy, another index is randomly chosen. The |
1386 |
|
* submitMask bounds the effective number of queues to the |
1387 |
< |
* (nearest poswer of two for) parallelism level. |
1387 |
> |
* (nearest power of two for) parallelism level. |
1388 |
|
* |
1389 |
|
* @param task the task. Caller must ensure non-null. |
1390 |
|
*/ |
1468 |
|
} |
1469 |
|
} |
1470 |
|
|
1486 |
– |
|
1471 |
|
// Scanning for tasks |
1472 |
|
|
1473 |
|
/** |
1475 |
|
*/ |
1476 |
|
final void runWorker(WorkQueue w) { |
1477 |
|
w.growArray(false); // initialize queue array in this thread |
1478 |
< |
do {} while (w.runTask(scan(w))); |
1478 |
> |
do { w.runTask(scan(w)); } while (w.runState >= 0); |
1479 |
|
} |
1480 |
|
|
1481 |
|
/** |
1535 |
|
t = (ForkJoinTask<?>)U.getObjectVolatile(a, i); |
1536 |
|
if (q.base == b && ec >= 0 && t != null && |
1537 |
|
U.compareAndSwapObject(a, i, t, null)) { |
1538 |
< |
q.base = b + 1; // specialization of pollAt |
1538 |
> |
if (q.top - (q.base = b + 1) > 1) |
1539 |
> |
signalWork(); // help pushes signal |
1540 |
|
return t; |
1541 |
|
} |
1542 |
< |
else if ((t != null || b + 1 != q.top) && |
1558 |
< |
(ec < 0 || j <= m)) { |
1542 |
> |
else if (ec < 0 || j <= m) { |
1543 |
|
rs = 0; // mark scan as imcomplete |
1544 |
|
break; // caller can retry after release |
1545 |
|
} |
1547 |
|
if (--j < 0) |
1548 |
|
break; |
1549 |
|
} |
1550 |
+ |
|
1551 |
|
long c = ctl; int e = (int)c, a = (int)(c >> AC_SHIFT), nr, ns; |
1552 |
|
if (e < 0) // decode ctl on empty scan |
1553 |
|
w.runState = -1; // pool is terminating |
1573 |
|
else { |
1574 |
|
if ((ns = w.nsteals) != 0) { |
1575 |
|
w.nsteals = 0; // set rescans if ran task |
1576 |
< |
w.rescans = (a > 0)? 0 : a + parallelism; |
1576 |
> |
w.rescans = (a > 0) ? 0 : a + parallelism; |
1577 |
|
w.totalSteals += ns; |
1578 |
|
} |
1579 |
|
if (a == 1 - parallelism) // quiescent |
1615 |
|
*/ |
1616 |
|
private void idleAwaitWork(WorkQueue w, long currentCtl, long prevCtl) { |
1617 |
|
if (w.eventCount < 0 && !tryTerminate(false, false) && |
1618 |
< |
(int)prevCtl != 0 && ctl == currentCtl) { |
1618 |
> |
(int)prevCtl != 0 && !hasQueuedSubmissions() && ctl == currentCtl) { |
1619 |
|
Thread wt = Thread.currentThread(); |
1620 |
|
Thread.yield(); // yield before block |
1621 |
|
while (ctl == currentCtl) { |
1650 |
|
* leaves hints in workers to speed up subsequent calls. The |
1651 |
|
* implementation is very branchy to cope with potential |
1652 |
|
* inconsistencies or loops encountering chains that are stale, |
1653 |
< |
* unknown, or so long that they are likely cyclic. All of these |
1669 |
< |
* cases are dealt with by just retrying by caller. |
1653 |
> |
* unknown, or so long that they are likely cyclic. |
1654 |
|
* |
1655 |
|
* @param joiner the joining worker |
1656 |
|
* @param task the task to join |
1657 |
< |
* @return true if found or ran a task (and so is immediately retryable) |
1657 |
> |
* @return 0 if no progress can be made, negative if task |
1658 |
> |
* known complete, else positive |
1659 |
|
*/ |
1660 |
< |
private boolean tryHelpStealer(WorkQueue joiner, ForkJoinTask<?> task) { |
1661 |
< |
WorkQueue[] ws; |
1662 |
< |
int m, depth = MAX_HELP; // remaining chain depth |
1663 |
< |
boolean progress = false; |
1664 |
< |
if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && |
1665 |
< |
task.status >= 0) { |
1666 |
< |
ForkJoinTask<?> subtask = task; // current target |
1667 |
< |
outer: for (WorkQueue j = joiner;;) { |
1668 |
< |
WorkQueue stealer = null; // find stealer of subtask |
1669 |
< |
WorkQueue v = ws[j.stealHint & m]; // try hint |
1670 |
< |
if (v != null && v.currentSteal == subtask) |
1671 |
< |
stealer = v; |
1672 |
< |
else { // scan |
1673 |
< |
for (int i = 1; i <= m; i += 2) { |
1674 |
< |
if ((v = ws[i]) != null && v.currentSteal == subtask && |
1675 |
< |
v != joiner) { |
1676 |
< |
stealer = v; |
1677 |
< |
j.stealHint = i; // save hint |
1678 |
< |
break; |
1660 |
> |
private int tryHelpStealer(WorkQueue joiner, ForkJoinTask<?> task) { |
1661 |
> |
int stat = 0, steps = 0; // bound to avoid cycles |
1662 |
> |
if (joiner != null && task != null) { // hoist null checks |
1663 |
> |
restart: for (;;) { |
1664 |
> |
ForkJoinTask<?> subtask = task; // current target |
1665 |
> |
for (WorkQueue j = joiner, v;;) { // v is stealer of subtask |
1666 |
> |
WorkQueue[] ws; int m, s, h; |
1667 |
> |
if ((s = task.status) < 0) { |
1668 |
> |
stat = s; |
1669 |
> |
break restart; |
1670 |
> |
} |
1671 |
> |
if ((ws = workQueues) == null || (m = ws.length - 1) <= 0) |
1672 |
> |
break restart; // shutting down |
1673 |
> |
if ((v = ws[h = (j.stealHint | 1) & m]) == null || |
1674 |
> |
v.currentSteal != subtask) { |
1675 |
> |
for (int origin = h;;) { // find stealer |
1676 |
> |
if (((h = (h + 2) & m) & 15) == 1 && |
1677 |
> |
(subtask.status < 0 || j.currentJoin != subtask)) |
1678 |
> |
continue restart; // occasional staleness check |
1679 |
> |
if ((v = ws[h]) != null && |
1680 |
> |
v.currentSteal == subtask) { |
1681 |
> |
j.stealHint = h; // save hint |
1682 |
> |
break; |
1683 |
> |
} |
1684 |
> |
if (h == origin) |
1685 |
> |
break restart; // cannot find stealer |
1686 |
|
} |
1687 |
|
} |
1688 |
< |
if (stealer == null) |
1689 |
< |
break; |
1690 |
< |
} |
1691 |
< |
|
1692 |
< |
for (WorkQueue q = stealer;;) { // try to help stealer |
1693 |
< |
ForkJoinTask[] a; ForkJoinTask<?> t; int b; |
1694 |
< |
if (task.status < 0) |
1695 |
< |
break outer; |
1696 |
< |
if ((b = q.base) - q.top < 0 && (a = q.array) != null) { |
1697 |
< |
progress = true; |
1698 |
< |
int i = (((a.length - 1) & b) << ASHIFT) + ABASE; |
1699 |
< |
t = (ForkJoinTask<?>)U.getObjectVolatile(a, i); |
1700 |
< |
if (subtask.status < 0) // must recheck before taking |
1701 |
< |
break outer; |
1702 |
< |
if (t != null && |
1703 |
< |
q.base == b && |
1704 |
< |
U.compareAndSwapObject(a, i, t, null)) { |
1705 |
< |
q.base = b + 1; |
1706 |
< |
joiner.runSubtask(t); |
1688 |
> |
for (;;) { // help stealer or descend to its stealer |
1689 |
> |
ForkJoinTask[] a; int b; |
1690 |
> |
if (subtask.status < 0) // surround probes with |
1691 |
> |
continue restart; // consistency checks |
1692 |
> |
if ((b = v.base) - v.top < 0 && (a = v.array) != null) { |
1693 |
> |
int i = (((a.length - 1) & b) << ASHIFT) + ABASE; |
1694 |
> |
ForkJoinTask<?> t = |
1695 |
> |
(ForkJoinTask<?>)U.getObjectVolatile(a, i); |
1696 |
> |
if (subtask.status < 0 || j.currentJoin != subtask || |
1697 |
> |
v.currentSteal != subtask) |
1698 |
> |
continue restart; // stale |
1699 |
> |
stat = 1; // apparent progress |
1700 |
> |
if (t != null && v.base == b && |
1701 |
> |
U.compareAndSwapObject(a, i, t, null)) { |
1702 |
> |
v.base = b + 1; // help stealer |
1703 |
> |
joiner.runSubtask(t); |
1704 |
> |
} |
1705 |
> |
else if (v.base == b && ++steps == MAX_HELP) |
1706 |
> |
break restart; // v apparently stalled |
1707 |
> |
} |
1708 |
> |
else { // empty -- try to descend |
1709 |
> |
ForkJoinTask<?> next = v.currentJoin; |
1710 |
> |
if (subtask.status < 0 || j.currentJoin != subtask || |
1711 |
> |
v.currentSteal != subtask) |
1712 |
> |
continue restart; // stale |
1713 |
> |
else if (next == null || ++steps == MAX_HELP) |
1714 |
> |
break restart; // dead-end or maybe cyclic |
1715 |
> |
else { |
1716 |
> |
subtask = next; |
1717 |
> |
j = v; |
1718 |
> |
break; |
1719 |
> |
} |
1720 |
|
} |
1716 |
– |
else if (q.base == b) |
1717 |
– |
break outer; // possibly stalled |
1718 |
– |
} |
1719 |
– |
else { // descend |
1720 |
– |
ForkJoinTask<?> next = stealer.currentJoin; |
1721 |
– |
if (--depth <= 0 || subtask.status < 0 || |
1722 |
– |
next == null || next == subtask) |
1723 |
– |
break outer; // stale, dead-end, or cyclic |
1724 |
– |
subtask = next; |
1725 |
– |
j = stealer; |
1726 |
– |
break; |
1721 |
|
} |
1722 |
|
} |
1723 |
|
} |
1724 |
|
} |
1725 |
< |
return progress; |
1725 |
> |
return stat; |
1726 |
|
} |
1727 |
|
|
1728 |
|
/** |
1751 |
|
* adds a new thread if no idle workers are available and either |
1752 |
|
* pool would become completely starved or: (at least half |
1753 |
|
* starved, and fewer than 50% spares exist, and there is at least |
1754 |
< |
* one task apparently available). Even though the availablity |
1754 |
> |
* one task apparently available). Even though the availability |
1755 |
|
* check requires a full scan, it is worthwhile in reducing false |
1756 |
|
* alarms. |
1757 |
|
* |
1758 |
< |
* @param task if nonnull, a task being waited for |
1759 |
< |
* @param blocker if nonnull, a blocker being waited for |
1758 |
> |
* @param task if non-null, a task being waited for |
1759 |
> |
* @param blocker if non-null, a blocker being waited for |
1760 |
|
* @return true if the caller can block, else should recheck and retry |
1761 |
|
*/ |
1762 |
|
final boolean tryCompensate(ForkJoinTask<?> task, ManagedBlocker blocker) { |
1815 |
|
} |
1816 |
|
|
1817 |
|
/** |
1818 |
< |
* Helps and/or blocks until the given task is done |
1818 |
> |
* Helps and/or blocks until the given task is done. |
1819 |
|
* |
1820 |
|
* @param joiner the joining worker |
1821 |
|
* @param task the task |
1822 |
|
* @return task status on exit |
1823 |
|
*/ |
1824 |
|
final int awaitJoin(WorkQueue joiner, ForkJoinTask<?> task) { |
1825 |
< |
ForkJoinTask<?> prevJoin = joiner.currentJoin; |
1826 |
< |
joiner.currentJoin = task; |
1827 |
< |
long startTime = 0L; |
1828 |
< |
for (int k = 0, s; ; ++k) { |
1829 |
< |
if ((joiner.isEmpty() ? // try to help |
1830 |
< |
!tryHelpStealer(joiner, task) : |
1831 |
< |
!joiner.tryRemoveAndExec(task))) { |
1832 |
< |
if (k == 0) { |
1833 |
< |
startTime = System.nanoTime(); |
1834 |
< |
tryPollForAndExec(joiner, task); // check uncommon case |
1835 |
< |
} |
1836 |
< |
else if ((k & (MAX_HELP - 1)) == 0 && |
1837 |
< |
System.nanoTime() - startTime >= COMPENSATION_DELAY && |
1838 |
< |
tryCompensate(task, null)) { |
1839 |
< |
if (task.trySetSignal() && task.status >= 0) { |
1840 |
< |
synchronized (task) { |
1841 |
< |
if (task.status >= 0) { |
1842 |
< |
try { // see ForkJoinTask |
1843 |
< |
task.wait(); // for explanation |
1844 |
< |
} catch (InterruptedException ie) { |
1825 |
> |
int s; |
1826 |
> |
if ((s = task.status) >= 0) { |
1827 |
> |
ForkJoinTask<?> prevJoin = joiner.currentJoin; |
1828 |
> |
joiner.currentJoin = task; |
1829 |
> |
long startTime = 0L; |
1830 |
> |
for (int k = 0;;) { |
1831 |
> |
if ((s = (joiner.isEmpty() ? // try to help |
1832 |
> |
tryHelpStealer(joiner, task) : |
1833 |
> |
joiner.tryRemoveAndExec(task))) == 0 && |
1834 |
> |
(s = task.status) >= 0) { |
1835 |
> |
if (k == 0) { |
1836 |
> |
startTime = System.nanoTime(); |
1837 |
> |
tryPollForAndExec(joiner, task); // check uncommon case |
1838 |
> |
} |
1839 |
> |
else if ((k & (MAX_HELP - 1)) == 0 && |
1840 |
> |
System.nanoTime() - startTime >= |
1841 |
> |
COMPENSATION_DELAY && |
1842 |
> |
tryCompensate(task, null)) { |
1843 |
> |
if (task.trySetSignal()) { |
1844 |
> |
synchronized (task) { |
1845 |
> |
if (task.status >= 0) { |
1846 |
> |
try { // see ForkJoinTask |
1847 |
> |
task.wait(); // for explanation |
1848 |
> |
} catch (InterruptedException ie) { |
1849 |
> |
} |
1850 |
|
} |
1851 |
+ |
else |
1852 |
+ |
task.notifyAll(); |
1853 |
|
} |
1853 |
– |
else |
1854 |
– |
task.notifyAll(); |
1854 |
|
} |
1855 |
+ |
long c; // re-activate |
1856 |
+ |
do {} while (!U.compareAndSwapLong |
1857 |
+ |
(this, CTL, c = ctl, c + AC_UNIT)); |
1858 |
|
} |
1857 |
– |
long c; // re-activate |
1858 |
– |
do {} while (!U.compareAndSwapLong |
1859 |
– |
(this, CTL, c = ctl, c + AC_UNIT)); |
1859 |
|
} |
1860 |
+ |
if (s < 0 || (s = task.status) < 0) { |
1861 |
+ |
joiner.currentJoin = prevJoin; |
1862 |
+ |
break; |
1863 |
+ |
} |
1864 |
+ |
else if ((k++ & (MAX_HELP - 1)) == MAX_HELP >>> 1) |
1865 |
+ |
Thread.yield(); // for politeness |
1866 |
|
} |
1862 |
– |
if ((s = task.status) < 0) { |
1863 |
– |
joiner.currentJoin = prevJoin; |
1864 |
– |
return s; |
1865 |
– |
} |
1866 |
– |
else if ((k & (MAX_HELP - 1)) == MAX_HELP >>> 1) |
1867 |
– |
Thread.yield(); // for politeness |
1867 |
|
} |
1868 |
+ |
return s; |
1869 |
|
} |
1870 |
|
|
1871 |
|
/** |
1882 |
|
while ((s = task.status) >= 0 && |
1883 |
|
(joiner.isEmpty() ? |
1884 |
|
tryHelpStealer(joiner, task) : |
1885 |
< |
joiner.tryRemoveAndExec(task))) |
1885 |
> |
joiner.tryRemoveAndExec(task)) != 0) |
1886 |
|
; |
1887 |
|
return s; |
1888 |
|
} |
1914 |
|
} |
1915 |
|
} |
1916 |
|
|
1917 |
+ |
|
1918 |
|
/** |
1919 |
|
* Runs tasks until {@code isQuiescent()}. We piggyback on |
1920 |
|
* active count ctl maintenance, but rather than blocking |
1923 |
|
*/ |
1924 |
|
final void helpQuiescePool(WorkQueue w) { |
1925 |
|
for (boolean active = true;;) { |
1926 |
< |
if (w.base - w.top < 0) |
1927 |
< |
w.runLocalTasks(); // exhaust local queue |
1926 |
> |
ForkJoinTask<?> localTask; // exhaust local queue |
1927 |
> |
while ((localTask = w.nextLocalTask()) != null) |
1928 |
> |
localTask.doExec(); |
1929 |
|
WorkQueue q = findNonEmptyStealQueue(w); |
1930 |
|
if (q != null) { |
1931 |
|
ForkJoinTask<?> t; int b; |