5370 // an appropriate loop. A litmus test for the correct |
5370 // an appropriate loop. A litmus test for the correct |
5371 // usage of park is the following: if park() were modified |
5371 // usage of park is the following: if park() were modified |
5372 // to immediately return 0 your code should still work, |
5372 // to immediately return 0 your code should still work, |
5373 // albeit degenerating to a spin loop. |
5373 // albeit degenerating to a spin loop. |
5374 // |
5374 // |
5375 // An interesting optimization for park() is to use a trylock() |
5375 // In a sense, park()-unpark() just provides more polite spinning |
5376 // to attempt to acquire the mutex. If the trylock() fails |
5376 // and polling with the key difference over naive spinning being |
5377 // then we know that a concurrent unpark() operation is in-progress. |
5377 // that a parked thread needs to be explicitly unparked() in order |
5378 // in that case the park() code could simply set _count to 0 |
5378 // to wake up and to poll the underlying condition. |
5379 // and return immediately. The subsequent park() operation *might* |
|
5380 // return immediately. That's harmless as the caller of park() is |
|
5381 // expected to loop. By using trylock() we will have avoided a |
|
5382 // avoided a context switch caused by contention on the per-thread mutex. |
|
5383 // |
5379 // |
5384 // TODO-FIXME: |
5380 // Assumption: |
5385 // 1. Reconcile Doug's JSR166 j.u.c park-unpark with the |
5381 // Only one parker can exist on an event, which is why we allocate |
5386 // objectmonitor implementation. |
5382 // them per-thread. Multiple unparkers can coexist. |
5387 // 2. Collapse the JSR166 parker event, and the |
|
5388 // objectmonitor ParkEvent into a single "Event" construct. |
|
5389 // 3. In park() and unpark() add: |
|
5390 // assert (Thread::current() == AssociatedWith). |
|
5391 // 4. add spurious wakeup injection on a -XX:EarlyParkReturn=N switch. |
|
5392 // 1-out-of-N park() operations will return immediately. |
|
5393 // |
5383 // |
5394 // _Event transitions in park() |
5384 // _Event transitions in park() |
5395 // -1 => -1 : illegal |
5385 // -1 => -1 : illegal |
5396 // 1 => 0 : pass - return immediately |
5386 // 1 => 0 : pass - return immediately |
5397 // 0 => -1 : block |
5387 // 0 => -1 : block; then set _Event to 0 before returning |
|
5388 // |
|
5389 // _Event transitions in unpark() |
|
5390 // 0 => 1 : just return |
|
5391 // 1 => 1 : just return |
|
5392 // -1 => either 0 or 1; must signal target thread |
|
5393 // That is, we can safely transition _Event from -1 to either |
|
5394 // 0 or 1. |
5398 // |
5395 // |
5399 // _Event serves as a restricted-range semaphore. |
5396 // _Event serves as a restricted-range semaphore. |
|
5397 // -1 : thread is blocked, i.e. there is a waiter |
|
5398 // 0 : neutral: thread is running or ready, |
|
5399 // could have been signaled after a wait started |
|
5400 // 1 : signaled - thread is running or ready |
5400 // |
5401 // |
5401 // Another possible encoding of _Event would be with |
5402 // Another possible encoding of _Event would be with |
5402 // explicit "PARKED" == 01b and "SIGNALED" == 10b bits. |
5403 // explicit "PARKED" == 01b and "SIGNALED" == 10b bits. |
5403 // |
5404 // |
5404 // TODO-FIXME: add DTRACE probes for: |
5405 // TODO-FIXME: add DTRACE probes for: |
5454 abstime->tv_nsec = usec * 1000; |
5455 abstime->tv_nsec = usec * 1000; |
5455 return abstime; |
5456 return abstime; |
5456 } |
5457 } |
5457 |
5458 |
5458 void os::PlatformEvent::park() { // AKA: down() |
5459 void os::PlatformEvent::park() { // AKA: down() |
|
5460 // Transitions for _Event: |
|
5461 // -1 => -1 : illegal |
|
5462 // 1 => 0 : pass - return immediately |
|
5463 // 0 => -1 : block; then set _Event to 0 before returning |
|
5464 |
5459 // Invariant: Only the thread associated with the Event/PlatformEvent |
5465 // Invariant: Only the thread associated with the Event/PlatformEvent |
5460 // may call park(). |
5466 // may call park(). |
5461 assert(_nParked == 0, "invariant"); |
5467 assert(_nParked == 0, "invariant"); |
5462 |
5468 |
5463 int v; |
5469 int v; |
5495 OrderAccess::fence(); |
5501 OrderAccess::fence(); |
5496 } |
5502 } |
5497 } |
5503 } |
5498 |
5504 |
5499 int os::PlatformEvent::park(jlong millis) { |
5505 int os::PlatformEvent::park(jlong millis) { |
|
5506 // Transitions for _Event: |
|
5507 // -1 => -1 : illegal |
|
5508 // 1 => 0 : pass - return immediately |
|
5509 // 0 => -1 : block; then set _Event to 0 before returning |
|
5510 |
5500 guarantee(_nParked == 0, "invariant"); |
5511 guarantee(_nParked == 0, "invariant"); |
5501 int v; |
5512 int v; |
5502 for (;;) { |
5513 for (;;) { |
5503 v = _Event; |
5514 v = _Event; |
5504 if (Atomic::cmpxchg(v-1, &_Event, v) == v) break; |
5515 if (Atomic::cmpxchg(v-1, &_Event, v) == v) break; |
5540 return ret; |
5551 return ret; |
5541 } |
5552 } |
5542 |
5553 |
5543 void os::PlatformEvent::unpark() { |
5554 void os::PlatformEvent::unpark() { |
5544 // Transitions for _Event: |
5555 // Transitions for _Event: |
5545 // 0 :=> 1 |
5556 // 0 => 1 : just return |
5546 // 1 :=> 1 |
5557 // 1 => 1 : just return |
5547 // -1 :=> either 0 or 1; must signal target thread |
5558 // -1 => either 0 or 1; must signal target thread |
5548 // That is, we can safely transition _Event from -1 to either |
5559 // That is, we can safely transition _Event from -1 to either |
5549 // 0 or 1. |
5560 // 0 or 1. |
5550 // See also: "Semaphores in Plan 9" by Mullender & Cox |
5561 // See also: "Semaphores in Plan 9" by Mullender & Cox |
5551 // |
5562 // |
5552 // Note: Forcing a transition from "-1" to "1" on an unpark() means |
5563 // Note: Forcing a transition from "-1" to "1" on an unpark() means |
5553 // that it will take two back-to-back park() calls for the owning |
5564 // that it will take two back-to-back park() calls for the owning |
5554 // thread to block. This has the benefit of forcing a spurious return |
5565 // thread to block. This has the benefit of forcing a spurious return |
5564 int AnyWaiters = _nParked; |
5575 int AnyWaiters = _nParked; |
5565 status = os::Solaris::mutex_unlock(_mutex); |
5576 status = os::Solaris::mutex_unlock(_mutex); |
5566 assert_status(status == 0, status, "mutex_unlock"); |
5577 assert_status(status == 0, status, "mutex_unlock"); |
5567 guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); |
5578 guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); |
5568 if (AnyWaiters != 0) { |
5579 if (AnyWaiters != 0) { |
5569 // We intentional signal *after* dropping the lock |
5580 // Note that we signal() *after* dropping the lock for "immortal" Events. |
5570 // to avoid a common class of futile wakeups. |
5581 // This is safe and avoids a common class of futile wakeups. In rare |
|
5582 // circumstances this can cause a thread to return prematurely from |
|
5583 // cond_{timed}wait() but the spurious wakeup is benign and the victim |
|
5584 // will simply re-test the condition and re-park itself. |
|
5585 // This provides particular benefit if the underlying platform does not |
|
5586 // provide wait morphing. |
5571 status = os::Solaris::cond_signal(_cond); |
5587 status = os::Solaris::cond_signal(_cond); |
5572 assert_status(status == 0, status, "cond_signal"); |
5588 assert_status(status == 0, status, "cond_signal"); |
5573 } |
5589 } |
5574 } |
5590 } |
5575 |
5591 |