mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 06:14:49 +02:00
6546236: Thread interrupt() of Thread.sleep() can be lost on Solaris due to race with signal handler
Reviewed-by: dholmes, dcubed
This commit is contained in:
parent
a9868648e6
commit
eff08434da
13 changed files with 180 additions and 467 deletions
|
@ -1451,7 +1451,7 @@ void os::Linux::fast_thread_clock_init() {
|
|||
}
|
||||
|
||||
jlong os::javaTimeNanos() {
|
||||
if (Linux::supports_monotonic_clock()) {
|
||||
if (os::supports_monotonic_clock()) {
|
||||
struct timespec tp;
|
||||
int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
assert(status == 0, "gettime error");
|
||||
|
@ -1467,7 +1467,7 @@ jlong os::javaTimeNanos() {
|
|||
}
|
||||
|
||||
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
||||
if (Linux::supports_monotonic_clock()) {
|
||||
if (os::supports_monotonic_clock()) {
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
|
||||
// CLOCK_MONOTONIC - amount of time since some arbitrary point in the past
|
||||
|
@ -3795,85 +3795,6 @@ size_t os::read(int fd, void *buf, unsigned int nBytes) {
|
|||
return ::read(fd, buf, nBytes);
|
||||
}
|
||||
|
||||
// TODO-FIXME: reconcile Solaris' os::sleep with the linux variation.
|
||||
// Solaris uses poll(), linux uses park().
|
||||
// Poll() is likely a better choice, assuming that Thread.interrupt()
|
||||
// generates a SIGUSRx signal. Note that SIGUSR1 can interfere with
|
||||
// SIGSEGV, see 4355769.
|
||||
|
||||
int os::sleep(Thread* thread, jlong millis, bool interruptible) {
|
||||
assert(thread == Thread::current(), "thread consistency check");
|
||||
|
||||
ParkEvent * const slp = thread->_SleepEvent ;
|
||||
slp->reset() ;
|
||||
OrderAccess::fence() ;
|
||||
|
||||
if (interruptible) {
|
||||
jlong prevtime = javaTimeNanos();
|
||||
|
||||
for (;;) {
|
||||
if (os::is_interrupted(thread, true)) {
|
||||
return OS_INTRPT;
|
||||
}
|
||||
|
||||
jlong newtime = javaTimeNanos();
|
||||
|
||||
if (newtime - prevtime < 0) {
|
||||
// time moving backwards, should only happen if no monotonic clock
|
||||
// not a guarantee() because JVM should not abort on kernel/glibc bugs
|
||||
assert(!Linux::supports_monotonic_clock(), "time moving backwards");
|
||||
} else {
|
||||
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
|
||||
}
|
||||
|
||||
if(millis <= 0) {
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
prevtime = newtime;
|
||||
|
||||
{
|
||||
assert(thread->is_Java_thread(), "sanity check");
|
||||
JavaThread *jt = (JavaThread *) thread;
|
||||
ThreadBlockInVM tbivm(jt);
|
||||
OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
|
||||
|
||||
jt->set_suspend_equivalent();
|
||||
// cleared by handle_special_suspend_equivalent_condition() or
|
||||
// java_suspend_self() via check_and_wait_while_suspended()
|
||||
|
||||
slp->park(millis);
|
||||
|
||||
// were we externally suspended while we were waiting?
|
||||
jt->check_and_wait_while_suspended();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||
jlong prevtime = javaTimeNanos();
|
||||
|
||||
for (;;) {
|
||||
// It'd be nice to avoid the back-to-back javaTimeNanos() calls on
|
||||
// the 1st iteration ...
|
||||
jlong newtime = javaTimeNanos();
|
||||
|
||||
if (newtime - prevtime < 0) {
|
||||
// time moving backwards, should only happen if no monotonic clock
|
||||
// not a guarantee() because JVM should not abort on kernel/glibc bugs
|
||||
assert(!Linux::supports_monotonic_clock(), "time moving backwards");
|
||||
} else {
|
||||
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
|
||||
}
|
||||
|
||||
if(millis <= 0) break ;
|
||||
|
||||
prevtime = newtime;
|
||||
slp->park(millis);
|
||||
}
|
||||
return OS_OK ;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Short sleep, direct OS call.
|
||||
//
|
||||
|
@ -4226,50 +4147,6 @@ static void do_resume(OSThread* osthread) {
|
|||
guarantee(osthread->sr.is_running(), "Must be running!");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// interrupt support
|
||||
|
||||
void os::interrupt(Thread* thread) {
|
||||
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
|
||||
if (!osthread->interrupted()) {
|
||||
osthread->set_interrupted(true);
|
||||
// More than one thread can get here with the same value of osthread,
|
||||
// resulting in multiple notifications. We do, however, want the store
|
||||
// to interrupted() to be visible to other threads before we execute unpark().
|
||||
OrderAccess::fence();
|
||||
ParkEvent * const slp = thread->_SleepEvent ;
|
||||
if (slp != NULL) slp->unpark() ;
|
||||
}
|
||||
|
||||
// For JSR166. Unpark even if interrupt status already was set
|
||||
if (thread->is_Java_thread())
|
||||
((JavaThread*)thread)->parker()->unpark();
|
||||
|
||||
ParkEvent * ev = thread->_ParkEvent ;
|
||||
if (ev != NULL) ev->unpark() ;
|
||||
|
||||
}
|
||||
|
||||
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
||||
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
|
||||
bool interrupted = osthread->interrupted();
|
||||
|
||||
if (interrupted && clear_interrupted) {
|
||||
osthread->set_interrupted(false);
|
||||
// consider thread->_SleepEvent->reset() ... optional optimization
|
||||
}
|
||||
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// signal handling (except suspend/resume)
|
||||
|
||||
|
@ -4787,7 +4664,7 @@ void os::init(void) {
|
|||
fatal(err_msg("pthread_condattr_init: %s", strerror(status)));
|
||||
}
|
||||
// Only set the clock if CLOCK_MONOTONIC is available
|
||||
if (Linux::supports_monotonic_clock()) {
|
||||
if (os::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" \
|
||||
|
@ -5618,7 +5495,7 @@ static struct timespec* compute_abstime(timespec* abstime, jlong millis) {
|
|||
seconds = 50000000;
|
||||
}
|
||||
|
||||
if (os::Linux::supports_monotonic_clock()) {
|
||||
if (os::supports_monotonic_clock()) {
|
||||
struct timespec now;
|
||||
int status = os::Linux::clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
assert_status(status == 0, status, "clock_gettime");
|
||||
|
@ -5835,7 +5712,7 @@ static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) {
|
|||
assert (time > 0, "convertTime");
|
||||
time_t max_secs = 0;
|
||||
|
||||
if (!os::Linux::supports_monotonic_clock() || isAbsolute) {
|
||||
if (!os::supports_monotonic_clock() || isAbsolute) {
|
||||
struct timeval now;
|
||||
int status = gettimeofday(&now, NULL);
|
||||
assert(status == 0, "gettimeofday");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue