src/os/bsd/vm/os_bsd.cpp
Print this page
@@ -4089,15 +4089,16 @@
if (status == ETIMEDOUT) { status = EINTR; }
assert_status(status == 0 || status == EINTR, status, "cond_wait");
}
-- _nParked ;
- // In theory we could move the ST of 0 into _Event past the unlock(),
- // but then we'd need a MEMBAR after the ST.
_Event = 0 ;
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
}
guarantee (_Event >= 0, "invariant") ;
}
int os::PlatformEvent::park(jlong millis) {
@@ -4156,45 +4157,49 @@
}
_Event = 0 ;
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
assert (_nParked == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
return ret;
}
void os::PlatformEvent::unpark() {
- int v, AnyWaiters ;
- for (;;) {
- v = _Event ;
- if (v > 0) {
- // The LD of _Event could have reordered or be satisfied
- // by a read-aside from this processor's write buffer.
- // To avoid problems execute a barrier and then
- // ratify the value.
- OrderAccess::fence() ;
- if (_Event == v) return ;
- continue ;
- }
- if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
- }
- if (v < 0) {
+ // Transitions for _Event:
+ // 0 :=> 1
+ // 1 :=> 1
+ // -1 :=> either 0 or 1; must signal target thread
+ // That is, we can safely transition _Event from -1 to either
+ // 0 or 1. Forcing 1 is slightly more efficient for back-to-back
+ // unpark() calls.
+ // See also: "Semaphores in Plan 9" by Mullender & Cox
+ //
+ // Note: Forcing a transition from "-1" to "1" on an unpark() means
+ // that it will take two back-to-back park() calls for the owning
+ // thread to block. This has the benefit of forcing a spurious return
+ // from the first park() call after an unpark() call which will help
+ // shake out uses of park() and unpark() without condition variables.
+
+ if (Atomic::xchg(1, &_Event) >= 0) return;
+
// Wait for the thread associated with the event to vacate
int status = pthread_mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
- AnyWaiters = _nParked ;
- assert (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
+ int AnyWaiters = _nParked;
+ assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
- AnyWaiters = 0 ;
- pthread_cond_signal (_cond);
+ AnyWaiters = 0;
+ pthread_cond_signal(_cond);
}
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
if (AnyWaiters != 0) {
status = pthread_cond_signal(_cond);
assert_status(status == 0, status, "cond_signal");
}
- }
// Note that we signal() _after dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim will
@@ -4275,17 +4280,18 @@
assert(absTime->tv_nsec >= 0, "tv_nsec < 0");
assert(absTime->tv_nsec < NANOSECS_PER_SEC, "tv_nsec >= nanos_per_sec");
}
void Parker::park(bool isAbsolute, jlong time) {
+ // Ideally we'd do something useful while spinning, such
+ // as calling unpackTime().
+
// Optional fast-path check:
// Return immediately if a permit is available.
- if (_counter > 0) {
- _counter = 0 ;
- OrderAccess::fence();
- return ;
- }
+ // We depend on Atomic::xchg() having full barrier semantics
+ // since we are doing a lock-free update to _counter.
+ if (Atomic::xchg(0, &_counter) > 0) return;
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
JavaThread *jt = (JavaThread *)thread;
@@ -4322,10 +4328,12 @@
int status ;
if (_counter > 0) { // no wait needed
_counter = 0;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
OrderAccess::fence();
return;
}
#ifdef ASSERT
@@ -4358,16 +4366,18 @@
#endif
_counter = 0 ;
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
+ OrderAccess::fence();
+
// If externally suspended while waiting, re-suspend
if (jt->handle_special_suspend_equivalent_condition()) {
jt->java_suspend_self();
}
-
- OrderAccess::fence();
}
void Parker::unpark() {
int s, status ;
status = pthread_mutex_lock(_mutex);