jdk/src/share/classes/java/util/concurrent/Exchanger.java
author duke
Sat, 01 Dec 2007 00:00:00 +0000
changeset 2 90ce3da70b43
child 5506 202f599c92aa
permissions -rw-r--r--
Initial load
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
 * This file is available under and governed by the GNU General Public
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
 * License version 2 only, as published by the Free Software Foundation.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
 * However, the following notice accompanied the original version of this
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
 * file:
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
 * Written by Doug Lea, Bill Scherer, and Michael Scott with
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
 * assistance from members of JCP JSR-166 Expert Group and released to
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
 * the public domain, as explained at
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
 * http://creativecommons.org/licenses/publicdomain
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
package java.util.concurrent;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
import java.util.concurrent.atomic.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import java.util.concurrent.locks.LockSupport;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 * A synchronization point at which threads can pair and swap elements
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * within pairs.  Each thread presents some object on entry to the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 * {@link #exchange exchange} method, matches with a partner thread,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 * and receives its partner's object on return.  An Exchanger may be
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 * viewed as a bidirectional form of a {@link SynchronousQueue}.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * Exchangers may be useful in applications such as genetic algorithms
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 * and pipeline designs.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
 * <p><b>Sample Usage:</b>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
 * Here are the highlights of a class that uses an {@code Exchanger}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
 * to swap buffers between threads so that the thread filling the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
 * buffer gets a freshly emptied one when it needs it, handing off the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
 * filled one to the thread emptying the buffer.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
 * <pre>{@code
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
 * class FillAndEmpty {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
 *   Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
 *   DataBuffer initialEmptyBuffer = ... a made-up type
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
 *   DataBuffer initialFullBuffer = ...
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
 *   class FillingLoop implements Runnable {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
 *     public void run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
 *       DataBuffer currentBuffer = initialEmptyBuffer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
 *       try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
 *         while (currentBuffer != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
 *           addToBuffer(currentBuffer);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
 *           if (currentBuffer.isFull())
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
 *             currentBuffer = exchanger.exchange(currentBuffer);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
 *         }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
 *       } catch (InterruptedException ex) { ... handle ... }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
 *     }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
 *   }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
 *   class EmptyingLoop implements Runnable {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
 *     public void run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
 *       DataBuffer currentBuffer = initialFullBuffer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
 *       try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
 *         while (currentBuffer != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
 *           takeFromBuffer(currentBuffer);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
 *           if (currentBuffer.isEmpty())
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
 *             currentBuffer = exchanger.exchange(currentBuffer);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
 *         }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
 *       } catch (InterruptedException ex) { ... handle ...}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
 *     }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
 *   }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
 *   void start() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
 *     new Thread(new FillingLoop()).start();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
 *     new Thread(new EmptyingLoop()).start();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
 *   }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
 * }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
 * }</pre>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
 * <p>Memory consistency effects: For each pair of threads that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
 * successfully exchange objects via an {@code Exchanger}, actions
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
 * prior to the {@code exchange()} in each thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
 * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
 * those subsequent to a return from the corresponding {@code exchange()}
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
 * in the other thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
 * @since 1.5
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
 * @author Doug Lea and Bill Scherer and Michael Scott
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
 * @param <V> The type of objects that may be exchanged
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
public class Exchanger<V> {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
     * Algorithm Description:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
     * The basic idea is to maintain a "slot", which is a reference to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
     * a Node containing both an Item to offer and a "hole" waiting to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
     * get filled in.  If an incoming "occupying" thread sees that the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
     * slot is null, it CAS'es (compareAndSets) a Node there and waits
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
     * for another to invoke exchange.  That second "fulfilling" thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
     * sees that the slot is non-null, and so CASes it back to null,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
     * also exchanging items by CASing the hole, plus waking up the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
     * occupying thread if it is blocked.  In each case CAS'es may
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
     * fail because a slot at first appears non-null but is null upon
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
     * CAS, or vice-versa.  So threads may need to retry these
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
     * actions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
     * This simple approach works great when there are only a few
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
     * threads using an Exchanger, but performance rapidly
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
     * deteriorates due to CAS contention on the single slot when
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
     * there are lots of threads using an exchanger.  So instead we use
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
     * an "arena"; basically a kind of hash table with a dynamically
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
     * varying number of slots, any one of which can be used by
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
     * threads performing an exchange.  Incoming threads pick slots
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
     * based on a hash of their Thread ids.  If an incoming thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
     * fails to CAS in its chosen slot, it picks an alternative slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
     * instead.  And similarly from there.  If a thread successfully
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
     * CASes into a slot but no other thread arrives, it tries
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
     * another, heading toward the zero slot, which always exists even
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
     * if the table shrinks.  The particular mechanics controlling this
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
     * are as follows:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
     * Waiting: Slot zero is special in that it is the only slot that
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
     * exists when there is no contention.  A thread occupying slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
     * zero will block if no thread fulfills it after a short spin.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
     * In other cases, occupying threads eventually give up and try
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
     * another slot.  Waiting threads spin for a while (a period that
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
     * should be a little less than a typical context-switch time)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
     * before either blocking (if slot zero) or giving up (if other
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
     * slots) and restarting.  There is no reason for threads to block
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
     * unless there are unlikely to be any other threads present.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
     * Occupants are mainly avoiding memory contention so sit there
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
     * quietly polling for a shorter period than it would take to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
     * block and then unblock them.  Non-slot-zero waits that elapse
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
     * because of lack of other threads waste around one extra
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
     * context-switch time per try, which is still on average much
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
     * faster than alternative approaches.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
     * Sizing: Usually, using only a few slots suffices to reduce
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
     * contention.  Especially with small numbers of threads, using
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
     * too many slots can lead to just as poor performance as using
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
     * too few of them, and there's not much room for error.  The
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
     * variable "max" maintains the number of slots actually in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
     * use.  It is increased when a thread sees too many CAS
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
     * failures.  (This is analogous to resizing a regular hash table
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
     * based on a target load factor, except here, growth steps are
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
     * just one-by-one rather than proportional.)  Growth requires
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
     * contention failures in each of three tried slots.  Requiring
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
     * multiple failures for expansion copes with the fact that some
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
     * failed CASes are not due to contention but instead to simple
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
     * races between two threads or thread pre-emptions occurring
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
     * between reading and CASing.  Also, very transient peak
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
     * contention can be much higher than the average sustainable
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
     * levels.  The max limit is decreased on average 50% of the times
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
     * that a non-slot-zero wait elapses without being fulfilled.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
     * Threads experiencing elapsed waits move closer to zero, so
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
     * eventually find existing (or future) threads even if the table
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
     * has been shrunk due to inactivity.  The chosen mechanics and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
     * thresholds for growing and shrinking are intrinsically
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
     * entangled with indexing and hashing inside the exchange code,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
     * and can't be nicely abstracted out.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
     * Hashing: Each thread picks its initial slot to use in accord
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
     * with a simple hashcode.  The sequence is the same on each
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
     * encounter by any given thread, but effectively random across
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
     * threads.  Using arenas encounters the classic cost vs quality
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
     * tradeoffs of all hash tables.  Here, we use a one-step FNV-1a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
     * hash code based on the current thread's Thread.getId(), along
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
     * with a cheap approximation to a mod operation to select an
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
     * index.  The downside of optimizing index selection in this way
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
     * is that the code is hardwired to use a maximum table size of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
     * 32.  But this value more than suffices for known platforms and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
     * applications.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
     * Probing: On sensed contention of a selected slot, we probe
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
     * sequentially through the table, analogously to linear probing
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
     * after collision in a hash table.  (We move circularly, in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
     * reverse order, to mesh best with table growth and shrinkage
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
     * rules.)  Except that to minimize the effects of false-alarms
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
     * and cache thrashing, we try the first selected slot twice
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
     * before moving.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
     * Padding: Even with contention management, slots are heavily
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
     * contended, so use cache-padding to avoid poor memory
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
     * performance.  Because of this, slots are lazily constructed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
     * only when used, to avoid wasting this space unnecessarily.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
     * While isolation of locations is not much of an issue at first
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
     * in an application, as time goes on and garbage-collectors
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
     * perform compaction, slots are very likely to be moved adjacent
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
     * to each other, which can cause much thrashing of cache lines on
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
     * MPs unless padding is employed.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
     * This is an improvement of the algorithm described in the paper
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
     * "A Scalable Elimination-based Exchange Channel" by William
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
     * Scherer, Doug Lea, and Michael Scott in Proceedings of SCOOL05
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
     * workshop.  Available at: http://hdl.handle.net/1802/2104
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
    /** The number of CPUs, for sizing and spin control */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
    private static final int NCPU = Runtime.getRuntime().availableProcessors();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
     * The capacity of the arena.  Set to a value that provides more
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
     * than enough space to handle contention.  On small machines
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
     * most slots won't be used, but it is still not wasted because
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
     * the extra space provides some machine-level address padding
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
     * to minimize interference with heavily CAS'ed Slot locations.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
     * And on very large machines, performance eventually becomes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
     * bounded by memory bandwidth, not numbers of threads/CPUs.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
     * This constant cannot be changed without also modifying
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
     * indexing and hashing algorithms.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
    private static final int CAPACITY = 32;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
     * The value of "max" that will hold all threads without
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
     * contention.  When this value is less than CAPACITY, some
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
     * otherwise wasted expansion can be avoided.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
    private static final int FULL =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
        Math.max(0, Math.min(CAPACITY, NCPU / 2) - 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
     * The number of times to spin (doing nothing except polling a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
     * memory location) before blocking or giving up while waiting to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
     * be fulfilled.  Should be zero on uniprocessors.  On
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
     * multiprocessors, this value should be large enough so that two
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
     * threads exchanging items as fast as possible block only when
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
     * one of them is stalled (due to GC or preemption), but not much
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
     * longer, to avoid wasting CPU resources.  Seen differently, this
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
     * value is a little over half the number of cycles of an average
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
     * context switch time on most systems.  The value here is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
     * approximately the average of those across a range of tested
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
     * systems.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
    private static final int SPINS = (NCPU == 1) ? 0 : 2000;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
     * The number of times to spin before blocking in timed waits.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
     * Timed waits spin more slowly because checking the time takes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
     * time.  The best value relies mainly on the relative rate of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
     * System.nanoTime vs memory accesses.  The value is empirically
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
     * derived to work well across a variety of systems.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
    private static final int TIMED_SPINS = SPINS / 20;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
     * Sentinel item representing cancellation of a wait due to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
     * interruption, timeout, or elapsed spin-waits.  This value is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
     * placed in holes on cancellation, and used as a return value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
     * from waiting methods to indicate failure to set or get hole.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
    private static final Object CANCEL = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
     * Value representing null arguments/returns from public
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
     * methods.  This disambiguates from internal requirement that
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
     * holes start out as null to mean they are not yet set.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
    private static final Object NULL_ITEM = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
     * Nodes hold partially exchanged data.  This class
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
     * opportunistically subclasses AtomicReference to represent the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
     * hole.  So get() returns hole, and compareAndSet CAS'es value
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
     * into hole.  This class cannot be parameterized as "V" because
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
     * of the use of non-V CANCEL sentinels.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
    private static final class Node extends AtomicReference<Object> {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
        /** The element offered by the Thread creating this node. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
        public final Object item;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
        /** The Thread waiting to be signalled; null until waiting. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
        public volatile Thread waiter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
         * Creates node with given item and empty hole.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
         * @param item the item
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
        public Node(Object item) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
            this.item = item;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
     * A Slot is an AtomicReference with heuristic padding to lessen
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
     * cache effects of this heavily CAS'ed location.  While the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
     * padding adds noticeable space, all slots are created only on
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
     * demand, and there will be more than one of them only when it
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
     * would improve throughput more than enough to outweigh using
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
     * extra space.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
    private static final class Slot extends AtomicReference<Object> {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
        // Improve likelihood of isolation on <= 64 byte cache lines
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
        long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
     * Slot array.  Elements are lazily initialized when needed.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
     * Declared volatile to enable double-checked lazy construction.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
    private volatile Slot[] arena = new Slot[CAPACITY];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
     * The maximum slot index being used.  The value sometimes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
     * increases when a thread experiences too many CAS contentions,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
     * and sometimes decreases when a spin-wait elapses.  Changes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
     * are performed only via compareAndSet, to avoid stale values
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
     * when a thread happens to stall right before setting.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
    private final AtomicInteger max = new AtomicInteger();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
     * Main exchange function, handling the different policy variants.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
     * Uses Object, not "V" as argument and return value to simplify
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
     * handling of sentinel values.  Callers from public methods decode
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
     * and cast accordingly.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
     * @param item the (non-null) item to exchange
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
     * @param timed true if the wait is timed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
     * @param nanos if timed, the maximum wait time
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
     * @return the other thread's item, or CANCEL if interrupted or timed out
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
    private Object doExchange(Object item, boolean timed, long nanos) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
        Node me = new Node(item);                 // Create in case occupying
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
        int index = hashIndex();                  // Index of current slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
        int fails = 0;                            // Number of CAS failures
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
        for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
            Object y;                             // Contents of current slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
            Slot slot = arena[index];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
            if (slot == null)                     // Lazily initialize slots
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
                createSlot(index);                // Continue loop to reread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
            else if ((y = slot.get()) != null &&  // Try to fulfill
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
                     slot.compareAndSet(y, null)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
                Node you = (Node)y;               // Transfer item
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
                if (you.compareAndSet(null, item)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
                    LockSupport.unpark(you.waiter);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
                    return you.item;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
                }                                 // Else cancelled; continue
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
            else if (y == null &&                 // Try to occupy
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
                     slot.compareAndSet(null, me)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
                if (index == 0)                   // Blocking wait for slot 0
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
                    return timed? awaitNanos(me, slot, nanos): await(me, slot);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
                Object v = spinWait(me, slot);    // Spin wait for non-0
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
                if (v != CANCEL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
                    return v;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
                me = new Node(item);              // Throw away cancelled node
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
                int m = max.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
                if (m > (index >>>= 1))           // Decrease index
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
                    max.compareAndSet(m, m - 1);  // Maybe shrink table
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
            else if (++fails > 1) {               // Allow 2 fails on 1st slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
                int m = max.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
                if (fails > 3 && m < FULL && max.compareAndSet(m, m + 1))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
                    index = m + 1;                // Grow on 3rd failed slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
                else if (--index < 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
                    index = m;                    // Circularly traverse
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
     * Returns a hash index for the current thread.  Uses a one-step
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
     * FNV-1a hash code (http://www.isthe.com/chongo/tech/comp/fnv/)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
     * based on the current thread's Thread.getId().  These hash codes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
     * have more uniform distribution properties with respect to small
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
     * moduli (here 1-31) than do other simple hashing functions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
     * <p>To return an index between 0 and max, we use a cheap
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
     * approximation to a mod operation, that also corrects for bias
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
     * due to non-power-of-2 remaindering (see {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
     * java.util.Random#nextInt}).  Bits of the hashcode are masked
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
     * with "nbits", the ceiling power of two of table size (looked up
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
     * in a table packed into three ints).  If too large, this is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
     * retried after rotating the hash by nbits bits, while forcing new
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
     * top bit to 0, which guarantees eventual termination (although
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
     * with a non-random-bias).  This requires an average of less than
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
     * 2 tries for all table sizes, and has a maximum 2% difference
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
     * from perfectly uniform slot probabilities when applied to all
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
     * possible hash codes for sizes less than 32.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
     * @return a per-thread-random index, 0 <= index < max
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
    private final int hashIndex() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
        long id = Thread.currentThread().getId();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
        int hash = (((int)(id ^ (id >>> 32))) ^ 0x811c9dc5) * 0x01000193;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
        int m = max.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
        int nbits = (((0xfffffc00  >> m) & 4) | // Compute ceil(log2(m+1))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
                     ((0x000001f8 >>> m) & 2) | // The constants hold
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
                     ((0xffff00f2 >>> m) & 1)); // a lookup table
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
        int index;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
        while ((index = hash & ((1 << nbits) - 1)) > m)       // May retry on
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
            hash = (hash >>> nbits) | (hash << (33 - nbits)); // non-power-2 m
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
        return index;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
     * Creates a new slot at given index.  Called only when the slot
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
     * appears to be null.  Relies on double-check using builtin
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
     * locks, since they rarely contend.  This in turn relies on the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
     * arena array being declared volatile.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
     * @param index the index to add slot at
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
    private void createSlot(int index) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
        // Create slot outside of lock to narrow sync region
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
        Slot newSlot = new Slot();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
        Slot[] a = arena;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
        synchronized (a) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
            if (a[index] == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
                a[index] = newSlot;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
     * Tries to cancel a wait for the given node waiting in the given
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
     * slot, if so, helping clear the node from its slot to avoid
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
     * garbage retention.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
     * @param node the waiting node
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
     * @param the slot it is waiting in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
     * @return true if successfully cancelled
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
    private static boolean tryCancel(Node node, Slot slot) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
        if (!node.compareAndSet(null, CANCEL))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
            return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
        if (slot.get() == node) // pre-check to minimize contention
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
            slot.compareAndSet(node, null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
        return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
    // Three forms of waiting. Each just different enough not to merge
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
    // code with others.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
     * Spin-waits for hole for a non-0 slot.  Fails if spin elapses
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
     * before hole filled.  Does not check interrupt, relying on check
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
     * in public exchange method to abort if interrupted on entry.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
     * @param node the waiting node
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
     * @return on success, the hole; on failure, CANCEL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
    private static Object spinWait(Node node, Slot slot) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
        int spins = SPINS;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
        for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
            Object v = node.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
            if (v != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
                return v;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
            else if (spins > 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
                --spins;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
            else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
                tryCancel(node, slot);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   471
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
     * Waits for (by spinning and/or blocking) and gets the hole
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
     * filled in by another thread.  Fails if interrupted before
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
     * hole filled.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
     * When a node/thread is about to block, it sets its waiter field
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
     * and then rechecks state at least one more time before actually
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
     * parking, thus covering race vs fulfiller noticing that waiter
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
     * is non-null so should be woken.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
     * Thread interruption status is checked only surrounding calls to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   483
     * park.  The caller is assumed to have checked interrupt status
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
     * on entry.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
     * @param node the waiting node
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
     * @return on success, the hole; on failure, CANCEL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
    private static Object await(Node node, Slot slot) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
        Thread w = Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
        int spins = SPINS;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
        for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
            Object v = node.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
            if (v != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
                return v;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
            else if (spins > 0)                 // Spin-wait phase
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
                --spins;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
            else if (node.waiter == null)       // Set up to block next
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
                node.waiter = w;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
            else if (w.isInterrupted())         // Abort on interrupt
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
                tryCancel(node, slot);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
            else                                // Block
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
                LockSupport.park(node);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   504
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
90ce3da70b43 Initial load
duke
parents:
diff changeset
   507
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   508
     * Waits for (at index 0) and gets the hole filled in by another
90ce3da70b43 Initial load
duke
parents:
diff changeset
   509
     * thread.  Fails if timed out or interrupted before hole filled.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   510
     * Same basic logic as untimed version, but a bit messier.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   511
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   512
     * @param node the waiting node
90ce3da70b43 Initial load
duke
parents:
diff changeset
   513
     * @param nanos the wait time
90ce3da70b43 Initial load
duke
parents:
diff changeset
   514
     * @return on success, the hole; on failure, CANCEL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   515
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   516
    private Object awaitNanos(Node node, Slot slot, long nanos) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   517
        int spins = TIMED_SPINS;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   518
        long lastTime = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   519
        Thread w = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   520
        for (;;) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   521
            Object v = node.get();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   522
            if (v != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   523
                return v;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   524
            long now = System.nanoTime();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   525
            if (w == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   526
                w = Thread.currentThread();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   527
            else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   528
                nanos -= now - lastTime;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
            lastTime = now;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
            if (nanos > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
                if (spins > 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   532
                    --spins;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   533
                else if (node.waiter == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   534
                    node.waiter = w;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   535
                else if (w.isInterrupted())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   536
                    tryCancel(node, slot);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   537
                else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   538
                    LockSupport.parkNanos(node, nanos);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   539
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   540
            else if (tryCancel(node, slot) && !w.isInterrupted())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   541
                return scanOnTimeout(node);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   542
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   543
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   544
90ce3da70b43 Initial load
duke
parents:
diff changeset
   545
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   546
     * Sweeps through arena checking for any waiting threads.  Called
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
     * only upon return from timeout while waiting in slot 0.  When a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   548
     * thread gives up on a timed wait, it is possible that a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   549
     * previously-entered thread is still waiting in some other
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
     * slot.  So we scan to check for any.  This is almost always
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
     * overkill, but decreases the likelihood of timeouts when there
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
     * are other threads present to far less than that in lock-based
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
     * exchangers in which earlier-arriving threads may still be
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
     * waiting on entry locks.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   555
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
     * @param node the waiting node
90ce3da70b43 Initial load
duke
parents:
diff changeset
   557
     * @return another thread's item, or CANCEL
90ce3da70b43 Initial load
duke
parents:
diff changeset
   558
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   559
    private Object scanOnTimeout(Node node) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   560
        Object y;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
        for (int j = arena.length - 1; j >= 0; --j) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   562
            Slot slot = arena[j];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   563
            if (slot != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   564
                while ((y = slot.get()) != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   565
                    if (slot.compareAndSet(y, null)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
                        Node you = (Node)y;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
                        if (you.compareAndSet(null, node.item)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
                            LockSupport.unpark(you.waiter);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   569
                            return you.item;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   570
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   572
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   573
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
        return CANCEL;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   576
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   577
90ce3da70b43 Initial load
duke
parents:
diff changeset
   578
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
     * Creates a new Exchanger.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
    public Exchanger() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   582
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   583
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   585
     * Waits for another thread to arrive at this exchange point (unless
90ce3da70b43 Initial load
duke
parents:
diff changeset
   586
     * the current thread is {@linkplain Thread#interrupt interrupted}),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
     * and then transfers the given object to it, receiving its object
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
     * in return.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   589
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   590
     * <p>If another thread is already waiting at the exchange point then
90ce3da70b43 Initial load
duke
parents:
diff changeset
   591
     * it is resumed for thread scheduling purposes and receives the object
90ce3da70b43 Initial load
duke
parents:
diff changeset
   592
     * passed in by the current thread.  The current thread returns immediately,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   593
     * receiving the object passed to the exchange by that other thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   594
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   595
     * <p>If no other thread is already waiting at the exchange then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   596
     * current thread is disabled for thread scheduling purposes and lies
90ce3da70b43 Initial load
duke
parents:
diff changeset
   597
     * dormant until one of two things happens:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   598
     * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   599
     * <li>Some other thread enters the exchange; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   600
     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the current
90ce3da70b43 Initial load
duke
parents:
diff changeset
   601
     * thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
     * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
     * <p>If the current thread:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   604
     * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   605
     * <li>has its interrupted status set on entry to this method; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
     * for the exchange,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
     * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
     * then {@link InterruptedException} is thrown and the current thread's
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
     * interrupted status is cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   611
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   612
     * @param x the object to exchange
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
     * @return the object provided by the other thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
     * @throws InterruptedException if the current thread was
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
     *         interrupted while waiting
90ce3da70b43 Initial load
duke
parents:
diff changeset
   616
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   617
    public V exchange(V x) throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
        if (!Thread.interrupted()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
            Object v = doExchange(x == null? NULL_ITEM : x, false, 0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   620
            if (v == NULL_ITEM)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   621
                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   622
            if (v != CANCEL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   623
                return (V)v;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   624
            Thread.interrupted(); // Clear interrupt status on IE throw
90ce3da70b43 Initial load
duke
parents:
diff changeset
   625
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   626
        throw new InterruptedException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   627
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   628
90ce3da70b43 Initial load
duke
parents:
diff changeset
   629
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   630
     * Waits for another thread to arrive at this exchange point (unless
90ce3da70b43 Initial load
duke
parents:
diff changeset
   631
     * the current thread is {@linkplain Thread#interrupt interrupted} or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   632
     * the specified waiting time elapses), and then transfers the given
90ce3da70b43 Initial load
duke
parents:
diff changeset
   633
     * object to it, receiving its object in return.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   634
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   635
     * <p>If another thread is already waiting at the exchange point then
90ce3da70b43 Initial load
duke
parents:
diff changeset
   636
     * it is resumed for thread scheduling purposes and receives the object
90ce3da70b43 Initial load
duke
parents:
diff changeset
   637
     * passed in by the current thread.  The current thread returns immediately,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   638
     * receiving the object passed to the exchange by that other thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   639
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   640
     * <p>If no other thread is already waiting at the exchange then the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   641
     * current thread is disabled for thread scheduling purposes and lies
90ce3da70b43 Initial load
duke
parents:
diff changeset
   642
     * dormant until one of three things happens:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   643
     * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   644
     * <li>Some other thread enters the exchange; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   645
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   646
     * the current thread; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   647
     * <li>The specified waiting time elapses.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   648
     * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   649
     * <p>If the current thread:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   650
     * <ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   651
     * <li>has its interrupted status set on entry to this method; or
90ce3da70b43 Initial load
duke
parents:
diff changeset
   652
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
90ce3da70b43 Initial load
duke
parents:
diff changeset
   653
     * for the exchange,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   654
     * </ul>
90ce3da70b43 Initial load
duke
parents:
diff changeset
   655
     * then {@link InterruptedException} is thrown and the current thread's
90ce3da70b43 Initial load
duke
parents:
diff changeset
   656
     * interrupted status is cleared.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   657
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   658
     * <p>If the specified waiting time elapses then {@link
90ce3da70b43 Initial load
duke
parents:
diff changeset
   659
     * TimeoutException} is thrown.  If the time is less than or equal
90ce3da70b43 Initial load
duke
parents:
diff changeset
   660
     * to zero, the method will not wait at all.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   661
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   662
     * @param x the object to exchange
90ce3da70b43 Initial load
duke
parents:
diff changeset
   663
     * @param timeout the maximum time to wait
90ce3da70b43 Initial load
duke
parents:
diff changeset
   664
     * @param unit the time unit of the <tt>timeout</tt> argument
90ce3da70b43 Initial load
duke
parents:
diff changeset
   665
     * @return the object provided by the other thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   666
     * @throws InterruptedException if the current thread was
90ce3da70b43 Initial load
duke
parents:
diff changeset
   667
     *         interrupted while waiting
90ce3da70b43 Initial load
duke
parents:
diff changeset
   668
     * @throws TimeoutException if the specified waiting time elapses
90ce3da70b43 Initial load
duke
parents:
diff changeset
   669
     *         before another thread enters the exchange
90ce3da70b43 Initial load
duke
parents:
diff changeset
   670
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   671
    public V exchange(V x, long timeout, TimeUnit unit)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   672
        throws InterruptedException, TimeoutException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   673
        if (!Thread.interrupted()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   674
            Object v = doExchange(x == null? NULL_ITEM : x,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   675
                                  true, unit.toNanos(timeout));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   676
            if (v == NULL_ITEM)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   677
                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   678
            if (v != CANCEL)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   679
                return (V)v;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   680
            if (!Thread.interrupted())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   681
                throw new TimeoutException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   682
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   683
        throw new InterruptedException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   684
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   685
}