364 |
|
*/ |
365 |
|
private int awaitDone(boolean timed, long nanos) |
366 |
|
throws InterruptedException { |
367 |
< |
final long deadline = timed ? System.nanoTime() + nanos : 0L; |
367 |
> |
// The code below is very delicate, to achieve these goals: |
368 |
> |
// - call nanoTime exactly once for each call to park |
369 |
> |
// - if nanos <= 0, return promptly without allocation or nanoTime |
370 |
> |
// - if nanos == Long.MIN_VALUE, don't underflow |
371 |
> |
// - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic |
372 |
> |
// and we suffer a spurious wakeup, we will do no worse than |
373 |
> |
// to park-spin for a while |
374 |
> |
long startTime = 0L; // Special value 0L means not yet parked |
375 |
|
WaitNode q = null; |
376 |
|
boolean queued = false; |
377 |
|
for (;;) { |
388 |
|
} |
389 |
|
else if (s == COMPLETING) // cannot time out yet |
390 |
|
Thread.yield(); |
391 |
< |
else if (q == null) |
391 |
> |
else if (q == null) { |
392 |
> |
if (timed && nanos <= 0L) |
393 |
> |
return s; |
394 |
|
q = new WaitNode(); |
395 |
+ |
} |
396 |
|
else if (!queued) |
397 |
|
queued = U.compareAndSwapObject(this, WAITERS, |
398 |
|
q.next = waiters, q); |
399 |
|
else if (timed) { |
400 |
< |
nanos = deadline - System.nanoTime(); |
401 |
< |
if (nanos <= 0L) { |
402 |
< |
removeWaiter(q); |
403 |
< |
return state; |
400 |
> |
final long parkNanos; |
401 |
> |
if (startTime == 0L) { // first time |
402 |
> |
startTime = System.nanoTime(); |
403 |
> |
if (startTime == 0L) |
404 |
> |
startTime = 1L; |
405 |
> |
parkNanos = nanos; |
406 |
> |
} else { |
407 |
> |
long elapsed = System.nanoTime() - startTime; |
408 |
> |
if (elapsed >= nanos) { |
409 |
> |
removeWaiter(q); |
410 |
> |
return state; |
411 |
> |
} |
412 |
> |
parkNanos = nanos - elapsed; |
413 |
|
} |
414 |
< |
LockSupport.parkNanos(this, nanos); |
414 |
> |
LockSupport.parkNanos(this, parkNanos); |
415 |
|
} |
416 |
|
else |
417 |
|
LockSupport.park(this); |