8212107: VMThread issues and cleanup

Reviewed-by: shade, dcubed, coleenp, dholmes, redestad
This commit is contained in:
Robbin Ehn 2020-09-29 09:37:15 +00:00
parent 6bddeb709d
commit 431338bcb3
8 changed files with 236 additions and 349 deletions

View File

@ -454,12 +454,8 @@ static bool prepare_for_emergency_dump(Thread* thread) {
Heap_lock->unlock();
}
if (VMOperationQueue_lock->owned_by_self()) {
VMOperationQueue_lock->unlock();
}
if (VMOperationRequest_lock->owned_by_self()) {
VMOperationRequest_lock->unlock();
if (VMOperation_lock->owned_by_self()) {
VMOperation_lock->unlock();
}
if (Service_lock->owned_by_self()) {

View File

@ -65,8 +65,7 @@ Monitor* CodeSweeper_lock = NULL;
Mutex* MethodData_lock = NULL;
Mutex* TouchedMethodLog_lock = NULL;
Mutex* RetData_lock = NULL;
Monitor* VMOperationQueue_lock = NULL;
Monitor* VMOperationRequest_lock = NULL;
Monitor* VMOperation_lock = NULL;
Monitor* Threads_lock = NULL;
Mutex* NonJavaThreadsList_lock = NULL;
Mutex* NonJavaThreadsListSync_lock = NULL;
@ -280,8 +279,7 @@ void mutex_init() {
def(NonJavaThreadsList_lock , PaddedMutex, barrier, true, _safepoint_check_never);
def(NonJavaThreadsListSync_lock , PaddedMutex, leaf, true, _safepoint_check_never);
def(VMOperationQueue_lock , PaddedMonitor, nonleaf, true, _safepoint_check_never); // VM_thread allowed to block on these
def(VMOperationRequest_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always);
def(VMOperation_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); // VM_thread allowed to block on these
def(RetData_lock , PaddedMutex , nonleaf, false, _safepoint_check_always);
def(Terminator_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always);
def(InitCompleted_lock , PaddedMonitor, leaf, true, _safepoint_check_never);

View File

@ -58,8 +58,7 @@ extern Monitor* CodeSweeper_lock; // a lock used by the sweeper o
extern Mutex* MethodData_lock; // a lock on installation of method data
extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info
extern Mutex* RetData_lock; // a lock on installation of RetData inside method data
extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute
extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting for a vm_operation to terminate
extern Monitor* VMOperation_lock; // a lock on queue of vm_operations waiting to execute
extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads
// (also used by Safepoints too to block threads creation/destruction)
extern Mutex* NonJavaThreadsList_lock; // a lock on the NonJavaThreads list

View File

@ -255,8 +255,6 @@ Thread::Thread() {
NOT_PRODUCT(_skip_gcalot = false;)
_jvmti_env_iteration_count = 0;
set_allocated_bytes(0);
_vm_operation_started_count = 0;
_vm_operation_completed_count = 0;
_current_pending_monitor = NULL;
_current_pending_monitor_is_from_java = true;
_current_waiting_monitor = NULL;

View File

@ -401,9 +401,6 @@ class Thread: public ThreadShadow {
JFR_ONLY(DEFINE_THREAD_LOCAL_FIELD_JFR;) // Thread-local data for jfr
int _vm_operation_started_count; // VM_Operation support
int _vm_operation_completed_count; // VM_Operation support
ObjectMonitor* _current_pending_monitor; // ObjectMonitor this thread
// is waiting to lock
bool _current_pending_monitor_is_from_java; // locking is from Java code
@ -621,11 +618,6 @@ class Thread: public ThreadShadow {
bool is_trace_suspend() { return (_suspend_flags & _trace_flag) != 0; }
// VM operation support
int vm_operation_ticket() { return ++_vm_operation_started_count; }
int vm_operation_completed_count() { return _vm_operation_completed_count; }
void increment_vm_operation_completed_count() { _vm_operation_completed_count++; }
// For tracking the heavyweight monitor the thread is pending on.
ObjectMonitor* current_pending_monitor() {
return _current_pending_monitor;

View File

@ -121,14 +121,12 @@ class VM_Operation : public StackObj {
private:
Thread* _calling_thread;
VM_Operation* _next;
VM_Operation* _prev;
// The VM operation name array
static const char* _names[];
public:
VM_Operation() : _calling_thread(NULL), _next(NULL), _prev(NULL) {}
VM_Operation() : _calling_thread(NULL) {}
// VM operation support (used by VM thread)
Thread* calling_thread() const { return _calling_thread; }
@ -148,12 +146,6 @@ class VM_Operation : public StackObj {
virtual bool doit_prologue() { return true; };
virtual void doit_epilogue() {};
// Linking
VM_Operation *next() const { return _next; }
VM_Operation *prev() const { return _prev; }
void set_next(VM_Operation *next) { _next = next; }
void set_prev(VM_Operation *prev) { _prev = prev; }
// Configuration. Override these appropriately in subclasses.
virtual VMOp_Type type() const = 0;
virtual bool allow_nested_vm_operations() const { return false; }

View File

@ -24,7 +24,6 @@
#include "precompiled.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "logging/log.hpp"
@ -32,7 +31,6 @@
#include "logging/logConfiguration.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "oops/verifyOopClosure.hpp"
#include "runtime/atomic.hpp"
@ -43,101 +41,13 @@
#include "runtime/safepoint.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vmOperations.hpp"
#include "services/runtimeService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#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] = &_queue_head[i];
_queue[i]->set_next(_queue[i]);
_queue[i]->set_prev(_queue[i]);
}
}
bool VMOperationQueue::queue_empty(int prio) {
// It is empty if there is exactly one element
bool empty = (_queue[prio] == _queue[prio]->next());
assert( (_queue_length[prio] == 0 && empty) ||
(_queue_length[prio] > 0 && !empty), "sanity check");
return _queue_length[prio] == 0;
}
// Inserts an element to the right of the q element
void VMOperationQueue::insert(VM_Operation* q, VM_Operation* n) {
assert(q->next()->prev() == q && q->prev()->next() == q, "sanity check");
n->set_prev(q);
n->set_next(q->next());
q->next()->set_prev(n);
q->set_next(n);
}
void VMOperationQueue::queue_add(int prio, VM_Operation *op) {
_queue_length[prio]++;
insert(_queue[prio]->prev(), op);
}
void VMOperationQueue::unlink(VM_Operation* q) {
assert(q->next()->prev() == q && q->prev()->next() == q, "sanity check");
q->prev()->set_next(q->next());
q->next()->set_prev(q->prev());
}
VM_Operation* VMOperationQueue::queue_remove_front(int prio) {
if (queue_empty(prio)) return NULL;
assert(_queue_length[prio] >= 0, "sanity check");
_queue_length[prio]--;
VM_Operation* r = _queue[prio]->next();
assert(r != _queue[prio], "cannot remove base element");
unlink(r);
return r;
}
//-----------------------------------------------------------------
// High-level interface
void VMOperationQueue::add(VM_Operation *op) {
HOTSPOT_VMOPS_REQUEST(
(char *) op->name(), strlen(op->name()),
op->evaluate_at_safepoint() ? 0 : 1);
// Encapsulates VM queue policy. Currently, that
// only involves putting them on the right list
queue_add(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op);
}
VM_Operation* VMOperationQueue::remove_next() {
// Assuming VMOperation queue is two-level priority queue. If there are
// more than two priorities, we need a different scheduling algorithm.
assert(SafepointPriority == 0 && MediumPriority == 1 && nof_priorities == 2,
"current algorithm does not work");
// simple counter based scheduling to prevent starvation of lower priority
// queue. -- see 4390175
int high_prio, low_prio;
if (_queue_counter++ < 10) {
high_prio = SafepointPriority;
low_prio = MediumPriority;
} else {
_queue_counter = 0;
high_prio = MediumPriority;
low_prio = SafepointPriority;
}
return queue_remove_front(queue_empty(high_prio) ? low_prio : high_prio);
}
//------------------------------------------------------------------------------------------------------------------
// Timeout machinery
@ -169,12 +79,15 @@ void VMOperationTimeoutTask::disarm() {
//------------------------------------------------------------------------------------------------------------------
// Implementation of VMThread stuff
static VM_None safepointALot_op("SafepointALot");
static VM_Cleanup cleanup_op;
bool VMThread::_should_terminate = false;
bool VMThread::_terminated = false;
Monitor* VMThread::_terminate_lock = NULL;
VMThread* VMThread::_vm_thread = NULL;
VM_Operation* VMThread::_cur_vm_operation = NULL;
VMOperationQueue* VMThread::_vm_queue = NULL;
VM_Operation* VMThread::_next_vm_operation = &cleanup_op; // Prevent any thread from setting an operation until VM thread is ready.
PerfCounter* VMThread::_perf_accumulated_vm_operation_time = NULL;
VMOperationTimeoutTask* VMThread::_timeout_task = NULL;
@ -198,10 +111,6 @@ void VMThread::create() {
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,
Monitor::_safepoint_check_never);
@ -310,9 +219,10 @@ void VMThread::run() {
// and wait until operation is performed.
void VMThread::wait_for_vm_thread_exit() {
assert(JavaThread::current()->is_terminated(), "Should be terminated");
{ MonitorLocker mu(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag);
{
MonitorLocker mu(VMOperation_lock);
_should_terminate = true;
mu.notify();
mu.notify_all();
}
// Note: VM thread leaves at Safepoint. We are not stopped by Safepoint
@ -324,8 +234,9 @@ void VMThread::wait_for_vm_thread_exit() {
// Note: it should be OK to use Terminator_lock here. But this is called
// at a very delicate time (VM shutdown) and we are operating in non- VM
// thread at Safepoint. It's safer to not share lock with other threads.
{ MonitorLocker ml(_terminate_lock, Mutex::_no_safepoint_check_flag);
while(!VMThread::is_terminated()) {
{
MonitorLocker ml(_terminate_lock, Mutex::_no_safepoint_check_flag);
while (!VMThread::is_terminated()) {
ml.wait();
}
}
@ -364,13 +275,8 @@ void VMThread::evaluate_operation(VM_Operation* op) {
op->evaluate_at_safepoint() ? 0 : 1);
}
// Mark as completed
op->calling_thread()->increment_vm_operation_completed_count();
}
static VM_None safepointALot_op("SafepointALot");
static VM_Cleanup cleanup_op;
class HandshakeALotClosure : public HandshakeClosure {
public:
HandshakeALotClosure() : HandshakeClosure("HandshakeALot") {}
@ -381,24 +287,180 @@ class HandshakeALotClosure : public HandshakeClosure {
}
};
VM_Operation* VMThread::no_op_safepoint() {
// Check for handshakes first since we may need to return a VMop.
if (HandshakeALot) {
HandshakeALotClosure hal_cl;
Handshake::execute(&hal_cl);
bool VMThread::handshake_alot() {
assert(_cur_vm_operation == NULL, "should not have an op yet");
assert(_next_vm_operation == NULL, "should not have an op yet");
if (!HandshakeALot) {
return false;
}
static jlong last_halot_ms = 0;
jlong now_ms = nanos_to_millis(os::javaTimeNanos());
// If only HandshakeALot is set, but GuaranteedSafepointInterval is 0,
// we emit a handshake if it's been more than a second since the last one.
jlong interval = GuaranteedSafepointInterval != 0 ? GuaranteedSafepointInterval : 1000;
jlong deadline_ms = interval + last_halot_ms;
if (now_ms > deadline_ms) {
last_halot_ms = now_ms;
return true;
}
return false;
}
void VMThread::setup_periodic_safepoint_if_needed() {
assert(_cur_vm_operation == NULL, "Already have an op");
assert(_next_vm_operation == NULL, "Already have an op");
// Check for a cleanup before SafepointALot to keep stats correct.
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()) {
return &cleanup_op;
if (!max_time_exceeded) {
return;
}
if (SafepointALot) {
return &safepointALot_op;
if (SafepointSynchronize::is_cleanup_needed()) {
_next_vm_operation = &cleanup_op;
} else if (SafepointALot) {
_next_vm_operation = &safepointALot_op;
}
}
bool VMThread::set_next_operation(VM_Operation *op) {
if (_next_vm_operation != NULL) {
return false;
}
log_debug(vmthread)("Adding VM operation: %s", op->name());
_next_vm_operation = op;
HOTSPOT_VMOPS_REQUEST(
(char *) op->name(), strlen(op->name()),
op->evaluate_at_safepoint() ? 0 : 1);
return true;
}
void VMThread::wait_until_executed(VM_Operation* op) {
MonitorLocker ml(VMOperation_lock,
Thread::current()->is_Java_thread() ?
Mutex::_safepoint_check_flag :
Mutex::_no_safepoint_check_flag);
{
TraceTime timer("Installing VM operation", TRACETIME_LOG(Trace, vmthread));
while (true) {
if (VMThread::vm_thread()->set_next_operation(op)) {
ml.notify_all();
break;
}
// Wait to install this operation as the next operation in the VM Thread
log_trace(vmthread)("A VM operation already set, waiting");
ml.wait();
}
}
{
// Wait until the operation has been processed
TraceTime timer("Waiting for VM operation to be completed", TRACETIME_LOG(Trace, vmthread));
// _next_vm_operation is cleared holding VMOperation_lock after it has been
// executed. We wait until _next_vm_operation is not our op.
while (_next_vm_operation == op) {
// VM Thread can process it once we unlock the mutex on wait.
ml.wait();
}
}
}
static void self_destruct_if_needed() {
// Support for self destruction
if ((SelfDestructTimer != 0) && !VMError::is_error_reported() &&
(os::elapsedTime() > (double)SelfDestructTimer * 60.0)) {
tty->print_cr("VM self-destructed");
exit(-1);
}
}
void VMThread::inner_execute(VM_Operation* op) {
assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
VM_Operation* prev_vm_operation = NULL;
if (_cur_vm_operation != NULL) {
// Check that the VM operation allows nested VM operation.
// This is normally not the case, e.g., the compiler
// does not allow nested scavenges or compiles.
if (!_cur_vm_operation->allow_nested_vm_operations()) {
fatal("Unexpected nested VM operation %s requested by operation %s",
op->name(), _cur_vm_operation->name());
}
op->set_calling_thread(_cur_vm_operation->calling_thread());
prev_vm_operation = _cur_vm_operation;
}
_cur_vm_operation = op;
HandleMark hm(VMThread::vm_thread());
EventMark em("Executing %s VM operation: %s", prev_vm_operation != NULL ? "nested" : "", op->name());
log_debug(vmthread)("Evaluating %s %s VM operation: %s",
prev_vm_operation != NULL ? "nested" : "",
_cur_vm_operation->evaluate_at_safepoint() ? "safepoint" : "non-safepoint",
_cur_vm_operation->name());
bool end_safepoint = false;
if (_cur_vm_operation->evaluate_at_safepoint() &&
!SafepointSynchronize::is_at_safepoint()) {
SafepointSynchronize::begin();
if (_timeout_task != NULL) {
_timeout_task->arm();
}
end_safepoint = true;
}
evaluate_operation(_cur_vm_operation);
if (end_safepoint) {
if (_timeout_task != NULL) {
_timeout_task->disarm();
}
SafepointSynchronize::end();
}
_cur_vm_operation = prev_vm_operation;
}
void VMThread::wait_for_operation() {
assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
MonitorLocker ml_op_lock(VMOperation_lock, Mutex::_no_safepoint_check_flag);
// Clear previous operation.
// On first call this clears a dummy place-holder.
_next_vm_operation = NULL;
// Notify operation is done and notify a next operation can be installed.
ml_op_lock.notify_all();
while (!should_terminate()) {
self_destruct_if_needed();
if (_next_vm_operation != NULL) {
return;
}
if (handshake_alot()) {
{
MutexUnlocker mul(VMOperation_lock);
HandshakeALotClosure hal_cl;
Handshake::execute(&hal_cl);
}
// When we unlocked above someone might have setup a new op.
if (_next_vm_operation != NULL) {
return;
}
}
assert(_next_vm_operation == NULL, "Must be");
assert(_cur_vm_operation == NULL, "Must be");
setup_periodic_safepoint_if_needed();
if (_next_vm_operation != NULL) {
return;
}
// We didn't find anything to execute, notify any waiter so they can install an op.
ml_op_lock.notify_all();
ml_op_lock.wait(GuaranteedSafepointInterval);
}
// Nothing to be done.
return NULL;
}
void VMThread::loop() {
@ -406,94 +468,17 @@ void VMThread::loop() {
SafepointSynchronize::init(_vm_thread);
while(true) {
//
// Wait for VM operation
//
// use no_safepoint_check to get lock without attempting to "sneak"
{ MonitorLocker mu_queue(VMOperationQueue_lock,
Mutex::_no_safepoint_check_flag);
// Need to set a calling thread for ops not passed
// via the normal way.
cleanup_op.set_calling_thread(_vm_thread);
safepointALot_op.set_calling_thread(_vm_thread);
// Look for new operation
assert(_cur_vm_operation == NULL, "no current one should be executing");
_cur_vm_operation = _vm_queue->remove_next();
while (!should_terminate() && _cur_vm_operation == NULL) {
// wait with a timeout to guarantee safepoints at regular intervals
// (if there is cleanup work to do)
(void)mu_queue.wait(GuaranteedSafepointInterval);
// Support for self destruction
if ((SelfDestructTimer != 0) && !VMError::is_error_reported() &&
(os::elapsedTime() > (double)SelfDestructTimer * 60.0)) {
tty->print_cr("VM self-destructed");
exit(-1);
}
// 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 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
// 'GuaranteedSafepointInterval' milliseconds and we need to clean
// something. This will run all the clean-up processing that needs
// to be done at a safepoint.
SafepointSynchronize::begin();
SafepointSynchronize::end();
_cur_vm_operation = NULL;
}
}
_cur_vm_operation = _vm_queue->remove_next();
}
if (should_terminate()) break;
} // Release mu_queue_lock
//
// Execute VM operation
//
{ HandleMark hm(VMThread::vm_thread());
EventMark em("Executing VM operation: %s", vm_operation()->name());
assert(_cur_vm_operation != NULL, "we should have found an operation to execute");
// If we are at a safepoint we will evaluate all the operations that
// follow that also require a safepoint
if (_cur_vm_operation->evaluate_at_safepoint()) {
log_debug(vmthread)("Evaluating safepoint VM operation: %s", _cur_vm_operation->name());
SafepointSynchronize::begin();
if (_timeout_task != NULL) {
_timeout_task->arm();
}
evaluate_operation(_cur_vm_operation);
_cur_vm_operation = 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());
evaluate_operation(_cur_vm_operation);
_cur_vm_operation = NULL;
}
}
//
// Notify (potential) waiting Java thread(s)
{ MonitorLocker mu(VMOperationRequest_lock, Mutex::_no_safepoint_check_flag);
mu.notify_all();
}
while (true) {
if (should_terminate()) break;
wait_for_operation();
if (should_terminate()) break;
assert(_next_vm_operation != NULL, "Must have one");
inner_execute(_next_vm_operation);
}
}
@ -525,71 +510,28 @@ class SkipGCALot : public StackObj {
void VMThread::execute(VM_Operation* op) {
Thread* t = Thread::current();
if (!t->is_VM_thread()) {
SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot
// JavaThread or WatcherThread
t->check_for_valid_safepoint_state();
// New request from Java thread, evaluate prologue
if (!op->doit_prologue()) {
return; // op was cancelled
}
// Setup VM_operations for execution
if (t->is_VM_thread()) {
op->set_calling_thread(t);
// 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
// to be queued up during a safepoint synchronization.
{
MonitorLocker ml(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag);
log_debug(vmthread)("Adding VM operation: %s", op->name());
_vm_queue->add(op);
ml.notify();
}
{
// 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);
while(t->vm_operation_completed_count() < ticket) {
ml.wait();
}
}
op->doit_epilogue();
} else {
// invoked by VM thread; usually nested VM operation
assert(t->is_VM_thread(), "must be a VM thread");
VM_Operation* prev_vm_operation = vm_operation();
if (prev_vm_operation != NULL) {
// Check the VM operation allows nested VM operation. This normally not the case, e.g., the compiler
// does not allow nested scavenges or compiles.
if (!prev_vm_operation->allow_nested_vm_operations()) {
fatal("Nested VM operation %s requested by operation %s",
op->name(), vm_operation()->name());
}
op->set_calling_thread(prev_vm_operation->calling_thread());
}
EventMark em("Executing %s VM operation: %s", prev_vm_operation ? "nested" : "", op->name());
// Release all internal handles after operation is evaluated
HandleMark hm(t);
_cur_vm_operation = op;
if (op->evaluate_at_safepoint() && !SafepointSynchronize::is_at_safepoint()) {
SafepointSynchronize::begin();
op->evaluate();
SafepointSynchronize::end();
} else {
op->evaluate();
}
_cur_vm_operation = prev_vm_operation;
((VMThread*)t)->inner_execute(op);
return;
}
// Avoid re-entrant attempts to gc-a-lot
SkipGCALot sgcalot(t);
// JavaThread or WatcherThread
t->check_for_valid_safepoint_state();
// New request from Java thread, evaluate prologue
if (!op->doit_prologue()) {
return; // op was cancelled
}
op->set_calling_thread(t);
wait_until_executed(op);
op->doit_epilogue();
}
void VMThread::verify() {

View File

@ -30,53 +30,6 @@
#include "runtime/task.hpp"
#include "runtime/vmOperations.hpp"
class VM_QueueHead : public VM_None {
public:
VM_QueueHead() : VM_None("QueueHead") {}
};
//
// Prioritized queue of VM operations.
//
// Encapsulates both queue management and
// and priority policy
//
class VMOperationQueue : public CHeapObj<mtInternal> {
private:
enum Priorities {
SafepointPriority, // Highest priority (operation executed at a safepoint)
MediumPriority, // Medium priority
nof_priorities
};
// We maintain a doubled linked list, with explicit count.
int _queue_length[nof_priorities];
int _queue_counter;
VM_Operation* _queue [nof_priorities];
static VM_QueueHead _queue_head[nof_priorities];
// Double-linked non-empty list insert.
void insert(VM_Operation* q,VM_Operation* n);
void unlink(VM_Operation* q);
// Basic queue manipulation
bool queue_empty (int prio);
void queue_add (int prio, VM_Operation *op);
VM_Operation* queue_remove_front(int prio);
// lock-free query: may return the wrong answer but must not break
bool queue_peek(int prio) { return _queue_length[prio] > 0; }
public:
VMOperationQueue();
// Highlevel operations. Encapsulates policy
void add(VM_Operation *op);
VM_Operation* remove_next(); // Returns next or null
bool peek_at_safepoint_priority() { return queue_peek(SafepointPriority); }
};
// VM operation timeout handling: warn or abort the VM when VM operation takes
// too long. Periodic tasks do not participate in safepoint protocol, and therefore
// can fire when application threads are stopped.
@ -114,9 +67,12 @@ class VMThread: public NamedThread {
static VMOperationTimeoutTask* _timeout_task;
static VM_Operation* no_op_safepoint();
static bool handshake_alot();
static void setup_periodic_safepoint_if_needed();
void evaluate_operation(VM_Operation* op);
void inner_execute(VM_Operation* op);
void wait_for_operation();
public:
// Constructor
@ -143,8 +99,16 @@ class VMThread: public NamedThread {
static void execute(VM_Operation* op);
// Returns the current vm operation if any.
static VM_Operation* vm_operation() { return _cur_vm_operation; }
static VM_Operation::VMOp_Type vm_op_type() { return _cur_vm_operation->type(); }
static VM_Operation* vm_operation() {
assert(Thread::current()->is_VM_thread(), "Must be");
return _cur_vm_operation;
}
static VM_Operation::VMOp_Type vm_op_type() {
VM_Operation* op = vm_operation();
assert(op != NULL, "sanity");
return op->type();
}
// Returns the single instance of VMThread.
static VMThread* vm_thread() { return _vm_thread; }
@ -152,7 +116,9 @@ class VMThread: public NamedThread {
void verify();
// Performance measurement
static PerfCounter* perf_accumulated_vm_operation_time() { return _perf_accumulated_vm_operation_time; }
static PerfCounter* perf_accumulated_vm_operation_time() {
return _perf_accumulated_vm_operation_time;
}
// Entry for starting vm thread
virtual void run();
@ -161,10 +127,14 @@ class VMThread: public NamedThread {
static void create();
static void destroy();
static void wait_until_executed(VM_Operation* op);
private:
// VM_Operation support
static VM_Operation* _cur_vm_operation; // Current VM operation
static VMOperationQueue* _vm_queue; // Queue (w/ policy) of VM operations
static VM_Operation* _next_vm_operation; // Next VM operation
bool set_next_operation(VM_Operation *op); // Set the _next_vm_operation if possible.
// Pointer to single-instance of VM thread
static VMThread* _vm_thread;