mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8072439: fix for 8047720 may need more work
Cleanup PeriodTask_lock usage. Also reviewed by varming@gmail.com. Co-authored-by: Carsten Varming <varming@gmail.com> Reviewed-by: dholmes, dcubed, mgronlun, coleenp
This commit is contained in:
parent
6465239986
commit
12cd46edc9
5 changed files with 59 additions and 40 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -421,9 +421,11 @@ void before_exit(JavaThread * thread) {
|
||||||
os::infinite_sleep();
|
os::infinite_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate watcher thread - must before disenrolling any periodic task
|
// Stop the WatcherThread. We do this before disenrolling various
|
||||||
if (PeriodicTask::num_tasks() > 0)
|
// PeriodicTasks to reduce the likelihood of races.
|
||||||
|
if (PeriodicTask::num_tasks() > 0) {
|
||||||
WatcherThread::stop();
|
WatcherThread::stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Print statistics gathered (profiling ...)
|
// Print statistics gathered (profiling ...)
|
||||||
if (Arguments::has_profile()) {
|
if (Arguments::has_profile()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -47,6 +47,8 @@ void PeriodicTask::print_intervals() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void PeriodicTask::real_time_tick(int delay_time) {
|
void PeriodicTask::real_time_tick(int delay_time) {
|
||||||
|
assert(Thread::current()->is_Watcher_thread(), "must be WatcherThread");
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (ProfilerCheckIntervals) {
|
if (ProfilerCheckIntervals) {
|
||||||
_ticks++;
|
_ticks++;
|
||||||
|
@ -60,6 +62,8 @@ void PeriodicTask::real_time_tick(int delay_time) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// The WatcherThread does not participate in the safepoint protocol
|
||||||
|
// for the PeriodicTask_lock because it is not a JavaThread.
|
||||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||||
int orig_num_tasks = _num_tasks;
|
int orig_num_tasks = _num_tasks;
|
||||||
|
|
||||||
|
@ -74,8 +78,7 @@ void PeriodicTask::real_time_tick(int delay_time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int PeriodicTask::time_to_wait() {
|
int PeriodicTask::time_to_wait() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
|
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||||
NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
|
||||||
|
|
||||||
if (_num_tasks == 0) {
|
if (_num_tasks == 0) {
|
||||||
return 0; // sleep until shutdown or a task is enrolled
|
return 0; // sleep until shutdown or a task is enrolled
|
||||||
|
@ -98,14 +101,19 @@ PeriodicTask::PeriodicTask(size_t interval_time) :
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask() {
|
PeriodicTask::~PeriodicTask() {
|
||||||
|
// This PeriodicTask may have already been disenrolled by a call
|
||||||
|
// to disenroll() before the PeriodicTask was deleted.
|
||||||
disenroll();
|
disenroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enroll could be called from a JavaThread, so we have to check for
|
// enroll the current PeriodicTask
|
||||||
* safepoint when taking the lock to avoid deadlocking */
|
|
||||||
void PeriodicTask::enroll() {
|
void PeriodicTask::enroll() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
|
// Follow normal safepoint aware lock enter protocol if the caller does
|
||||||
NULL : PeriodicTask_lock);
|
// not already own the PeriodicTask_lock. Otherwise, we don't try to
|
||||||
|
// enter it again because VM internal Mutexes do not support recursion.
|
||||||
|
//
|
||||||
|
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? NULL
|
||||||
|
: PeriodicTask_lock);
|
||||||
|
|
||||||
if (_num_tasks == PeriodicTask::max_tasks) {
|
if (_num_tasks == PeriodicTask::max_tasks) {
|
||||||
fatal("Overflow in PeriodicTask table");
|
fatal("Overflow in PeriodicTask table");
|
||||||
|
@ -113,18 +121,21 @@ void PeriodicTask::enroll() {
|
||||||
_tasks[_num_tasks++] = this;
|
_tasks[_num_tasks++] = this;
|
||||||
|
|
||||||
WatcherThread* thread = WatcherThread::watcher_thread();
|
WatcherThread* thread = WatcherThread::watcher_thread();
|
||||||
if (thread) {
|
if (thread != NULL) {
|
||||||
thread->unpark();
|
thread->unpark();
|
||||||
} else {
|
} else {
|
||||||
WatcherThread::start();
|
WatcherThread::start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disenroll could be called from a JavaThread, so we have to check for
|
// disenroll the current PeriodicTask
|
||||||
* safepoint when taking the lock to avoid deadlocking */
|
|
||||||
void PeriodicTask::disenroll() {
|
void PeriodicTask::disenroll() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
|
// Follow normal safepoint aware lock enter protocol if the caller does
|
||||||
NULL : PeriodicTask_lock);
|
// not already own the PeriodicTask_lock. Otherwise, we don't try to
|
||||||
|
// enter it again because VM internal Mutexes do not support recursion.
|
||||||
|
//
|
||||||
|
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? NULL
|
||||||
|
: PeriodicTask_lock);
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
for(index = 0; index < _num_tasks && _tasks[index] != this; index++)
|
for(index = 0; index < _num_tasks && _tasks[index] != this; index++)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -54,6 +54,7 @@ class PeriodicTask: public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
static int _num_tasks;
|
static int _num_tasks;
|
||||||
static PeriodicTask* _tasks[PeriodicTask::max_tasks];
|
static PeriodicTask* _tasks[PeriodicTask::max_tasks];
|
||||||
|
// Can only be called by the WatcherThread
|
||||||
static void real_time_tick(int delay_time);
|
static void real_time_tick(int delay_time);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
@ -98,6 +99,7 @@ class PeriodicTask: public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
// Calculate when the next periodic task will fire.
|
// Calculate when the next periodic task will fire.
|
||||||
// Called by the WatcherThread's run method.
|
// Called by the WatcherThread's run method.
|
||||||
|
// Requires the PeriodicTask_lock.
|
||||||
static int time_to_wait();
|
static int time_to_wait();
|
||||||
|
|
||||||
// The task to perform at each period
|
// The task to perform at each period
|
||||||
|
|
|
@ -1197,8 +1197,15 @@ WatcherThread::WatcherThread() : Thread(), _crash_protection(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int WatcherThread::sleep() const {
|
int WatcherThread::sleep() const {
|
||||||
|
// The WatcherThread does not participate in the safepoint protocol
|
||||||
|
// for the PeriodicTask_lock because it is not a JavaThread.
|
||||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
|
||||||
|
if (_should_terminate) {
|
||||||
|
// check for termination before we do any housekeeping or wait
|
||||||
|
return 0; // we did not sleep.
|
||||||
|
}
|
||||||
|
|
||||||
// remaining will be zero if there are no tasks,
|
// remaining will be zero if there are no tasks,
|
||||||
// causing the WatcherThread to sleep until a task is
|
// causing the WatcherThread to sleep until a task is
|
||||||
// enrolled
|
// enrolled
|
||||||
|
@ -1211,8 +1218,9 @@ int WatcherThread::sleep() const {
|
||||||
|
|
||||||
jlong time_before_loop = os::javaTimeNanos();
|
jlong time_before_loop = os::javaTimeNanos();
|
||||||
|
|
||||||
for (;;) {
|
while (true) {
|
||||||
bool timedout = PeriodicTask_lock->wait(Mutex::_no_safepoint_check_flag, remaining);
|
bool timedout = PeriodicTask_lock->wait(Mutex::_no_safepoint_check_flag,
|
||||||
|
remaining);
|
||||||
jlong now = os::javaTimeNanos();
|
jlong now = os::javaTimeNanos();
|
||||||
|
|
||||||
if (remaining == 0) {
|
if (remaining == 0) {
|
||||||
|
@ -1253,7 +1261,7 @@ void WatcherThread::run() {
|
||||||
this->initialize_thread_local_storage();
|
this->initialize_thread_local_storage();
|
||||||
this->set_native_thread_name(this->name());
|
this->set_native_thread_name(this->name());
|
||||||
this->set_active_handles(JNIHandleBlock::allocate_block());
|
this->set_active_handles(JNIHandleBlock::allocate_block());
|
||||||
while (!_should_terminate) {
|
while (true) {
|
||||||
assert(watcher_thread() == Thread::current(), "thread consistency check");
|
assert(watcher_thread() == Thread::current(), "thread consistency check");
|
||||||
assert(watcher_thread() == this, "thread consistency check");
|
assert(watcher_thread() == this, "thread consistency check");
|
||||||
|
|
||||||
|
@ -1289,6 +1297,11 @@ void WatcherThread::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_should_terminate) {
|
||||||
|
// check for termination before posting the next tick
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
PeriodicTask::real_time_tick(time_waited);
|
PeriodicTask::real_time_tick(time_waited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1319,27 +1332,19 @@ void WatcherThread::make_startable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatcherThread::stop() {
|
void WatcherThread::stop() {
|
||||||
// Get the PeriodicTask_lock if we can. If we cannot, then the
|
{
|
||||||
// WatcherThread is using it and we don't want to block on that lock
|
// Follow normal safepoint aware lock enter protocol since the
|
||||||
// here because that might cause a safepoint deadlock depending on
|
// WatcherThread is stopped by another JavaThread.
|
||||||
// what the current WatcherThread tasks are doing.
|
MutexLocker ml(PeriodicTask_lock);
|
||||||
bool have_lock = PeriodicTask_lock->try_lock();
|
|
||||||
|
|
||||||
_should_terminate = true;
|
_should_terminate = true;
|
||||||
OrderAccess::fence(); // ensure WatcherThread sees update in main loop
|
|
||||||
|
|
||||||
if (have_lock) {
|
|
||||||
WatcherThread* watcher = watcher_thread();
|
WatcherThread* watcher = watcher_thread();
|
||||||
if (watcher != NULL) {
|
if (watcher != NULL) {
|
||||||
// If we managed to get the lock, then we should unpark the
|
// unpark the WatcherThread so it can see that it should terminate
|
||||||
// WatcherThread so that it can see we want it to stop.
|
|
||||||
watcher->unpark();
|
watcher->unpark();
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask_lock->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// it is ok to take late safepoints here, if needed
|
|
||||||
MutexLocker mu(Terminator_lock);
|
MutexLocker mu(Terminator_lock);
|
||||||
|
|
||||||
while (watcher_thread() != NULL) {
|
while (watcher_thread() != NULL) {
|
||||||
|
@ -1359,9 +1364,7 @@ void WatcherThread::stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatcherThread::unpark() {
|
void WatcherThread::unpark() {
|
||||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self()
|
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||||
? NULL
|
|
||||||
: PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
|
||||||
PeriodicTask_lock->notify();
|
PeriodicTask_lock->notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3558,8 +3561,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
MutexLocker ml(PeriodicTask_lock);
|
||||||
// Make sure the watcher thread can be started by WatcherThread::start()
|
// Make sure the WatcherThread can be started by WatcherThread::start()
|
||||||
// or by dynamic enrollment.
|
// or by dynamic enrollment.
|
||||||
WatcherThread::make_startable();
|
WatcherThread::make_startable();
|
||||||
// Start up the WatcherThread if there are any periodic tasks
|
// Start up the WatcherThread if there are any periodic tasks
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -701,7 +701,8 @@ class WatcherThread: public Thread {
|
||||||
static WatcherThread* _watcher_thread;
|
static WatcherThread* _watcher_thread;
|
||||||
|
|
||||||
static bool _startable;
|
static bool _startable;
|
||||||
volatile static bool _should_terminate; // updated without holding lock
|
// volatile due to at least one lock-free read
|
||||||
|
volatile static bool _should_terminate;
|
||||||
|
|
||||||
os::WatcherThreadCrashProtection* _crash_protection;
|
os::WatcherThreadCrashProtection* _crash_protection;
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue