< prev index next >
src/hotspot/share/runtime/vmThread.cpp
Print this page
rev 51818 : 8181143: Introduce diagnostic flag to abort VM on too long VM operations
Reviewed-by: rkennke, zgu, dholmes, stuefe, rehn
*** 26,35 ****
--- 26,36 ----
#include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.hpp"
#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"
#include "oops/oop.inline.hpp"
#include "oops/verifyOopClosure.hpp"
*** 195,204 ****
--- 196,231 ----
queue_oops_do(i, 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
bool VMThread::_should_terminate = false;
*** 207,222 ****
--- 234,265 ----
VMThread* VMThread::_vm_thread = NULL;
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");
_terminate_lock = new Monitor(Mutex::safepoint, "VMThread::_terminate_lock", true,
*** 495,504 ****
--- 538,552 ----
log_debug(vmthread)("Evaluating safepoint VM operation: %s", _cur_vm_operation->name());
_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
do {
_cur_vm_operation = safepoint_ops;
*** 536,545 ****
--- 584,597 ----
}
} while(safepoint_ops != NULL);
_vm_queue->set_drain_list(NULL);
+ if (_timeout_task != NULL) {
+ _timeout_task->disarm();
+ }
+
// Complete safepoint synchronization
SafepointSynchronize::end();
} else { // not a safepoint operation
log_debug(vmthread)("Evaluating non-safepoint VM operation: %s", _cur_vm_operation->name());
< prev index next >