< prev index next >
src/os/posix/vm/os_posix.cpp
Print this page
*** 29,45 ****
#include "runtime/interfaceSupport.hpp"
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
! #include <signal.h>
! #include <unistd.h>
! #include <sys/resource.h>
! #include <sys/utsname.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
// Todo: provide a os::get_max_process_id() or similar. Number of processes
// may have been configured, can be read more accurately from proc fs etc.
#ifndef MAX_PID
#define MAX_PID INT_MAX
--- 29,46 ----
#include "runtime/interfaceSupport.hpp"
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
! #include <dlfcn.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
+ #include <sys/resource.h>
+ #include <sys/utsname.h>
+ #include <time.h>
+ #include <unistd.h>
// Todo: provide a os::get_max_process_id() or similar. Number of processes
// may have been configured, can be read more accurately from proc fs etc.
#ifndef MAX_PID
#define MAX_PID INT_MAX
*** 1392,1396 ****
--- 1393,1962 ----
}
}
}
#endif // __APPLE__
+
+
+ // Shared pthread_mutex/cond based PlatformEvent implementation.
+ // Not currently usable by Solaris
+
+ #ifndef SOLARIS
+
+ // Shared condattr object for use with relative timed-waits. Will be associated
+ // with CLOCK_MONOTONIC if available to avoid issues with time-of-day changes,
+ // but otherwise whatever default is used by the platform - generally the
+ // time-of-day clock
+ static pthread_condattr_t _condAttr[1];
+
+ // Shared mutexattr to explicitly set the type to PTHREAD_MUTEX_NORMAL as not
+ // all systems (e.g. FreeBSD) map the default to "normal".
+ static pthread_mutexattr_t _mutexAttr[1];
+
+ // common basic initialization that is always supported
+ static void pthread_init_common(void) {
+ int status;
+ if ((status = pthread_condattr_init(_condAttr)) != 0) {
+ fatal("pthread_condattr_init: %s", os::strerror(status));
+ }
+ if ((status = pthread_mutexattr_init(_mutexAttr)) != 0) {
+ fatal("pthread_mutexattr_init: %s", os::strerror(status));
+ }
+ if ((status = pthread_mutexattr_settype(_mutexAttr, PTHREAD_MUTEX_NORMAL)) != 0) {
+ fatal("pthread_mutexattr_settype: %s", os::strerror(status));
+ }
+ }
+
+ // Not all POSIX types and API's are available on all notionally "posix"
+ // platforms. If we have build-time support then we will check for actual
+ // runtime support via dlopen/dlsym lookup. This allows for running on an
+ // older OS version compared to the build platform. But if there is no
+ // build time support then there can not be any runtime support as we do not
+ // know what the runtime types would be (for example clockid_t might be an
+ // int or int64_t.
+ //
+ #ifdef SUPPORTS_CLOCK_MONOTONIC
+
+ // This means we have clockid_t, clock_gettime et al and CLOCK_MONOTONIC
+
+ static int (*_clock_gettime)(clockid_t, struct timespec *);
+ static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t);
+
+ static bool _use_clock_monotonic_condattr;
+
+ // determine what POSIX API's are present and do appropriate
+ // configuration
+ void os::Posix::init(void) {
+
+ // NOTE: no logging available when this is called. Put logging
+ // statements in init_2().
+
+ // copied from os::Linux::clock_init(). The duplication is temporary.
+
+ // 1. Check for CLOCK_MONOTONIC support
+
+ void* handle = NULL;
+
+ // For linux we need librt, for other OS we can find
+ // this function in regular libc
+ #ifdef NEEDS_LIBRT
+ // we do dlopen's in this particular order due to bug in linux
+ // dynamical loader (see 6348968) leading to crash on exit
+ handle = dlopen("librt.so.1", RTLD_LAZY);
+ if (handle == NULL) {
+ handle = dlopen("librt.so", RTLD_LAZY);
+ }
+ #endif
+
+ if (handle == NULL) {
+ handle = RTLD_DEFAULT;
+ }
+
+ _clock_gettime = NULL;
+
+ int (*clock_getres_func)(clockid_t, struct timespec*) =
+ (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
+ int (*clock_gettime_func)(clockid_t, struct timespec*) =
+ (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
+ if (clock_getres_func != NULL && clock_gettime_func != NULL) {
+ // we assume that if both clock_gettime and clock_getres support
+ // CLOCK_MONOTONIC then the OS provides true high-res monotonic clock
+ struct timespec res;
+ struct timespec tp;
+ if (clock_getres_func(CLOCK_MONOTONIC, &res) == 0 &&
+ clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
+ // yes, monotonic clock is supported
+ _clock_gettime = clock_gettime_func;
+ } else {
+ #ifdef NEEDS_LIBRT
+ // close librt if there is no monotonic clock
+ if (handle != RTLD_DEFAULT) {
+ dlclose(handle);
+ }
+ #endif
+ }
+ }
+
+ // 2. Check for pthread_condattr_setclock support
+
+ _pthread_condattr_setclock = NULL;
+
+ // libpthread is already loaded
+ int (*condattr_setclock_func)(pthread_condattr_t*, clockid_t) =
+ (int (*)(pthread_condattr_t*, clockid_t))dlsym(RTLD_DEFAULT,
+ "pthread_condattr_setclock");
+ if (condattr_setclock_func != NULL) {
+ _pthread_condattr_setclock = condattr_setclock_func;
+ }
+
+ // Now do general initialization
+
+ pthread_init_common();
+
+ int status;
+ if (_pthread_condattr_setclock != NULL &&
+ _clock_gettime != NULL) {
+ _use_clock_monotonic_condattr = true;
+
+ if ((status = _pthread_condattr_setclock(_condAttr, CLOCK_MONOTONIC)) != 0) {
+ if (status == EINVAL) {
+ _use_clock_monotonic_condattr = false;
+ warning("Unable to use monotonic clock with relative timed-waits" \
+ " - changes to the time-of-day clock may have adverse affects");
+ } else {
+ fatal("pthread_condattr_setclock: %s", os::strerror(status));
+ }
+ }
+ }
+ else {
+ _use_clock_monotonic_condattr = false;
+ }
+ }
+
+ void os::Posix::init_2(void) {
+ log_info(os)("Use of CLOCK_MONOTONIC is%s supported",
+ (_clock_gettime != NULL ? "" : " not"));
+ log_info(os)("Use of pthread_condattr_setclock is%s supported",
+ (_pthread_condattr_setclock != NULL ? "" : " not"));
+ log_info(os)("Relative timed-wait using pthread_cond_timedwait is associated with %s",
+ _use_clock_monotonic_condattr ? "CLOCK_MONOTONIC" : "the default clock");
+ }
+
+ #else // !SUPPORTS_CLOCK_MONOTONIC
+
+ void os::Posix::init(void) {
+ pthread_init_common();
+ }
+
+ void os::Posix::init_2(void) {
+ log_info(os)("Use of CLOCK_MONOTONIC is not supported");
+ log_info(os)("Use of pthread_condattr_setclock is not supported");
+ log_info(os)("Relative timed-wait using pthread_cond_timedwait is associated with the default clock");
+ }
+
+ #endif // SUPPORTS_CLOCK_MONOTONIC
+
+ os::PlatformEvent::PlatformEvent() {
+ int status = pthread_cond_init(_cond, _condAttr);
+ assert_status(status == 0, status, "cond_init");
+ status = pthread_mutex_init(_mutex, _mutexAttr);
+ assert_status(status == 0, status, "mutex_init");
+ _event = 0;
+ _nParked = 0;
+ }
+
+ // Utility to convert the given timeout to an absolute timespec
+ // (based on the appropriate clock) to use with pthread_cond_timewait.
+ // The clock queried here must be the clock used to manage the
+ // timeout of the condition variable.
+ //
+ // The passed in timeout value is either a relative time in nanoseconds
+ // or an absolute time in milliseconds. A relative timeout will be
+ // associated with CLOCK_MONOTONIC if available; otherwise, or if absolute,
+ // the default time-of-day clock will be used.
+
+ // Given time is a 64-bit value and the time_t used in the timespec is
+ // sometimes a signed-32-bit value we have to watch for overflow if times
+ // way in the future are given. Further on Solaris versions
+ // prior to 10 there is a restriction (see cond_timedwait) that the specified
+ // number of seconds, in abstime, is less than current_time + 100,000,000.
+ // As it will be over 20 years before "now + 100000000" will overflow we can
+ // ignore overflow and just impose a hard-limit on seconds using the value
+ // of "now + 100,000,000". This places a limit on the timeout of about 3.17
+ // years from "now".
+ //
+ #define MAX_SECS 100000000
+
+ static void to_abstime(timespec* abstime, jlong timeout, bool isAbsolute) {
+
+ if (timeout < 0)
+ timeout = 0;
+
+ time_t max_secs = 0;
+
+ #ifdef SUPPORTS_CLOCK_MONOTONIC
+
+ if (_use_clock_monotonic_condattr && !isAbsolute) {
+ // relative timeout in nanoseconds
+ jlong seconds = timeout / NANOUNITS;
+ timeout %= NANOUNITS; // remaining nanos
+
+ struct timespec now;
+ int status = _clock_gettime(CLOCK_MONOTONIC, &now);
+ assert_status(status == 0, status, "clock_gettime");
+
+ max_secs = now.tv_sec + MAX_SECS;
+ if (seconds >= MAX_SECS) {
+ // More seconds than we can add, so pin to max_secs
+ abstime->tv_sec = max_secs;
+ abstime->tv_nsec = 0;
+ }
+ else {
+ abstime->tv_sec = now.tv_sec + seconds;
+ long nsecs = now.tv_nsec + timeout;
+ if (nsecs >= NANOUNITS) { // overflow
+ abstime->tv_sec += 1;
+ nsecs -= NANOUNITS;
+ }
+ abstime->tv_nsec = nsecs;
+ }
+ }
+ else {
+
+ #else
+
+ { // match the block scope
+
+ #endif // SUPPORTS_CLOCK_MONOTONIC
+
+ // time-of-day clock is all we can reliably use
+ struct timeval now;
+ int status = gettimeofday(&now, NULL);
+ assert(status == 0, "gettimeofday");
+ max_secs = now.tv_sec + MAX_SECS;
+
+ if (isAbsolute) {
+ // absolute timeout in milliseconds
+ jlong seconds = timeout / MILLIUNITS;
+ timeout %= MILLIUNITS; // remaining millis
+
+ if (seconds >= max_secs) {
+ // Absolue seconds exceeds allow max, so pin to max_secs
+ abstime->tv_sec = max_secs;
+ abstime->tv_nsec = 0;
+ }
+ else {
+ abstime->tv_sec = seconds;
+ abstime->tv_nsec = timeout * (NANOUNITS/MILLIUNITS);
+ }
+ }
+ else {
+ // relative timeout in nanoseconds
+ jlong seconds = timeout / NANOUNITS;
+ timeout %= NANOUNITS; // remaining nanos
+
+ if (seconds >= MAX_SECS) {
+ // More seconds than we can add, so pin to max_secs
+ abstime->tv_sec = max_secs;
+ abstime->tv_nsec = 0;
+ }
+ else {
+ abstime->tv_sec = now.tv_sec + seconds;
+ jlong micros_left = timeout / (NANOUNITS/MICROUNITS);
+ long usec = now.tv_usec + micros_left;
+ if (usec >= MICROUNITS) { // overflow
+ abstime->tv_sec += 1;
+ usec -= MICROUNITS;
+ }
+ abstime->tv_nsec = usec * (NANOUNITS/MICROUNITS);
+ }
+ }
+ }
+
+ assert(abstime->tv_sec >= 0, "tv_sec < 0");
+ assert(abstime->tv_sec <= max_secs, "tv_sec > max_secs");
+ assert(abstime->tv_nsec >= 0, "tv_nsec < 0");
+ assert(abstime->tv_nsec < NANOSECS_PER_SEC, "tv_nsec >= nanos_per_sec");
+
+ }
+
+ // PlatformEvent
+ //
+ // Assumption:
+ // Only one parker can exist on an event, which is why we allocate
+ // them per-thread. Multiple unparkers can coexist.
+ //
+ // _event serves as a restricted-range semaphore.
+ // -1 : thread is blocked, i.e. there is a waiter
+ // 0 : neutral: thread is running or ready,
+ // could have been signaled after a wait started
+ // 1 : signaled - thread is running or ready
+ //
+ // Having three states allows for some detection of bad usage - see
+ // comments on unpark().
+
+ void os::PlatformEvent::park() { // AKA "down()"
+ // Transitions for _event:
+ // -1 => -1 : illegal
+ // 1 => 0 : pass - return immediately
+ // 0 => -1 : block; then set _event to 0 before returning
+
+ // Invariant: Only the thread associated with the PlatformEvent
+ // may call park().
+ assert(_nParked == 0, "invariant");
+
+ int v;
+
+ // atomically decrement _event
+ for (;;) {
+ v = _event;
+ if (Atomic::cmpxchg(v-1, &_event, v) == v) break;
+ }
+ guarantee(v >= 0, "invariant");
+
+ if (v == 0) { // Do this the hard way by blocking ...
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ guarantee(_nParked == 0, "invariant");
+ ++_nParked;
+ while (_event < 0) {
+ // OS-level "spurious wakeups" are ignored
+ status = pthread_cond_wait(_cond, _mutex);
+ assert_status(status == 0, status, "cond_wait");
+ }
+ --_nParked;
+
+ _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) {
+ // Transitions for _event:
+ // -1 => -1 : illegal
+ // 1 => 0 : pass - return immediately
+ // 0 => -1 : block; then set _event to 0 before returning
+
+ // Invariant: Only the thread associated with the Event/PlatformEvent
+ // may call park().
+ assert(_nParked == 0, "invariant");
+
+ int v;
+ // atomically decrement _event
+ for (;;) {
+ v = _event;
+ if (Atomic::cmpxchg(v-1, &_event, v) == v) break;
+ }
+ guarantee(v >= 0, "invariant");
+
+ if (v == 0) { // Do this the hard way by blocking ...
+ struct timespec abst;
+ to_abstime(&abst, millis * (NANOUNITS/MILLIUNITS), false);
+
+ int ret = OS_TIMEOUT;
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ guarantee(_nParked == 0, "invariant");
+ ++_nParked;
+
+ while (_event < 0) {
+ status = pthread_cond_timedwait(_cond, _mutex, &abst);
+ assert_status(status == 0 || status == ETIMEDOUT,
+ status, "cond_timedwait");
+ // OS-level "spurious wakeups" are ignored unless the archaic
+ // FilterSpuriousWakeups is set false. That flag should be obsoleted.
+ if (!FilterSpuriousWakeups) break;
+ if (status == ETIMEDOUT) break;
+ }
+ --_nParked;
+
+ if (_event >= 0) {
+ ret = OS_OK;
+ }
+
+ _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();
+ return ret;
+ }
+ return OS_OK;
+ }
+
+ void os::PlatformEvent::unpark() {
+ // Transitions for _event:
+ // 0 => 1 : just return
+ // 1 => 1 : just return
+ // -1 => either 0 or 1; must signal target thread
+ // That is, we can safely transition _event from -1 to either
+ // 0 or 1.
+ // 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 checking state conditions
+ // properly. This spurious return doesn't manifest itself in any user code
+ // but only in the correctly written condition checking loops of ObjectMonitor,
+ // Mutex/Monitor, Thread::muxAcquire and os::sleep
+
+ if (Atomic::xchg(1, &_event) >= 0) return;
+
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ int anyWaiters = _nParked;
+ assert(anyWaiters == 0 || anyWaiters == 1, "invariant");
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+
+ // 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 simply re-test the condition and re-park itself.
+ // This provides particular benefit if the underlying platform does not
+ // provide wait morphing.
+
+ if (anyWaiters != 0) {
+ status = pthread_cond_signal(_cond);
+ assert_status(status == 0, status, "cond_signal");
+ }
+ }
+
+ // JSR166 support
+
+ os::PlatformParker::PlatformParker() {
+ int status;
+ status = pthread_cond_init(&_cond[REL_INDEX], _condAttr);
+ assert_status(status == 0, status, "cond_init rel");
+ status = pthread_cond_init(&_cond[ABS_INDEX], NULL);
+ assert_status(status == 0, status, "cond_init abs");
+ status = pthread_mutex_init(_mutex, _mutexAttr);
+ assert_status(status == 0, status, "mutex_init");
+ _cur_index = -1; // mark as unused
+ }
+
+ // Parker::park decrements count if > 0, else does a condvar wait. Unpark
+ // sets count to 1 and signals condvar. Only one thread ever waits
+ // on the condvar. Contention seen when trying to park implies that someone
+ // is unparking you, so don't wait. And spurious returns are fine, so there
+ // is no need to track notifications.
+
+ void Parker::park(bool isAbsolute, jlong time) {
+
+ // Optional fast-path check:
+ // Return immediately if a permit is available.
+ // 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;
+
+ // Optional optimization -- avoid state transitions if there's
+ // an interrupt pending.
+ if (Thread::is_interrupted(thread, false)) {
+ return;
+ }
+
+ // Next, demultiplex/decode time arguments
+ struct timespec absTime;
+ if (time < 0 || (isAbsolute && time == 0)) { // don't wait at all
+ return;
+ }
+ if (time > 0) {
+ to_abstime(&absTime, time, isAbsolute);
+ }
+
+ // Enter safepoint region
+ // Beware of deadlocks such as 6317397.
+ // The per-thread Parker:: mutex is a classic leaf-lock.
+ // In particular a thread must never block on the Threads_lock while
+ // holding the Parker:: mutex. If safepoints are pending both the
+ // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
+ ThreadBlockInVM tbivm(jt);
+
+ // Don't wait if cannot get lock since interference arises from
+ // unparking. Also re-check interrupt before trying wait.
+ if (Thread::is_interrupted(thread, false) ||
+ pthread_mutex_trylock(_mutex) != 0) {
+ return;
+ }
+
+ int status;
+ if (_counter > 0) { // no wait needed
+ _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();
+ return;
+ }
+
+ OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
+ jt->set_suspend_equivalent();
+ // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
+
+ assert(_cur_index == -1, "invariant");
+ if (time == 0) {
+ _cur_index = REL_INDEX; // arbitrary choice when not timed
+ status = pthread_cond_wait(&_cond[_cur_index], _mutex);
+ assert_status(status == 0, status, "cond_timedwait");
+ }
+ else {
+ _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
+ status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime);
+ assert_status(status == 0 || status == ETIMEDOUT,
+ status, "cond_timedwait");
+ }
+ _cur_index = -1;
+
+ _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();
+ }
+ }
+
+ void Parker::unpark() {
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "invariant");
+ const int s = _counter;
+ _counter = 1;
+ // must capture correct index before unlocking
+ int index = _cur_index;
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "invariant");
+
+ // 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 simply re-test the condition and re-park itself.
+ // This provides particular benefit if the underlying platform does not
+ // provide wait morphing.
+
+ if (s < 1 && index != -1) {
+ // thread is definitely parked
+ status = pthread_cond_signal(&_cond[index]);
+ assert_status(status == 0, status, "invariant");
+ }
+ }
+
+
+ #endif // !SOLARIS
< prev index next >