| /* |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * This file is available under and governed by the GNU General Public |
| * License version 2 only, as published by the Free Software Foundation. |
| * However, the following notice accompanied the original version of this |
| * file: |
| * |
| * Written by Doug Lea with assistance from members of JCP JSR-166 |
| * Expert Group and released to the public domain, as explained at |
| * http://creativecommons.org/publicdomain/zero/1.0/ |
| */ |
| |
| package java.util; |
| |
| import java.util.concurrent.CountedCompleter; |
| import java.util.concurrent.ForkJoinPool; |
| import java.util.function.BinaryOperator; |
| import java.util.function.DoubleBinaryOperator; |
| import java.util.function.IntBinaryOperator; |
| import java.util.function.LongBinaryOperator; |
| |
| /** |
| * ForkJoin tasks to perform Arrays.parallelPrefix operations. |
| * |
| * @author Doug Lea |
| * @since 1.8 |
| */ |
| class ArrayPrefixHelpers { |
| private ArrayPrefixHelpers() {} // non-instantiable |
| |
| /* |
| * Parallel prefix (aka cumulate, scan) task classes |
| * are based loosely on Guy Blelloch's original |
| * algorithm (http://www.cs.cmu.edu/~scandal/alg/scan.html): |
| * Keep dividing by two to threshold segment size, and then: |
| * Pass 1: Create tree of partial sums for each segment |
| * Pass 2: For each segment, cumulate with offset of left sibling |
| * |
| * This version improves performance within FJ framework mainly by |
| * allowing the second pass of ready left-hand sides to proceed |
| * even if some right-hand side first passes are still executing. |
| * It also combines first and second pass for leftmost segment, |
| * and skips the first pass for rightmost segment (whose result is |
| * not needed for second pass). It similarly manages to avoid |
| * requiring that users supply an identity basis for accumulations |
| * by tracking those segments/subtasks for which the first |
| * existing element is used as base. |
| * |
| * Managing this relies on ORing some bits in the pendingCount for |
| * phases/states: CUMULATE, SUMMED, and FINISHED. CUMULATE is the |
| * main phase bit. When false, segments compute only their sum. |
| * When true, they cumulate array elements. CUMULATE is set at |
| * root at beginning of second pass and then propagated down. But |
| * it may also be set earlier for subtrees with lo==0 (the left |
| * spine of tree). SUMMED is a one bit join count. For leafs, it |
| * is set when summed. For internal nodes, it becomes true when |
| * one child is summed. When the second child finishes summing, |
| * we then moves up tree to trigger the cumulate phase. FINISHED |
| * is also a one bit join count. For leafs, it is set when |
| * cumulated. For internal nodes, it becomes true when one child |
| * is cumulated. When the second child finishes cumulating, it |
| * then moves up tree, completing at the root. |
| * |
| * To better exploit locality and reduce overhead, the compute |
| * method loops starting with the current task, moving if possible |
| * to one of its subtasks rather than forking. |
| * |
| * As usual for this sort of utility, there are 4 versions, that |
| * are simple copy/paste/adapt variants of each other. (The |
| * double and int versions differ from long version solely by |
| * replacing "long" (with case-matching)). |
| */ |
| |
| // see above |
| static final int CUMULATE = 1; |
| static final int SUMMED = 2; |
| static final int FINISHED = 4; |
| |
| /** The smallest subtask array partition size to use as threshold */ |
| static final int MIN_PARTITION = 16; |
| |
| static final class CumulateTask<T> extends CountedCompleter<Void> { |
| final T[] array; |
| final BinaryOperator<T> function; |
| CumulateTask<T> left, right; |
| T in, out; |
| final int lo, hi, origin, fence, threshold; |
| |
| /** Root task constructor */ |
| public CumulateTask(CumulateTask<T> parent, |
| BinaryOperator<T> function, |
| T[] array, int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.lo = this.origin = lo; this.hi = this.fence = hi; |
| int p; |
| this.threshold = |
| (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3)) |
| <= MIN_PARTITION ? MIN_PARTITION : p; |
| } |
| |
| /** Subtask constructor */ |
| CumulateTask(CumulateTask<T> parent, BinaryOperator<T> function, |
| T[] array, int origin, int fence, int threshold, |
| int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.origin = origin; this.fence = fence; |
| this.threshold = threshold; |
| this.lo = lo; this.hi = hi; |
| } |
| |
| public final void compute() { |
| final BinaryOperator<T> fn; |
| final T[] a; |
| if ((fn = this.function) == null || (a = this.array) == null) |
| throw new NullPointerException(); // hoist checks |
| int th = threshold, org = origin, fnc = fence, l, h; |
| CumulateTask<T> t = this; |
| outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) { |
| if (h - l > th) { |
| CumulateTask<T> lt = t.left, rt = t.right, f; |
| if (lt == null) { // first pass |
| int mid = (l + h) >>> 1; |
| f = rt = t.right = |
| new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h); |
| t = lt = t.left = |
| new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid); |
| } |
| else { // possibly refork |
| T pin = t.in; |
| lt.in = pin; |
| f = t = null; |
| if (rt != null) { |
| T lout = lt.out; |
| rt.in = (l == org ? lout : |
| fn.apply(pin, lout)); |
| for (int c;;) { |
| if (((c = rt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (rt.compareAndSetPendingCount(c, c|CUMULATE)){ |
| t = rt; |
| break; |
| } |
| } |
| } |
| for (int c;;) { |
| if (((c = lt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (lt.compareAndSetPendingCount(c, c|CUMULATE)) { |
| if (t != null) |
| f = t; |
| t = lt; |
| break; |
| } |
| } |
| if (t == null) |
| break; |
| } |
| if (f != null) |
| f.fork(); |
| } |
| else { |
| int state; // Transition to sum, cumulate, or both |
| for (int b;;) { |
| if (((b = t.getPendingCount()) & FINISHED) != 0) |
| break outer; // already done |
| state = ((b & CUMULATE) != 0 ? FINISHED : |
| (l > org) ? SUMMED : (SUMMED|FINISHED)); |
| if (t.compareAndSetPendingCount(b, b|state)) |
| break; |
| } |
| |
| T sum; |
| if (state != SUMMED) { |
| int first; |
| if (l == org) { // leftmost; no in |
| sum = a[org]; |
| first = org + 1; |
| } |
| else { |
| sum = t.in; |
| first = l; |
| } |
| for (int i = first; i < h; ++i) // cumulate |
| a[i] = sum = fn.apply(sum, a[i]); |
| } |
| else if (h < fnc) { // skip rightmost |
| sum = a[l]; |
| for (int i = l + 1; i < h; ++i) // sum only |
| sum = fn.apply(sum, a[i]); |
| } |
| else |
| sum = t.in; |
| t.out = sum; |
| for (CumulateTask<T> par;;) { // propagate |
| @SuppressWarnings("unchecked") CumulateTask<T> partmp |
| = (CumulateTask<T>)t.getCompleter(); |
| if ((par = partmp) == null) { |
| if ((state & FINISHED) != 0) // enable join |
| t.quietlyComplete(); |
| break outer; |
| } |
| int b = par.getPendingCount(); |
| if ((b & state & FINISHED) != 0) |
| t = par; // both done |
| else if ((b & state & SUMMED) != 0) { // both summed |
| int nextState; CumulateTask<T> lt, rt; |
| if ((lt = par.left) != null && |
| (rt = par.right) != null) { |
| T lout = lt.out; |
| par.out = (rt.hi == fnc ? lout : |
| fn.apply(lout, rt.out)); |
| } |
| int refork = (((b & CUMULATE) == 0 && |
| par.lo == org) ? CUMULATE : 0); |
| if ((nextState = b|state|refork) == b || |
| par.compareAndSetPendingCount(b, nextState)) { |
| state = SUMMED; // drop finished |
| t = par; |
| if (refork != 0) |
| par.fork(); |
| } |
| } |
| else if (par.compareAndSetPendingCount(b, b|state)) |
| break outer; // sib not ready |
| } |
| } |
| } |
| } |
| private static final long serialVersionUID = 5293554502939613543L; |
| } |
| |
| static final class LongCumulateTask extends CountedCompleter<Void> { |
| final long[] array; |
| final LongBinaryOperator function; |
| LongCumulateTask left, right; |
| long in, out; |
| final int lo, hi, origin, fence, threshold; |
| |
| /** Root task constructor */ |
| public LongCumulateTask(LongCumulateTask parent, |
| LongBinaryOperator function, |
| long[] array, int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.lo = this.origin = lo; this.hi = this.fence = hi; |
| int p; |
| this.threshold = |
| (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3)) |
| <= MIN_PARTITION ? MIN_PARTITION : p; |
| } |
| |
| /** Subtask constructor */ |
| LongCumulateTask(LongCumulateTask parent, LongBinaryOperator function, |
| long[] array, int origin, int fence, int threshold, |
| int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.origin = origin; this.fence = fence; |
| this.threshold = threshold; |
| this.lo = lo; this.hi = hi; |
| } |
| |
| public final void compute() { |
| final LongBinaryOperator fn; |
| final long[] a; |
| if ((fn = this.function) == null || (a = this.array) == null) |
| throw new NullPointerException(); // hoist checks |
| int th = threshold, org = origin, fnc = fence, l, h; |
| LongCumulateTask t = this; |
| outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) { |
| if (h - l > th) { |
| LongCumulateTask lt = t.left, rt = t.right, f; |
| if (lt == null) { // first pass |
| int mid = (l + h) >>> 1; |
| f = rt = t.right = |
| new LongCumulateTask(t, fn, a, org, fnc, th, mid, h); |
| t = lt = t.left = |
| new LongCumulateTask(t, fn, a, org, fnc, th, l, mid); |
| } |
| else { // possibly refork |
| long pin = t.in; |
| lt.in = pin; |
| f = t = null; |
| if (rt != null) { |
| long lout = lt.out; |
| rt.in = (l == org ? lout : |
| fn.applyAsLong(pin, lout)); |
| for (int c;;) { |
| if (((c = rt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (rt.compareAndSetPendingCount(c, c|CUMULATE)){ |
| t = rt; |
| break; |
| } |
| } |
| } |
| for (int c;;) { |
| if (((c = lt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (lt.compareAndSetPendingCount(c, c|CUMULATE)) { |
| if (t != null) |
| f = t; |
| t = lt; |
| break; |
| } |
| } |
| if (t == null) |
| break; |
| } |
| if (f != null) |
| f.fork(); |
| } |
| else { |
| int state; // Transition to sum, cumulate, or both |
| for (int b;;) { |
| if (((b = t.getPendingCount()) & FINISHED) != 0) |
| break outer; // already done |
| state = ((b & CUMULATE) != 0 ? FINISHED : |
| (l > org) ? SUMMED : (SUMMED|FINISHED)); |
| if (t.compareAndSetPendingCount(b, b|state)) |
| break; |
| } |
| |
| long sum; |
| if (state != SUMMED) { |
| int first; |
| if (l == org) { // leftmost; no in |
| sum = a[org]; |
| first = org + 1; |
| } |
| else { |
| sum = t.in; |
| first = l; |
| } |
| for (int i = first; i < h; ++i) // cumulate |
| a[i] = sum = fn.applyAsLong(sum, a[i]); |
| } |
| else if (h < fnc) { // skip rightmost |
| sum = a[l]; |
| for (int i = l + 1; i < h; ++i) // sum only |
| sum = fn.applyAsLong(sum, a[i]); |
| } |
| else |
| sum = t.in; |
| t.out = sum; |
| for (LongCumulateTask par;;) { // propagate |
| if ((par = (LongCumulateTask)t.getCompleter()) == null) { |
| if ((state & FINISHED) != 0) // enable join |
| t.quietlyComplete(); |
| break outer; |
| } |
| int b = par.getPendingCount(); |
| if ((b & state & FINISHED) != 0) |
| t = par; // both done |
| else if ((b & state & SUMMED) != 0) { // both summed |
| int nextState; LongCumulateTask lt, rt; |
| if ((lt = par.left) != null && |
| (rt = par.right) != null) { |
| long lout = lt.out; |
| par.out = (rt.hi == fnc ? lout : |
| fn.applyAsLong(lout, rt.out)); |
| } |
| int refork = (((b & CUMULATE) == 0 && |
| par.lo == org) ? CUMULATE : 0); |
| if ((nextState = b|state|refork) == b || |
| par.compareAndSetPendingCount(b, nextState)) { |
| state = SUMMED; // drop finished |
| t = par; |
| if (refork != 0) |
| par.fork(); |
| } |
| } |
| else if (par.compareAndSetPendingCount(b, b|state)) |
| break outer; // sib not ready |
| } |
| } |
| } |
| } |
| private static final long serialVersionUID = -5074099945909284273L; |
| } |
| |
| static final class DoubleCumulateTask extends CountedCompleter<Void> { |
| final double[] array; |
| final DoubleBinaryOperator function; |
| DoubleCumulateTask left, right; |
| double in, out; |
| final int lo, hi, origin, fence, threshold; |
| |
| /** Root task constructor */ |
| public DoubleCumulateTask(DoubleCumulateTask parent, |
| DoubleBinaryOperator function, |
| double[] array, int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.lo = this.origin = lo; this.hi = this.fence = hi; |
| int p; |
| this.threshold = |
| (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3)) |
| <= MIN_PARTITION ? MIN_PARTITION : p; |
| } |
| |
| /** Subtask constructor */ |
| DoubleCumulateTask(DoubleCumulateTask parent, DoubleBinaryOperator function, |
| double[] array, int origin, int fence, int threshold, |
| int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.origin = origin; this.fence = fence; |
| this.threshold = threshold; |
| this.lo = lo; this.hi = hi; |
| } |
| |
| public final void compute() { |
| final DoubleBinaryOperator fn; |
| final double[] a; |
| if ((fn = this.function) == null || (a = this.array) == null) |
| throw new NullPointerException(); // hoist checks |
| int th = threshold, org = origin, fnc = fence, l, h; |
| DoubleCumulateTask t = this; |
| outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) { |
| if (h - l > th) { |
| DoubleCumulateTask lt = t.left, rt = t.right, f; |
| if (lt == null) { // first pass |
| int mid = (l + h) >>> 1; |
| f = rt = t.right = |
| new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h); |
| t = lt = t.left = |
| new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid); |
| } |
| else { // possibly refork |
| double pin = t.in; |
| lt.in = pin; |
| f = t = null; |
| if (rt != null) { |
| double lout = lt.out; |
| rt.in = (l == org ? lout : |
| fn.applyAsDouble(pin, lout)); |
| for (int c;;) { |
| if (((c = rt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (rt.compareAndSetPendingCount(c, c|CUMULATE)){ |
| t = rt; |
| break; |
| } |
| } |
| } |
| for (int c;;) { |
| if (((c = lt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (lt.compareAndSetPendingCount(c, c|CUMULATE)) { |
| if (t != null) |
| f = t; |
| t = lt; |
| break; |
| } |
| } |
| if (t == null) |
| break; |
| } |
| if (f != null) |
| f.fork(); |
| } |
| else { |
| int state; // Transition to sum, cumulate, or both |
| for (int b;;) { |
| if (((b = t.getPendingCount()) & FINISHED) != 0) |
| break outer; // already done |
| state = ((b & CUMULATE) != 0 ? FINISHED : |
| (l > org) ? SUMMED : (SUMMED|FINISHED)); |
| if (t.compareAndSetPendingCount(b, b|state)) |
| break; |
| } |
| |
| double sum; |
| if (state != SUMMED) { |
| int first; |
| if (l == org) { // leftmost; no in |
| sum = a[org]; |
| first = org + 1; |
| } |
| else { |
| sum = t.in; |
| first = l; |
| } |
| for (int i = first; i < h; ++i) // cumulate |
| a[i] = sum = fn.applyAsDouble(sum, a[i]); |
| } |
| else if (h < fnc) { // skip rightmost |
| sum = a[l]; |
| for (int i = l + 1; i < h; ++i) // sum only |
| sum = fn.applyAsDouble(sum, a[i]); |
| } |
| else |
| sum = t.in; |
| t.out = sum; |
| for (DoubleCumulateTask par;;) { // propagate |
| if ((par = (DoubleCumulateTask)t.getCompleter()) == null) { |
| if ((state & FINISHED) != 0) // enable join |
| t.quietlyComplete(); |
| break outer; |
| } |
| int b = par.getPendingCount(); |
| if ((b & state & FINISHED) != 0) |
| t = par; // both done |
| else if ((b & state & SUMMED) != 0) { // both summed |
| int nextState; DoubleCumulateTask lt, rt; |
| if ((lt = par.left) != null && |
| (rt = par.right) != null) { |
| double lout = lt.out; |
| par.out = (rt.hi == fnc ? lout : |
| fn.applyAsDouble(lout, rt.out)); |
| } |
| int refork = (((b & CUMULATE) == 0 && |
| par.lo == org) ? CUMULATE : 0); |
| if ((nextState = b|state|refork) == b || |
| par.compareAndSetPendingCount(b, nextState)) { |
| state = SUMMED; // drop finished |
| t = par; |
| if (refork != 0) |
| par.fork(); |
| } |
| } |
| else if (par.compareAndSetPendingCount(b, b|state)) |
| break outer; // sib not ready |
| } |
| } |
| } |
| } |
| private static final long serialVersionUID = -586947823794232033L; |
| } |
| |
| static final class IntCumulateTask extends CountedCompleter<Void> { |
| final int[] array; |
| final IntBinaryOperator function; |
| IntCumulateTask left, right; |
| int in, out; |
| final int lo, hi, origin, fence, threshold; |
| |
| /** Root task constructor */ |
| public IntCumulateTask(IntCumulateTask parent, |
| IntBinaryOperator function, |
| int[] array, int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.lo = this.origin = lo; this.hi = this.fence = hi; |
| int p; |
| this.threshold = |
| (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3)) |
| <= MIN_PARTITION ? MIN_PARTITION : p; |
| } |
| |
| /** Subtask constructor */ |
| IntCumulateTask(IntCumulateTask parent, IntBinaryOperator function, |
| int[] array, int origin, int fence, int threshold, |
| int lo, int hi) { |
| super(parent); |
| this.function = function; this.array = array; |
| this.origin = origin; this.fence = fence; |
| this.threshold = threshold; |
| this.lo = lo; this.hi = hi; |
| } |
| |
| public final void compute() { |
| final IntBinaryOperator fn; |
| final int[] a; |
| if ((fn = this.function) == null || (a = this.array) == null) |
| throw new NullPointerException(); // hoist checks |
| int th = threshold, org = origin, fnc = fence, l, h; |
| IntCumulateTask t = this; |
| outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) { |
| if (h - l > th) { |
| IntCumulateTask lt = t.left, rt = t.right, f; |
| if (lt == null) { // first pass |
| int mid = (l + h) >>> 1; |
| f = rt = t.right = |
| new IntCumulateTask(t, fn, a, org, fnc, th, mid, h); |
| t = lt = t.left = |
| new IntCumulateTask(t, fn, a, org, fnc, th, l, mid); |
| } |
| else { // possibly refork |
| int pin = t.in; |
| lt.in = pin; |
| f = t = null; |
| if (rt != null) { |
| int lout = lt.out; |
| rt.in = (l == org ? lout : |
| fn.applyAsInt(pin, lout)); |
| for (int c;;) { |
| if (((c = rt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (rt.compareAndSetPendingCount(c, c|CUMULATE)){ |
| t = rt; |
| break; |
| } |
| } |
| } |
| for (int c;;) { |
| if (((c = lt.getPendingCount()) & CUMULATE) != 0) |
| break; |
| if (lt.compareAndSetPendingCount(c, c|CUMULATE)) { |
| if (t != null) |
| f = t; |
| t = lt; |
| break; |
| } |
| } |
| if (t == null) |
| break; |
| } |
| if (f != null) |
| f.fork(); |
| } |
| else { |
| int state; // Transition to sum, cumulate, or both |
| for (int b;;) { |
| if (((b = t.getPendingCount()) & FINISHED) != 0) |
| break outer; // already done |
| state = ((b & CUMULATE) != 0 ? FINISHED : |
| (l > org) ? SUMMED : (SUMMED|FINISHED)); |
| if (t.compareAndSetPendingCount(b, b|state)) |
| break; |
| } |
| |
| int sum; |
| if (state != SUMMED) { |
| int first; |
| if (l == org) { // leftmost; no in |
| sum = a[org]; |
| first = org + 1; |
| } |
| else { |
| sum = t.in; |
| first = l; |
| } |
| for (int i = first; i < h; ++i) // cumulate |
| a[i] = sum = fn.applyAsInt(sum, a[i]); |
| } |
| else if (h < fnc) { // skip rightmost |
| sum = a[l]; |
| for (int i = l + 1; i < h; ++i) // sum only |
| sum = fn.applyAsInt(sum, a[i]); |
| } |
| else |
| sum = t.in; |
| t.out = sum; |
| for (IntCumulateTask par;;) { // propagate |
| if ((par = (IntCumulateTask)t.getCompleter()) == null) { |
| if ((state & FINISHED) != 0) // enable join |
| t.quietlyComplete(); |
| break outer; |
| } |
| int b = par.getPendingCount(); |
| if ((b & state & FINISHED) != 0) |
| t = par; // both done |
| else if ((b & state & SUMMED) != 0) { // both summed |
| int nextState; IntCumulateTask lt, rt; |
| if ((lt = par.left) != null && |
| (rt = par.right) != null) { |
| int lout = lt.out; |
| par.out = (rt.hi == fnc ? lout : |
| fn.applyAsInt(lout, rt.out)); |
| } |
| int refork = (((b & CUMULATE) == 0 && |
| par.lo == org) ? CUMULATE : 0); |
| if ((nextState = b|state|refork) == b || |
| par.compareAndSetPendingCount(b, nextState)) { |
| state = SUMMED; // drop finished |
| t = par; |
| if (refork != 0) |
| par.fork(); |
| } |
| } |
| else if (par.compareAndSetPendingCount(b, b|state)) |
| break outer; // sib not ready |
| } |
| } |
| } |
| } |
| private static final long serialVersionUID = 3731755594596840961L; |
| } |
| } |