4563 Millis -= prd ; |
4563 Millis -= prd ; |
4564 } |
4564 } |
4565 } |
4565 } |
4566 v = _Event ; |
4566 v = _Event ; |
4567 _Event = 0 ; |
4567 _Event = 0 ; |
|
4568 // see comment at end of os::PlatformEvent::park() below: |
4568 OrderAccess::fence() ; |
4569 OrderAccess::fence() ; |
4569 // If we encounter a nearly simultanous timeout expiry and unpark() |
4570 // If we encounter a nearly simultanous timeout expiry and unpark() |
4570 // we return OS_OK indicating we awoke via unpark(). |
4571 // we return OS_OK indicating we awoke via unpark(). |
4571 // Implementor's license -- returning OS_TIMEOUT would be equally valid, however. |
4572 // Implementor's license -- returning OS_TIMEOUT would be equally valid, however. |
4572 return (v >= 0) ? OS_OK : OS_TIMEOUT ; |
4573 return (v >= 0) ? OS_OK : OS_TIMEOUT ; |
4600 guarantee (_Event >= 0, "invariant") ; |
4601 guarantee (_Event >= 0, "invariant") ; |
4601 } |
4602 } |
4602 |
4603 |
4603 void os::PlatformEvent::unpark() { |
4604 void os::PlatformEvent::unpark() { |
4604 guarantee (_ParkHandle != NULL, "Invariant") ; |
4605 guarantee (_ParkHandle != NULL, "Invariant") ; |
4605 int v ; |
4606 |
4606 for (;;) { |
4607 // Transitions for _Event: |
4607 v = _Event ; // Increment _Event if it's < 1. |
4608 // 0 :=> 1 |
4608 if (v > 0) { |
4609 // 1 :=> 1 |
4609 // If it's already signaled just return. |
4610 // -1 :=> either 0 or 1; must signal target thread |
4610 // The LD of _Event could have reordered or be satisfied |
4611 // That is, we can safely transition _Event from -1 to either |
4611 // by a read-aside from this processor's write buffer. |
4612 // 0 or 1. Forcing 1 is slightly more efficient for back-to-back |
4612 // To avoid problems execute a barrier and then |
4613 // unpark() calls. |
4613 // ratify the value. A degenerate CAS() would also work. |
4614 // See also: "Semaphores in Plan 9" by Mullender & Cox |
4614 // Viz., CAS (v+0, &_Event, v) == v). |
4615 // |
4615 OrderAccess::fence() ; |
4616 // Note: Forcing a transition from "-1" to "1" on an unpark() means |
4616 if (_Event == v) return ; |
4617 // that it will take two back-to-back park() calls for the owning |
4617 continue ; |
4618 // thread to block. This has the benefit of forcing a spurious return |
4618 } |
4619 // from the first park() call after an unpark() call which will help |
4619 if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ; |
4620 // shake out uses of park() and unpark() without condition variables. |
4620 } |
4621 |
4621 if (v < 0) { |
4622 if (Atomic::xchg(1, &_Event) >= 0) return; |
4622 ::SetEvent (_ParkHandle) ; |
4623 |
4623 } |
4624 ::SetEvent(_ParkHandle); |
4624 } |
4625 } |
4625 |
4626 |
4626 |
4627 |
4627 // JSR166 |
4628 // JSR166 |
4628 // ------------------------------------------------------- |
4629 // ------------------------------------------------------- |