OpenJDK / portola / portola
changeset 53488:08d6edeb3145
8194860: Cleanup Semaphore timed-wait time calculations
Reviewed-by: coleenp, kbarrett
author | dholmes |
---|---|
date | Wed, 23 Jan 2019 21:17:51 -0500 |
parents | 65c813da7c65 |
children | 091ed8f2e7d7 |
files | src/hotspot/os/bsd/os_bsd.cpp src/hotspot/os/bsd/semaphore_bsd.cpp src/hotspot/os/bsd/semaphore_bsd.hpp src/hotspot/os/linux/os_linux.cpp src/hotspot/os/posix/os_posix.cpp src/hotspot/os/posix/os_posix.hpp src/hotspot/os/posix/semaphore_posix.cpp src/hotspot/os/posix/semaphore_posix.hpp src/hotspot/os/solaris/os_solaris.cpp |
diffstat | 9 files changed, 105 insertions(+), 93 deletions(-) [+] |
line wrap: on
line diff
--- a/src/hotspot/os/bsd/os_bsd.cpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/bsd/os_bsd.cpp Wed Jan 23 21:17:51 2019 -0500 @@ -2565,7 +2565,7 @@ // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED while (true) { - if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + if (sr_semaphore.timedwait(2)) { break; } else { // timeout @@ -2599,7 +2599,7 @@ while (true) { if (sr_notify(osthread) == 0) { - if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) { + if (sr_semaphore.timedwait(2)) { if (osthread->sr.is_running()) { return; }
--- a/src/hotspot/os/bsd/semaphore_bsd.cpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/bsd/semaphore_bsd.cpp Wed Jan 23 21:17:51 2019 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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 @@ -24,6 +24,7 @@ #include "precompiled/precompiled.hpp" #include "semaphore_bsd.hpp" +#include "runtime/os.hpp" #include "utilities/debug.hpp" #include <semaphore.h> @@ -65,29 +66,27 @@ assert(ret == KERN_SUCCESS, "Failed to wait on semaphore"); } -int64_t OSXSemaphore::currenttime() { - struct timeval tv; - gettimeofday(&tv, NULL); - return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000); +bool OSXSemaphore::trywait() { + return timedwait(0); } -bool OSXSemaphore::trywait() { - return timedwait(0, 0); -} +bool OSXSemaphore::timedwait(int64_t millis) { + kern_return_t kr = KERN_ABORTED; -bool OSXSemaphore::timedwait(unsigned int sec, int nsec) { - kern_return_t kr = KERN_ABORTED; + // kernel semaphores take a relative timeout mach_timespec_t waitspec; - waitspec.tv_sec = sec; - waitspec.tv_nsec = nsec; + int secs = millis / MILLIUNITS; + int nsecs = (millis % MILLIUNITS) * NANOSECS_PER_MILLISEC; + waitspec.tv_sec = secs; + waitspec.tv_nsec = nsecs; - int64_t starttime = currenttime(); + int64_t starttime = os::javaTimeMillis() * NANOSECS_PER_MILLISEC; kr = semaphore_timedwait(_semaphore, waitspec); while (kr == KERN_ABORTED) { - int64_t totalwait = (sec * NANOSECS_PER_SEC) + nsec; - - int64_t current = currenttime(); + // reduce the timout and try again + int64_t totalwait = millis * NANOSECS_PER_MILLISEC; + int64_t current = os::javaTimeMillis() * NANOSECS_PER_MILLISEC; int64_t passedtime = current - starttime; if (passedtime >= totalwait) {
--- a/src/hotspot/os/bsd/semaphore_bsd.hpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/bsd/semaphore_bsd.hpp Wed Jan 23 21:17:51 2019 -0500 @@ -50,10 +50,9 @@ void wait(); bool trywait(); - bool timedwait(unsigned int sec, int nsec); - private: - static int64_t currenttime(); + // wait until the given relative time elapses + bool timedwait(int64_t millis); }; typedef OSXSemaphore SemaphoreImpl;
--- a/src/hotspot/os/linux/os_linux.cpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/linux/os_linux.cpp Wed Jan 23 21:17:51 2019 -0500 @@ -2436,26 +2436,6 @@ return CAST_FROM_FN_PTR(void*, UserHandler); } -static struct timespec create_semaphore_timespec(unsigned int sec, int nsec) { - struct timespec ts; - // Semaphore's are always associated with CLOCK_REALTIME - os::Posix::clock_gettime(CLOCK_REALTIME, &ts); - // see os_posix.cpp for discussion on overflow checking - if (sec >= MAX_SECS) { - ts.tv_sec += MAX_SECS; - ts.tv_nsec = 0; - } else { - ts.tv_sec += sec; - ts.tv_nsec += nsec; - if (ts.tv_nsec >= NANOSECS_PER_SEC) { - ts.tv_nsec -= NANOSECS_PER_SEC; - ++ts.tv_sec; // note: this must be <= max_secs - } - } - - return ts; -} - extern "C" { typedef void (*sa_handler_t)(int); typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); @@ -4327,7 +4307,7 @@ // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED while (true) { - if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2 * NANOSECS_PER_MILLISEC))) { + if (sr_semaphore.timedwait(2)) { break; } else { // timeout @@ -4361,7 +4341,7 @@ while (true) { if (sr_notify(osthread) == 0) { - if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2 * NANOSECS_PER_MILLISEC))) { + if (sr_semaphore.timedwait(2)) { if (osthread->sr.is_running()) { return; }
--- a/src/hotspot/os/posix/os_posix.cpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/posix/os_posix.cpp Wed Jan 23 21:17:51 2019 -0500 @@ -1619,11 +1619,9 @@ } } - -// Shared pthread_mutex/cond based PlatformEvent implementation. -// Not currently usable by Solaris. - -#ifndef SOLARIS +// Shared clock/time and other supporting routines for pthread_mutex/cond +// initialization. This is enabled on Solaris but only some of the clock/time +// functionality is actually used there. // 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, @@ -1661,11 +1659,11 @@ // This means we have clockid_t, clock_gettime et al and CLOCK_MONOTONIC -static int (*_clock_gettime)(clockid_t, struct timespec *); -static int (*_clock_getres)(clockid_t, struct timespec *); -static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t); +static int (*_clock_gettime)(clockid_t, struct timespec *) = NULL; +static int (*_clock_getres)(clockid_t, struct timespec *) = NULL; +static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t) = NULL; -static bool _use_clock_monotonic_condattr; +static bool _use_clock_monotonic_condattr = false; // Exported clock functionality @@ -1707,9 +1705,6 @@ handle = RTLD_DEFAULT; } - _clock_gettime = NULL; - _clock_getres = 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*) = @@ -1736,8 +1731,6 @@ // 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, @@ -1750,6 +1743,7 @@ pthread_init_common(); +#ifndef SOLARIS int status; if (_pthread_condattr_setclock != NULL && _clock_gettime != NULL) { if ((status = _pthread_condattr_setclock(_condAttr, CLOCK_MONOTONIC)) != 0) { @@ -1763,18 +1757,20 @@ } else { _use_clock_monotonic_condattr = true; } - } else { - _use_clock_monotonic_condattr = false; } +#endif // !SOLARIS + } void os::Posix::init_2(void) { +#ifndef SOLARIS 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"); +#endif // !SOLARIS } #else // !SUPPORTS_CLOCK_MONOTONIC @@ -1784,30 +1780,25 @@ } void os::Posix::init_2(void) { +#ifndef SOLARIS 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 // !SOLARIS } #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. +// (based on the appropriate clock) to use with pthread_cond_timewait, +// and sem_timedwait(). // The clock queried here must be the clock used to manage the -// timeout of the condition variable. +// timeout of the condition variable or semaphore. // // 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, +// associated with CLOCK_MONOTONIC if available, unless the real-time clock +// is explicitly requested; 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 @@ -1824,7 +1815,7 @@ // Calculate a new absolute time that is "timeout" nanoseconds from "now". // "unit" indicates the unit of "now_part_sec" (may be nanos or micros depending -// on which clock is being used). +// on which clock API is being used). static void calc_rel_time(timespec* abstime, jlong timeout, jlong now_sec, jlong now_part_sec, jlong unit) { time_t max_secs = now_sec + MAX_SECS; @@ -1849,6 +1840,7 @@ // Unpack the given deadline in milliseconds since the epoch, into the given timespec. // The current time in seconds is also passed in to enforce an upper bound as discussed above. +// This is only used with gettimeofday, when clock_gettime is not available. static void unpack_abs_time(timespec* abstime, jlong deadline, jlong now_sec) { time_t max_secs = now_sec + MAX_SECS; @@ -1865,7 +1857,18 @@ } } -static void to_abstime(timespec* abstime, jlong timeout, bool isAbsolute) { +static jlong millis_to_nanos(jlong millis) { + // We have to watch for overflow when converting millis to nanos, + // but if millis is that large then we will end up limiting to + // MAX_SECS anyway, so just do that here. + if (millis / MILLIUNITS > MAX_SECS) { + millis = jlong(MAX_SECS) * MILLIUNITS; + } + return millis * (NANOUNITS / MILLIUNITS); +} + +static void to_abstime(timespec* abstime, jlong timeout, + bool isAbsolute, bool isRealtime) { DEBUG_ONLY(int max_secs = MAX_SECS;) if (timeout < 0) { @@ -1874,9 +1877,14 @@ #ifdef SUPPORTS_CLOCK_MONOTONIC - if (_use_clock_monotonic_condattr && !isAbsolute) { + clockid_t clock = CLOCK_MONOTONIC; + // need to ensure we have a runtime check for clock_gettime support + if (!isAbsolute && _clock_gettime != NULL) { + if (!_use_clock_monotonic_condattr || isRealtime) { + clock = CLOCK_REALTIME; + } struct timespec now; - int status = _clock_gettime(CLOCK_MONOTONIC, &now); + int status = _clock_gettime(clock, &now); assert_status(status == 0, status, "clock_gettime"); calc_rel_time(abstime, timeout, now.tv_sec, now.tv_nsec, NANOUNITS); DEBUG_ONLY(max_secs += now.tv_sec;) @@ -1906,6 +1914,19 @@ assert(abstime->tv_nsec < NANOUNITS, "tv_nsec >= NANOUNITS"); } +// Create an absolute time 'millis' milliseconds in the future, using the +// real-time (time-of-day) clock. Used by PosixSemaphore. +void os::Posix::to_RTC_abstime(timespec* abstime, int64_t millis) { + to_abstime(abstime, millis_to_nanos(millis), + false /* not absolute */, + true /* use real-time clock */); +} + +// Shared pthread_mutex/cond based PlatformEvent implementation. +// Not currently usable by Solaris. + +#ifndef SOLARIS + // PlatformEvent // // Assumption: @@ -1921,6 +1942,15 @@ // Having three states allows for some detection of bad usage - see // comments on unpark(). +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; +} + void os::PlatformEvent::park() { // AKA "down()" // Transitions for _event: // -1 => -1 : illegal @@ -1982,13 +2012,7 @@ if (v == 0) { // Do this the hard way by blocking ... struct timespec abst; - // We have to watch for overflow when converting millis to nanos, - // but if millis is that large then we will end up limiting to - // MAX_SECS anyway, so just do that here. - if (millis / MILLIUNITS > MAX_SECS) { - millis = jlong(MAX_SECS) * MILLIUNITS; - } - to_abstime(&abst, millis * (NANOUNITS / MILLIUNITS), false); + to_abstime(&abst, millis_to_nanos(millis), false, false); int ret = OS_TIMEOUT; int status = pthread_mutex_lock(_mutex); @@ -2106,7 +2130,7 @@ return; } if (time > 0) { - to_abstime(&absTime, time, isAbsolute); + to_abstime(&absTime, time, isAbsolute, false); } // Enter safepoint region
--- a/src/hotspot/os/posix/os_posix.hpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/posix/os_posix.hpp Wed Jan 23 21:17:51 2019 -0500 @@ -132,6 +132,8 @@ static bool supports_monotonic_clock() { return false; } #endif + + static void to_RTC_abstime(timespec* abstime, int64_t millis); }; /*
--- a/src/hotspot/os/posix/semaphore_posix.cpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/posix/semaphore_posix.cpp Wed Jan 23 21:17:51 2019 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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 @@ -79,6 +79,12 @@ return ret == 0; } +bool PosixSemaphore::timedwait(int64_t millis) { + struct timespec ts; + os::Posix::to_RTC_abstime(&ts, millis); + return timedwait(ts); +} + bool PosixSemaphore::timedwait(struct timespec ts) { while (true) { int result = sem_timedwait(&_semaphore, &ts);
--- a/src/hotspot/os/posix/semaphore_posix.hpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/posix/semaphore_posix.hpp Wed Jan 23 21:17:51 2019 -0500 @@ -45,7 +45,10 @@ void wait(); bool trywait(); + // wait until the given absolute time is reached bool timedwait(struct timespec ts); + // wait until the given relative time elapses + bool timedwait(int64_t millis); }; typedef PosixSemaphore SemaphoreImpl;
--- a/src/hotspot/os/solaris/os_solaris.cpp Wed Jan 23 14:10:31 2019 -0800 +++ b/src/hotspot/os/solaris/os_solaris.cpp Wed Jan 23 21:17:51 2019 -0500 @@ -2011,13 +2011,6 @@ return CAST_FROM_FN_PTR(void*, UserHandler); } -static struct timespec create_semaphore_timespec(unsigned int sec, int nsec) { - struct timespec ts; - unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); - - return ts; -} - extern "C" { typedef void (*sa_handler_t)(int); typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); @@ -3493,7 +3486,7 @@ // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED while (true) { - if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2000 * NANOSECS_PER_MILLISEC))) { + if (sr_semaphore.timedwait(2000)) { break; } else { // timeout @@ -3527,7 +3520,7 @@ while (true) { if (sr_notify(osthread) == 0) { - if (sr_semaphore.timedwait(create_semaphore_timespec(0, 2 * NANOSECS_PER_MILLISEC))) { + if (sr_semaphore.timedwait(2)) { if (osthread->sr.is_running()) { return; } @@ -4112,6 +4105,9 @@ Solaris::_pthread_setname_np = // from 11.3 (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np"); } + + // Shared Posix initialization + os::Posix::init(); } // To install functions for atexit system call @@ -4218,6 +4214,9 @@ // Init pset_loadavg function pointer init_pset_getloadavg_ptr(); + // Shared Posix initialization + os::Posix::init_2(); + return JNI_OK; }