< 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 >