src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java

Print this page
rev 12972 : 8140606: Update library code to use internal Unsafe
Reviewed-by: duke


 266                         waiter = null;
 267                         LockSupport.unpark(w);
 268                     }
 269                     return true;
 270                 }
 271                 return match == s;
 272             }
 273 
 274             /**
 275              * Tries to cancel a wait by matching node to itself.
 276              */
 277             void tryCancel() {
 278                 U.compareAndSwapObject(this, MATCH, null, this);
 279             }
 280 
 281             boolean isCancelled() {
 282                 return match == this;
 283             }
 284 
 285             // Unsafe mechanics
 286             private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
 287             private static final long MATCH;
 288             private static final long NEXT;
 289 
 290             static {
 291                 try {
 292                     MATCH = U.objectFieldOffset
 293                         (SNode.class.getDeclaredField("match"));
 294                     NEXT = U.objectFieldOffset
 295                         (SNode.class.getDeclaredField("next"));
 296                 } catch (ReflectiveOperationException e) {
 297                     throw new Error(e);
 298                 }
 299             }
 300         }
 301 
 302         /** The head (top) of the stack */
 303         volatile SNode head;
 304 
 305         boolean casHead(SNode h, SNode nh) {
 306             return h == head &&


 492             SNode past = s.next;
 493             if (past != null && past.isCancelled())
 494                 past = past.next;
 495 
 496             // Absorb cancelled nodes at head
 497             SNode p;
 498             while ((p = head) != null && p != past && p.isCancelled())
 499                 casHead(p, p.next);
 500 
 501             // Unsplice embedded nodes
 502             while (p != null && p != past) {
 503                 SNode n = p.next;
 504                 if (n != null && n.isCancelled())
 505                     p.casNext(n, n.next);
 506                 else
 507                     p = n;
 508             }
 509         }
 510 
 511         // Unsafe mechanics
 512         private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
 513         private static final long HEAD;
 514         static {
 515             try {
 516                 HEAD = U.objectFieldOffset
 517                     (TransferStack.class.getDeclaredField("head"));
 518             } catch (ReflectiveOperationException e) {
 519                 throw new Error(e);
 520             }
 521         }
 522     }
 523 
 524     /** Dual Queue */
 525     static final class TransferQueue<E> extends Transferer<E> {
 526         /*
 527          * This extends Scherer-Scott dual queue algorithm, differing,
 528          * among other ways, by using modes within nodes rather than
 529          * marked pointers. The algorithm is a little simpler than
 530          * that for stacks because fulfillers do not need explicit
 531          * nodes, and matching is done by CAS'ing QNode.item field
 532          * from non-null to null (for put) or vice versa (for take).


 558              * Tries to cancel by CAS'ing ref to this as item.
 559              */
 560             void tryCancel(Object cmp) {
 561                 U.compareAndSwapObject(this, ITEM, cmp, this);
 562             }
 563 
 564             boolean isCancelled() {
 565                 return item == this;
 566             }
 567 
 568             /**
 569              * Returns true if this node is known to be off the queue
 570              * because its next pointer has been forgotten due to
 571              * an advanceHead operation.
 572              */
 573             boolean isOffList() {
 574                 return next == this;
 575             }
 576 
 577             // Unsafe mechanics
 578             private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
 579             private static final long ITEM;
 580             private static final long NEXT;
 581 
 582             static {
 583                 try {
 584                     ITEM = U.objectFieldOffset
 585                         (QNode.class.getDeclaredField("item"));
 586                     NEXT = U.objectFieldOffset
 587                         (QNode.class.getDeclaredField("next"));
 588                 } catch (ReflectiveOperationException e) {
 589                     throw new Error(e);
 590                 }
 591             }
 592         }
 593 
 594         /** Head of queue */
 595         transient volatile QNode head;
 596         /** Tail of queue */
 597         transient volatile QNode tail;
 598         /**


 800                 }
 801                 QNode dp = cleanMe;
 802                 if (dp != null) {    // Try unlinking previous cancelled node
 803                     QNode d = dp.next;
 804                     QNode dn;
 805                     if (d == null ||               // d is gone or
 806                         d == dp ||                 // d is off list or
 807                         !d.isCancelled() ||        // d not cancelled or
 808                         (d != t &&                 // d not tail and
 809                          (dn = d.next) != null &&  //   has successor
 810                          dn != d &&                //   that is on list
 811                          dp.casNext(d, dn)))       // d unspliced
 812                         casCleanMe(dp, null);
 813                     if (dp == pred)
 814                         return;      // s is already saved node
 815                 } else if (casCleanMe(null, pred))
 816                     return;          // Postpone cleaning s
 817             }
 818         }
 819 
 820         private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
 821         private static final long HEAD;
 822         private static final long TAIL;
 823         private static final long CLEANME;
 824         static {
 825             try {
 826                 HEAD = U.objectFieldOffset
 827                     (TransferQueue.class.getDeclaredField("head"));
 828                 TAIL = U.objectFieldOffset
 829                     (TransferQueue.class.getDeclaredField("tail"));
 830                 CLEANME = U.objectFieldOffset
 831                     (TransferQueue.class.getDeclaredField("cleanMe"));
 832             } catch (ReflectiveOperationException e) {
 833                 throw new Error(e);
 834             }
 835         }
 836     }
 837 
 838     /**
 839      * The transferer. Set only in constructor, but cannot be declared
 840      * as final without further complicating serialization.  Since




 266                         waiter = null;
 267                         LockSupport.unpark(w);
 268                     }
 269                     return true;
 270                 }
 271                 return match == s;
 272             }
 273 
 274             /**
 275              * Tries to cancel a wait by matching node to itself.
 276              */
 277             void tryCancel() {
 278                 U.compareAndSwapObject(this, MATCH, null, this);
 279             }
 280 
 281             boolean isCancelled() {
 282                 return match == this;
 283             }
 284 
 285             // Unsafe mechanics
 286             private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
 287             private static final long MATCH;
 288             private static final long NEXT;
 289 
 290             static {
 291                 try {
 292                     MATCH = U.objectFieldOffset
 293                         (SNode.class.getDeclaredField("match"));
 294                     NEXT = U.objectFieldOffset
 295                         (SNode.class.getDeclaredField("next"));
 296                 } catch (ReflectiveOperationException e) {
 297                     throw new Error(e);
 298                 }
 299             }
 300         }
 301 
 302         /** The head (top) of the stack */
 303         volatile SNode head;
 304 
 305         boolean casHead(SNode h, SNode nh) {
 306             return h == head &&


 492             SNode past = s.next;
 493             if (past != null && past.isCancelled())
 494                 past = past.next;
 495 
 496             // Absorb cancelled nodes at head
 497             SNode p;
 498             while ((p = head) != null && p != past && p.isCancelled())
 499                 casHead(p, p.next);
 500 
 501             // Unsplice embedded nodes
 502             while (p != null && p != past) {
 503                 SNode n = p.next;
 504                 if (n != null && n.isCancelled())
 505                     p.casNext(n, n.next);
 506                 else
 507                     p = n;
 508             }
 509         }
 510 
 511         // Unsafe mechanics
 512         private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
 513         private static final long HEAD;
 514         static {
 515             try {
 516                 HEAD = U.objectFieldOffset
 517                     (TransferStack.class.getDeclaredField("head"));
 518             } catch (ReflectiveOperationException e) {
 519                 throw new Error(e);
 520             }
 521         }
 522     }
 523 
 524     /** Dual Queue */
 525     static final class TransferQueue<E> extends Transferer<E> {
 526         /*
 527          * This extends Scherer-Scott dual queue algorithm, differing,
 528          * among other ways, by using modes within nodes rather than
 529          * marked pointers. The algorithm is a little simpler than
 530          * that for stacks because fulfillers do not need explicit
 531          * nodes, and matching is done by CAS'ing QNode.item field
 532          * from non-null to null (for put) or vice versa (for take).


 558              * Tries to cancel by CAS'ing ref to this as item.
 559              */
 560             void tryCancel(Object cmp) {
 561                 U.compareAndSwapObject(this, ITEM, cmp, this);
 562             }
 563 
 564             boolean isCancelled() {
 565                 return item == this;
 566             }
 567 
 568             /**
 569              * Returns true if this node is known to be off the queue
 570              * because its next pointer has been forgotten due to
 571              * an advanceHead operation.
 572              */
 573             boolean isOffList() {
 574                 return next == this;
 575             }
 576 
 577             // Unsafe mechanics
 578             private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
 579             private static final long ITEM;
 580             private static final long NEXT;
 581 
 582             static {
 583                 try {
 584                     ITEM = U.objectFieldOffset
 585                         (QNode.class.getDeclaredField("item"));
 586                     NEXT = U.objectFieldOffset
 587                         (QNode.class.getDeclaredField("next"));
 588                 } catch (ReflectiveOperationException e) {
 589                     throw new Error(e);
 590                 }
 591             }
 592         }
 593 
 594         /** Head of queue */
 595         transient volatile QNode head;
 596         /** Tail of queue */
 597         transient volatile QNode tail;
 598         /**


 800                 }
 801                 QNode dp = cleanMe;
 802                 if (dp != null) {    // Try unlinking previous cancelled node
 803                     QNode d = dp.next;
 804                     QNode dn;
 805                     if (d == null ||               // d is gone or
 806                         d == dp ||                 // d is off list or
 807                         !d.isCancelled() ||        // d not cancelled or
 808                         (d != t &&                 // d not tail and
 809                          (dn = d.next) != null &&  //   has successor
 810                          dn != d &&                //   that is on list
 811                          dp.casNext(d, dn)))       // d unspliced
 812                         casCleanMe(dp, null);
 813                     if (dp == pred)
 814                         return;      // s is already saved node
 815                 } else if (casCleanMe(null, pred))
 816                     return;          // Postpone cleaning s
 817             }
 818         }
 819 
 820         private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
 821         private static final long HEAD;
 822         private static final long TAIL;
 823         private static final long CLEANME;
 824         static {
 825             try {
 826                 HEAD = U.objectFieldOffset
 827                     (TransferQueue.class.getDeclaredField("head"));
 828                 TAIL = U.objectFieldOffset
 829                     (TransferQueue.class.getDeclaredField("tail"));
 830                 CLEANME = U.objectFieldOffset
 831                     (TransferQueue.class.getDeclaredField("cleanMe"));
 832             } catch (ReflectiveOperationException e) {
 833                 throw new Error(e);
 834             }
 835         }
 836     }
 837 
 838     /**
 839      * The transferer. Set only in constructor, but cannot be declared
 840      * as final without further complicating serialization.  Since