Created
February 25, 2014 23:44
-
-
Save andi-bigswitch/9220407 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
changeset: 4744:fd506dce728a | |
user: dholmes | |
date: Thu Oct 03 18:41:44 2013 -0400 | |
summary: 6900441: PlatformEvent.park(millis) on Linux could still be affected by changes to the time-of-day clock | |
diff -r c50928ab9548 -r fd506dce728a src/os/linux/vm/os_linux.cpp | |
--- a/src/os/linux/vm/os_linux.cpp Thu Oct 03 06:04:42 2013 -0700 | |
+++ b/src/os/linux/vm/os_linux.cpp Thu Oct 03 18:41:44 2013 -0400 | |
@@ -144,6 +144,7 @@ | |
bool os::Linux::_supports_fast_thread_cpu_time = false; | |
const char * os::Linux::_glibc_version = NULL; | |
const char * os::Linux::_libpthread_version = NULL; | |
+pthread_condattr_t os::Linux::_condattr[1]; | |
static jlong initial_time_count=0; | |
@@ -1427,12 +1428,15 @@ | |
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) { | |
// yes, monotonic clock is supported | |
_clock_gettime = clock_gettime_func; | |
+ return; | |
} else { | |
// close librt if there is no monotonic clock | |
dlclose(handle); | |
} | |
} | |
} | |
+ warning("No monotonic clock was available - timed services may " \ | |
+ "be adversely affected if the time-of-day clock changes"); | |
} | |
#ifndef SYS_clock_getres | |
@@ -4493,6 +4497,26 @@ | |
Linux::clock_init(); | |
initial_time_count = os::elapsed_counter(); | |
+ | |
+ // pthread_condattr initialization for monotonic clock | |
+ int status; | |
+ pthread_condattr_t* _condattr = os::Linux::condAttr(); | |
+ if ((status = pthread_condattr_init(_condattr)) != 0) { | |
+ fatal(err_msg("pthread_condattr_init: %s", strerror(status))); | |
+ } | |
+ // Only set the clock if CLOCK_MONOTONIC is available | |
+ if (Linux::supports_monotonic_clock()) { | |
+ if ((status = pthread_condattr_setclock(_condattr, CLOCK_MONOTONIC)) != 0) { | |
+ if (status == EINVAL) { | |
+ warning("Unable to use monotonic clock with relative timed-waits" \ | |
+ " - changes to the time-of-day clock may have adverse affects"); | |
+ } else { | |
+ fatal(err_msg("pthread_condattr_setclock: %s", strerror(status))); | |
+ } | |
+ } | |
+ } | |
+ // else it defaults to CLOCK_REALTIME | |
+ | |
pthread_mutex_init(&dl_mutex, NULL); | |
// If the pagesize of the VM is greater than 8K determine the appropriate | |
@@ -5339,21 +5363,36 @@ | |
static struct timespec* compute_abstime(timespec* abstime, jlong millis) { | |
if (millis < 0) millis = 0; | |
- struct timeval now; | |
- int status = gettimeofday(&now, NULL); | |
- assert(status == 0, "gettimeofday"); | |
+ | |
jlong seconds = millis / 1000; | |
millis %= 1000; | |
if (seconds > 50000000) { // see man cond_timedwait(3T) | |
seconds = 50000000; | |
} | |
- abstime->tv_sec = now.tv_sec + seconds; | |
- long usec = now.tv_usec + millis * 1000; | |
- if (usec >= 1000000) { | |
- abstime->tv_sec += 1; | |
- usec -= 1000000; | |
- } | |
- abstime->tv_nsec = usec * 1000; | |
+ | |
+ if (os::Linux::supports_monotonic_clock()) { | |
+ struct timespec now; | |
+ int status = os::Linux::clock_gettime(CLOCK_MONOTONIC, &now); | |
+ assert_status(status == 0, status, "clock_gettime"); | |
+ abstime->tv_sec = now.tv_sec + seconds; | |
+ long nanos = now.tv_nsec + millis * NANOSECS_PER_MILLISEC; | |
+ if (nanos >= NANOSECS_PER_SEC) { | |
+ abstime->tv_sec += 1; | |
+ nanos -= NANOSECS_PER_SEC; | |
+ } | |
+ abstime->tv_nsec = nanos; | |
+ } else { | |
+ struct timeval now; | |
+ int status = gettimeofday(&now, NULL); | |
+ assert(status == 0, "gettimeofday"); | |
+ abstime->tv_sec = now.tv_sec + seconds; | |
+ long usec = now.tv_usec + millis * 1000; | |
+ if (usec >= 1000000) { | |
+ abstime->tv_sec += 1; | |
+ usec -= 1000000; | |
+ } | |
+ abstime->tv_nsec = usec * 1000; | |
+ } | |
return abstime; | |
} | |
@@ -5445,7 +5484,7 @@ | |
status = os::Linux::safe_cond_timedwait(_cond, _mutex, &abst); | |
if (status != 0 && WorkAroundNPTLTimedWaitHang) { | |
pthread_cond_destroy (_cond); | |
- pthread_cond_init (_cond, NULL) ; | |
+ pthread_cond_init (_cond, os::Linux::condAttr()) ; | |
} | |
assert_status(status == 0 || status == EINTR || | |
status == ETIME || status == ETIMEDOUT, | |
@@ -5546,32 +5585,50 @@ | |
static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) { | |
assert (time > 0, "convertTime"); | |
- | |
- struct timeval now; | |
- int status = gettimeofday(&now, NULL); | |
- assert(status == 0, "gettimeofday"); | |
- | |
- time_t max_secs = now.tv_sec + MAX_SECS; | |
- | |
- if (isAbsolute) { | |
- jlong secs = time / 1000; | |
- if (secs > max_secs) { | |
- absTime->tv_sec = max_secs; | |
+ time_t max_secs = 0; | |
+ | |
+ if (!os::Linux::supports_monotonic_clock() || isAbsolute) { | |
+ struct timeval now; | |
+ int status = gettimeofday(&now, NULL); | |
+ assert(status == 0, "gettimeofday"); | |
+ | |
+ max_secs = now.tv_sec + MAX_SECS; | |
+ | |
+ if (isAbsolute) { | |
+ jlong secs = time / 1000; | |
+ if (secs > max_secs) { | |
+ absTime->tv_sec = max_secs; | |
+ } else { | |
+ absTime->tv_sec = secs; | |
+ } | |
+ absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC; | |
+ } else { | |
+ jlong secs = time / NANOSECS_PER_SEC; | |
+ if (secs >= MAX_SECS) { | |
+ absTime->tv_sec = max_secs; | |
+ absTime->tv_nsec = 0; | |
+ } else { | |
+ absTime->tv_sec = now.tv_sec + secs; | |
+ absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000; | |
+ if (absTime->tv_nsec >= NANOSECS_PER_SEC) { | |
+ absTime->tv_nsec -= NANOSECS_PER_SEC; | |
+ ++absTime->tv_sec; // note: this must be <= max_secs | |
+ } | |
+ } | |
} | |
- else { | |
- absTime->tv_sec = secs; | |
- } | |
- absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC; | |
- } | |
- else { | |
+ } else { | |
+ // must be relative using monotonic clock | |
+ struct timespec now; | |
+ int status = os::Linux::clock_gettime(CLOCK_MONOTONIC, &now); | |
+ assert_status(status == 0, status, "clock_gettime"); | |
+ max_secs = now.tv_sec + MAX_SECS; | |
jlong secs = time / NANOSECS_PER_SEC; | |
if (secs >= MAX_SECS) { | |
absTime->tv_sec = max_secs; | |
absTime->tv_nsec = 0; | |
- } | |
- else { | |
+ } else { | |
absTime->tv_sec = now.tv_sec + secs; | |
- absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000; | |
+ absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_nsec; | |
if (absTime->tv_nsec >= NANOSECS_PER_SEC) { | |
absTime->tv_nsec -= NANOSECS_PER_SEC; | |
++absTime->tv_sec; // note: this must be <= max_secs | |
@@ -5650,16 +5707,20 @@ | |
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) { | |
- status = pthread_cond_wait (_cond, _mutex) ; | |
+ _cur_index = REL_INDEX; // arbitrary choice when not timed | |
+ status = pthread_cond_wait (&_cond[_cur_index], _mutex) ; | |
} else { | |
- status = os::Linux::safe_cond_timedwait (_cond, _mutex, &absTime) ; | |
+ _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX; | |
+ status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ; | |
if (status != 0 && WorkAroundNPTLTimedWaitHang) { | |
- pthread_cond_destroy (_cond) ; | |
- pthread_cond_init (_cond, NULL); | |
+ pthread_cond_destroy (&_cond[_cur_index]) ; | |
+ pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr()); | |
} | |
} | |
+ _cur_index = -1; | |
+ | |
assert_status(status == 0 || status == EINTR || | |
status == ETIME || status == ETIMEDOUT, | |
status, "cond_timedwait"); | |
@@ -5688,17 +5749,24 @@ | |
s = _counter; | |
_counter = 1; | |
if (s < 1) { | |
- if (WorkAroundNPTLTimedWaitHang) { | |
- status = pthread_cond_signal (_cond) ; | |
- assert (status == 0, "invariant") ; | |
+ // thread might be parked | |
+ if (_cur_index != -1) { | |
+ // thread is definitely parked | |
+ if (WorkAroundNPTLTimedWaitHang) { | |
+ status = pthread_cond_signal (&_cond[_cur_index]); | |
+ assert (status == 0, "invariant"); | |
status = pthread_mutex_unlock(_mutex); | |
- assert (status == 0, "invariant") ; | |
- } else { | |
+ assert (status == 0, "invariant"); | |
+ } else { | |
status = pthread_mutex_unlock(_mutex); | |
- assert (status == 0, "invariant") ; | |
- status = pthread_cond_signal (_cond) ; | |
- assert (status == 0, "invariant") ; | |
- } | |
+ assert (status == 0, "invariant"); | |
+ status = pthread_cond_signal (&_cond[_cur_index]); | |
+ assert (status == 0, "invariant"); | |
+ } | |
+ } else { | |
+ pthread_mutex_unlock(_mutex); | |
+ assert (status == 0, "invariant") ; | |
+ } | |
} else { | |
pthread_mutex_unlock(_mutex); | |
assert (status == 0, "invariant") ; | |
diff -r c50928ab9548 -r fd506dce728a src/os/linux/vm/os_linux.hpp | |
--- a/src/os/linux/vm/os_linux.hpp Thu Oct 03 06:04:42 2013 -0700 | |
+++ b/src/os/linux/vm/os_linux.hpp Thu Oct 03 18:41:44 2013 -0400 | |
@@ -207,6 +207,13 @@ | |
static jlong fast_thread_cpu_time(clockid_t clockid); | |
+ // pthread_cond clock suppport | |
+ private: | |
+ static pthread_condattr_t _condattr[1]; | |
+ | |
+ public: | |
+ static pthread_condattr_t* condAttr() { return _condattr; } | |
+ | |
// Stack repair handling | |
// none present | |
@@ -273,7 +280,7 @@ | |
public: | |
PlatformEvent() { | |
int status; | |
- status = pthread_cond_init (_cond, NULL); | |
+ status = pthread_cond_init (_cond, os::Linux::condAttr()); | |
assert_status(status == 0, status, "cond_init"); | |
status = pthread_mutex_init (_mutex, NULL); | |
assert_status(status == 0, status, "mutex_init"); | |
@@ -288,14 +295,19 @@ | |
void park () ; | |
void unpark () ; | |
int TryPark () ; | |
- int park (jlong millis) ; | |
+ int park (jlong millis) ; // relative timed-wait only | |
void SetAssociation (Thread * a) { _Assoc = a ; } | |
} ; | |
class PlatformParker : public CHeapObj<mtInternal> { | |
protected: | |
+ enum { | |
+ REL_INDEX = 0, | |
+ ABS_INDEX = 1 | |
+ }; | |
+ int _cur_index; // which cond is in use: -1, 0, 1 | |
pthread_mutex_t _mutex [1] ; | |
- pthread_cond_t _cond [1] ; | |
+ pthread_cond_t _cond [2] ; // one for relative times and one for abs. | |
public: // TODO-FIXME: make dtor private | |
~PlatformParker() { guarantee (0, "invariant") ; } | |
@@ -303,10 +315,13 @@ | |
public: | |
PlatformParker() { | |
int status; | |
- status = pthread_cond_init (_cond, NULL); | |
- assert_status(status == 0, status, "cond_init"); | |
+ status = pthread_cond_init (&_cond[REL_INDEX], os::Linux::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, NULL); | |
assert_status(status == 0, status, "mutex_init"); | |
+ _cur_index = -1; // mark as unused | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment