diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/vmThread.cpp --- a/src/hotspot/share/runtime/vmThread.cpp Fri Nov 29 11:26:25 2019 +0100 +++ b/src/hotspot/share/runtime/vmThread.cpp Fri Nov 29 12:09:25 2019 +0100 @@ -50,13 +50,15 @@ #include "utilities/vmError.hpp" #include "utilities/xmlstream.hpp" +VM_QueueHead VMOperationQueue::_queue_head[VMOperationQueue::nof_priorities]; + VMOperationQueue::VMOperationQueue() { // The queue is a circular doubled-linked list, which always contains // one element (i.e., one element means empty). for(int i = 0; i < nof_priorities; i++) { _queue_length[i] = 0; _queue_counter = 0; - _queue[i] = new VM_None("QueueHead"); + _queue[i] = &_queue_head[i]; _queue[i]->set_next(_queue[i]); _queue[i]->set_prev(_queue[i]); } @@ -81,12 +83,7 @@ q->set_next(n); } -void VMOperationQueue::queue_add_front(int prio, VM_Operation *op) { - _queue_length[prio]++; - insert(_queue[prio]->next(), op); -} - -void VMOperationQueue::queue_add_back(int prio, VM_Operation *op) { +void VMOperationQueue::queue_add(int prio, VM_Operation *op) { _queue_length[prio]++; insert(_queue[prio]->prev(), op); } @@ -154,11 +151,11 @@ HOTSPOT_VMOPS_REQUEST( (char *) op->name(), strlen(op->name()), - op->evaluation_mode()); + op->evaluate_at_safepoint() ? 0 : 1); // Encapsulates VM queue policy. Currently, that // only involves putting them on the right list - queue_add_back(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op); + queue_add(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op); } VM_Operation* VMOperationQueue::remove_next() { @@ -380,15 +377,11 @@ assert(event != NULL, "invariant"); assert(event->should_commit(), "invariant"); assert(op != NULL, "invariant"); - const bool is_concurrent = op->evaluate_concurrently(); const bool evaluate_at_safepoint = op->evaluate_at_safepoint(); event->set_operation(op->type()); event->set_safepoint(evaluate_at_safepoint); - event->set_blocking(!is_concurrent); - // Only write caller thread information for non-concurrent vm operations. - // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown. - // This is because the caller thread could have exited already. - event->set_caller(is_concurrent ? 0 : JFR_THREAD_ID(op->calling_thread())); + event->set_blocking(true); + event->set_caller(JFR_THREAD_ID(op->calling_thread())); event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_id() : 0); event->commit(); } @@ -400,7 +393,7 @@ PerfTraceTime vm_op_timer(perf_accumulated_vm_operation_time()); HOTSPOT_VMOPS_BEGIN( (char *) op->name(), strlen(op->name()), - op->evaluation_mode()); + op->evaluate_at_safepoint() ? 0 : 1); EventExecuteVMOperation event; op->evaluate(); @@ -410,21 +403,11 @@ HOTSPOT_VMOPS_END( (char *) op->name(), strlen(op->name()), - op->evaluation_mode()); + op->evaluate_at_safepoint() ? 0 : 1); } - // Last access of info in _cur_vm_operation! - bool c_heap_allocated = op->is_cheap_allocated(); - // Mark as completed - if (!op->evaluate_concurrently()) { - op->calling_thread()->increment_vm_operation_completed_count(); - } - // It is unsafe to access the _cur_vm_operation after the 'increment_vm_operation_completed_count' call, - // since if it is stack allocated the calling thread might have deallocated - if (c_heap_allocated) { - delete _cur_vm_operation; - } + op->calling_thread()->increment_vm_operation_completed_count(); } static VM_None safepointALot_op("SafepointALot"); @@ -441,6 +424,11 @@ } }; +void VMThread::check_for_forced_cleanup() { + MonitorLocker mq(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag); + mq.notify(); +} + VM_Operation* VMThread::no_op_safepoint() { // Check for handshakes first since we may need to return a VMop. if (HandshakeALot) { @@ -451,7 +439,8 @@ long interval_ms = SafepointTracing::time_since_last_safepoint_ms(); bool max_time_exceeded = GuaranteedSafepointInterval != 0 && (interval_ms >= GuaranteedSafepointInterval); - if (max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) { + if ((max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) || + SafepointSynchronize::is_forced_cleanup_needed()) { return &cleanup_op; } if (SafepointALot) { @@ -480,8 +469,7 @@ _cur_vm_operation = _vm_queue->remove_next(); // Stall time tracking code - if (PrintVMQWaitTime && _cur_vm_operation != NULL && - !_cur_vm_operation->evaluate_concurrently()) { + if (PrintVMQWaitTime && _cur_vm_operation != NULL) { long stall = os::javaTimeMillis() - _cur_vm_operation->timestamp(); if (stall > 0) tty->print_cr("%s stall: %ld", _cur_vm_operation->name(), stall); @@ -489,8 +477,8 @@ while (!should_terminate() && _cur_vm_operation == NULL) { // wait with a timeout to guarantee safepoints at regular intervals - bool timedout = - mu_queue.wait(GuaranteedSafepointInterval); + // (if there is cleanup work to do) + (void)mu_queue.wait(GuaranteedSafepointInterval); // Support for self destruction if ((SelfDestructTimer != 0) && !VMError::is_error_reported() && @@ -499,9 +487,12 @@ exit(-1); } - if (timedout) { + // If the queue contains a safepoint VM op, + // clean up will be done so we can skip this part. + if (!_vm_queue->peek_at_safepoint_priority()) { + // Have to unlock VMOperationQueue_lock just in case no_op_safepoint() - // has to do a handshake. + // has to do a handshake when HandshakeALot is enabled. MutexUnlocker mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag); if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) { // Force a safepoint since we have not had one for at least @@ -624,15 +615,6 @@ { MonitorLocker mu(VMOperationRequest_lock, Mutex::_no_safepoint_check_flag); mu.notify_all(); } - - // We want to make sure that we get to a safepoint regularly - // even when executing VMops that don't require safepoints. - if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) { - HandleMark hm(VMThread::vm_thread()); - SafepointSynchronize::begin(); - SafepointSynchronize::end(); - _cur_vm_operation = NULL; - } } } @@ -667,11 +649,7 @@ if (!t->is_VM_thread()) { SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot // JavaThread or WatcherThread - bool concurrent = op->evaluate_concurrently(); - // only blocking VM operations need to verify the caller's safepoint state: - if (!concurrent) { - t->check_for_valid_safepoint_state(); - } + t->check_for_valid_safepoint_state(); // New request from Java thread, evaluate prologue if (!op->doit_prologue()) { @@ -681,16 +659,8 @@ // Setup VM_operations for execution op->set_calling_thread(t); - // It does not make sense to execute the epilogue, if the VM operation object is getting - // deallocated by the VM thread. - bool execute_epilog = !op->is_cheap_allocated(); - assert(!concurrent || op->is_cheap_allocated(), "concurrent => cheap_allocated"); - - // Get ticket number for non-concurrent VM operations - int ticket = 0; - if (!concurrent) { - ticket = t->vm_operation_ticket(); - } + // Get ticket number for the VM operation + int ticket = t->vm_operation_ticket(); // Add VM operation to list of waiting threads. We are guaranteed not to block while holding the // VMOperationQueue_lock, so we can block without a safepoint check. This allows vm operation requests @@ -702,9 +672,8 @@ op->set_timestamp(os::javaTimeMillis()); ml.notify(); } - - if (!concurrent) { - // Wait for completion of request (non-concurrent) + { + // Wait for completion of request // Note: only a JavaThread triggers the safepoint check when locking MonitorLocker ml(VMOperationRequest_lock, t->is_Java_thread() ? Mutex::_safepoint_check_flag : Mutex::_no_safepoint_check_flag); @@ -712,10 +681,7 @@ ml.wait(); } } - - if (execute_epilog) { - op->doit_epilogue(); - } + op->doit_epilogue(); } else { // invoked by VM thread; usually nested VM operation assert(t->is_VM_thread(), "must be a VM thread"); @@ -744,9 +710,6 @@ op->evaluate(); } - // Free memory if needed - if (op->is_cheap_allocated()) delete op; - _cur_vm_operation = prev_vm_operation; } }