mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
7127792: Add the ability to change an existing PeriodicTask's execution interval
Enables dynamic enrollment / disenrollment from the PeriodicTasks in WatcherThread. Reviewed-by: dholmes, mgronlun
This commit is contained in:
parent
61a5a58cb1
commit
e1d995ab86
6 changed files with 162 additions and 92 deletions
|
@ -1217,6 +1217,7 @@ void NamedThread::set_name(const char* format, ...) {
|
|||
// timer interrupts exists on the platform.
|
||||
|
||||
WatcherThread* WatcherThread::_watcher_thread = NULL;
|
||||
bool WatcherThread::_startable = false;
|
||||
volatile bool WatcherThread::_should_terminate = false;
|
||||
|
||||
WatcherThread::WatcherThread() : Thread() {
|
||||
|
@ -1237,6 +1238,55 @@ WatcherThread::WatcherThread() : Thread() {
|
|||
}
|
||||
}
|
||||
|
||||
int WatcherThread::sleep() const {
|
||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
// remaining will be zero if there are no tasks,
|
||||
// causing the WatcherThread to sleep until a task is
|
||||
// enrolled
|
||||
int remaining = PeriodicTask::time_to_wait();
|
||||
int time_slept = 0;
|
||||
|
||||
// we expect this to timeout - we only ever get unparked when
|
||||
// we should terminate or when a new task has been enrolled
|
||||
OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */);
|
||||
|
||||
jlong time_before_loop = os::javaTimeNanos();
|
||||
|
||||
for (;;) {
|
||||
bool timedout = PeriodicTask_lock->wait(Mutex::_no_safepoint_check_flag, remaining);
|
||||
jlong now = os::javaTimeNanos();
|
||||
|
||||
if (remaining == 0) {
|
||||
// if we didn't have any tasks we could have waited for a long time
|
||||
// consider the time_slept zero and reset time_before_loop
|
||||
time_slept = 0;
|
||||
time_before_loop = now;
|
||||
} else {
|
||||
// need to recalulate since we might have new tasks in _tasks
|
||||
time_slept = (int) ((now - time_before_loop) / 1000000);
|
||||
}
|
||||
|
||||
// Change to task list or spurious wakeup of some kind
|
||||
if (timedout || _should_terminate) {
|
||||
break;
|
||||
}
|
||||
|
||||
remaining = PeriodicTask::time_to_wait();
|
||||
if (remaining == 0) {
|
||||
// Last task was just disenrolled so loop around and wait until
|
||||
// another task gets enrolled
|
||||
continue;
|
||||
}
|
||||
|
||||
remaining -= time_slept;
|
||||
if (remaining <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return time_slept;
|
||||
}
|
||||
|
||||
void WatcherThread::run() {
|
||||
assert(this == watcher_thread(), "just checking");
|
||||
|
||||
|
@ -1249,26 +1299,7 @@ void WatcherThread::run() {
|
|||
|
||||
// Calculate how long it'll be until the next PeriodicTask work
|
||||
// should be done, and sleep that amount of time.
|
||||
size_t time_to_wait = PeriodicTask::time_to_wait();
|
||||
|
||||
// we expect this to timeout - we only ever get unparked when
|
||||
// we should terminate
|
||||
{
|
||||
OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */);
|
||||
|
||||
jlong prev_time = os::javaTimeNanos();
|
||||
for (;;) {
|
||||
int res= _SleepEvent->park(time_to_wait);
|
||||
if (res == OS_TIMEOUT || _should_terminate)
|
||||
break;
|
||||
// spurious wakeup of some kind
|
||||
jlong now = os::javaTimeNanos();
|
||||
time_to_wait -= (now - prev_time) / 1000000;
|
||||
if (time_to_wait <= 0)
|
||||
break;
|
||||
prev_time = now;
|
||||
}
|
||||
}
|
||||
int time_waited = sleep();
|
||||
|
||||
if (is_error_reported()) {
|
||||
// A fatal error has happened, the error handler(VMError::report_and_die)
|
||||
|
@ -1298,13 +1329,7 @@ void WatcherThread::run() {
|
|||
}
|
||||
}
|
||||
|
||||
PeriodicTask::real_time_tick(time_to_wait);
|
||||
|
||||
// If we have no more tasks left due to dynamic disenrollment,
|
||||
// shut down the thread since we don't currently support dynamic enrollment
|
||||
if (PeriodicTask::num_tasks() == 0) {
|
||||
_should_terminate = true;
|
||||
}
|
||||
PeriodicTask::real_time_tick(time_waited);
|
||||
}
|
||||
|
||||
// Signal that it is terminated
|
||||
|
@ -1319,22 +1344,33 @@ void WatcherThread::run() {
|
|||
}
|
||||
|
||||
void WatcherThread::start() {
|
||||
if (watcher_thread() == NULL) {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
|
||||
if (watcher_thread() == NULL && _startable) {
|
||||
_should_terminate = false;
|
||||
// Create the single instance of WatcherThread
|
||||
new WatcherThread();
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::make_startable() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
_startable = true;
|
||||
}
|
||||
|
||||
void WatcherThread::stop() {
|
||||
{
|
||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||
_should_terminate = true;
|
||||
OrderAccess::fence(); // ensure WatcherThread sees update in main loop
|
||||
|
||||
WatcherThread* watcher = watcher_thread();
|
||||
if (watcher != NULL)
|
||||
watcher->unpark();
|
||||
}
|
||||
|
||||
// it is ok to take late safepoints here, if needed
|
||||
MutexLocker mu(Terminator_lock);
|
||||
_should_terminate = true;
|
||||
OrderAccess::fence(); // ensure WatcherThread sees update in main loop
|
||||
|
||||
Thread* watcher = watcher_thread();
|
||||
if (watcher != NULL)
|
||||
watcher->_SleepEvent->unpark();
|
||||
|
||||
while(watcher_thread() != NULL) {
|
||||
// This wait should make safepoint checks, wait without a timeout,
|
||||
|
@ -1352,6 +1388,11 @@ void WatcherThread::stop() {
|
|||
}
|
||||
}
|
||||
|
||||
void WatcherThread::unpark() {
|
||||
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ? NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||
PeriodicTask_lock->notify();
|
||||
}
|
||||
|
||||
void WatcherThread::print_on(outputStream* st) const {
|
||||
st->print("\"%s\" ", name());
|
||||
Thread::print_on(st);
|
||||
|
@ -3658,12 +3699,18 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
|||
}
|
||||
}
|
||||
|
||||
// Start up the WatcherThread if there are any periodic tasks
|
||||
// NOTE: All PeriodicTasks should be registered by now. If they
|
||||
// aren't, late joiners might appear to start slowly (we might
|
||||
// take a while to process their first tick).
|
||||
if (PeriodicTask::num_tasks() > 0) {
|
||||
WatcherThread::start();
|
||||
{
|
||||
MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Make sure the watcher thread can be started by WatcherThread::start()
|
||||
// or by dynamic enrollment.
|
||||
WatcherThread::make_startable();
|
||||
// Start up the WatcherThread if there are any periodic tasks
|
||||
// NOTE: All PeriodicTasks should be registered by now. If they
|
||||
// aren't, late joiners might appear to start slowly (we might
|
||||
// take a while to process their first tick).
|
||||
if (PeriodicTask::num_tasks() > 0) {
|
||||
WatcherThread::start();
|
||||
}
|
||||
}
|
||||
|
||||
// Give os specific code one last chance to start
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue