8194860: Cleanup Semaphore timed-wait time calculations
authordholmes
Wed, 23 Jan 2019 21:17:51 -0500
changeset 53461 08d6edeb3145
parent 53460 65c813da7c65
child 53462 091ed8f2e7d7
8194860: Cleanup Semaphore timed-wait time calculations Reviewed-by: coleenp, kbarrett
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
--- 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;
 }