--- a/hotspot/src/os/linux/vm/os_linux.cpp Tue Jan 22 05:55:04 2013 -0800
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Tue Jan 22 05:56:42 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -5001,11 +5001,12 @@
}
-- _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") ;
}
@@ -5068,40 +5069,44 @@
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) {
- // 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") ;
- if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
- 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");
- }
+ // 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");
+ int AnyWaiters = _nParked;
+ assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
+ if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
+ 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.
@@ -5187,13 +5192,14 @@
}
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");
@@ -5234,6 +5240,8 @@
_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;
}
@@ -5270,12 +5278,14 @@
_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() {