mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8181143: Introduce diagnostic flag to abort VM on too long VM operations
Reviewed-by: rkennke, zgu, dholmes, stuefe, rehn
This commit is contained in:
parent
650f3fc113
commit
2278601b7c
4 changed files with 163 additions and 0 deletions
|
@ -28,6 +28,7 @@
|
|||
#include "jfr/jfrEvents.hpp"
|
||||
#include "jfr/support/jfrThreadId.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/method.hpp"
|
||||
|
@ -197,6 +198,32 @@ void VMOperationQueue::oops_do(OopClosure* f) {
|
|||
drain_list_oops_do(f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Timeout machinery
|
||||
|
||||
void VMOperationTimeoutTask::task() {
|
||||
assert(AbortVMOnVMOperationTimeout, "only if enabled");
|
||||
if (is_armed()) {
|
||||
jlong delay = (os::javaTimeMillis() - _arm_time);
|
||||
if (delay > AbortVMOnVMOperationTimeoutDelay) {
|
||||
fatal("VM operation took too long: " SIZE_FORMAT " ms (timeout: " SIZE_FORMAT " ms)",
|
||||
delay, AbortVMOnVMOperationTimeoutDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VMOperationTimeoutTask::is_armed() {
|
||||
return OrderAccess::load_acquire(&_armed) != 0;
|
||||
}
|
||||
|
||||
void VMOperationTimeoutTask::arm() {
|
||||
_arm_time = os::javaTimeMillis();
|
||||
OrderAccess::release_store_fence(&_armed, 1);
|
||||
}
|
||||
|
||||
void VMOperationTimeoutTask::disarm() {
|
||||
OrderAccess::release_store_fence(&_armed, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Implementation of VMThread stuff
|
||||
|
@ -209,12 +236,28 @@ VM_Operation* VMThread::_cur_vm_operation = NULL;
|
|||
VMOperationQueue* VMThread::_vm_queue = NULL;
|
||||
PerfCounter* VMThread::_perf_accumulated_vm_operation_time = NULL;
|
||||
const char* VMThread::_no_op_reason = NULL;
|
||||
VMOperationTimeoutTask* VMThread::_timeout_task = NULL;
|
||||
|
||||
|
||||
void VMThread::create() {
|
||||
assert(vm_thread() == NULL, "we can only allocate one VMThread");
|
||||
_vm_thread = new VMThread();
|
||||
|
||||
if (AbortVMOnVMOperationTimeout) {
|
||||
// Make sure we call the timeout task frequently enough, but not too frequent.
|
||||
// Try to make the interval 10% of the timeout delay, so that we miss the timeout
|
||||
// by those 10% at max. Periodic task also expects it to fit min/max intervals.
|
||||
size_t interval = (size_t)AbortVMOnVMOperationTimeoutDelay / 10;
|
||||
interval = interval / PeriodicTask::interval_gran * PeriodicTask::interval_gran;
|
||||
interval = MAX2<size_t>(interval, PeriodicTask::min_interval);
|
||||
interval = MIN2<size_t>(interval, PeriodicTask::max_interval);
|
||||
|
||||
_timeout_task = new VMOperationTimeoutTask(interval);
|
||||
_timeout_task->enroll();
|
||||
} else {
|
||||
assert(_timeout_task == NULL, "sanity");
|
||||
}
|
||||
|
||||
// Create VM operation queue
|
||||
_vm_queue = new VMOperationQueue();
|
||||
guarantee(_vm_queue != NULL, "just checking");
|
||||
|
@ -492,6 +535,11 @@ void VMThread::loop() {
|
|||
_vm_queue->set_drain_list(safepoint_ops); // ensure ops can be scanned
|
||||
|
||||
SafepointSynchronize::begin();
|
||||
|
||||
if (_timeout_task != NULL) {
|
||||
_timeout_task->arm();
|
||||
}
|
||||
|
||||
evaluate_operation(_cur_vm_operation);
|
||||
// now process all queued safepoint ops, iteratively draining
|
||||
// the queue until there are none left
|
||||
|
@ -533,6 +581,10 @@ void VMThread::loop() {
|
|||
|
||||
_vm_queue->set_drain_list(NULL);
|
||||
|
||||
if (_timeout_task != NULL) {
|
||||
_timeout_task->disarm();
|
||||
}
|
||||
|
||||
// Complete safepoint synchronization
|
||||
SafepointSynchronize::end();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue