8194860: Cleanup Semaphore timed-wait time calculations
Reviewed-by: coleenp, kbarrett
--- 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(unsigned int sec, int nsec) {
+bool OSXSemaphore::timedwait(int64_t millis) {
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;
}