48 #include "utilities/dtrace.hpp" |
48 #include "utilities/dtrace.hpp" |
49 #include "utilities/events.hpp" |
49 #include "utilities/events.hpp" |
50 #include "utilities/vmError.hpp" |
50 #include "utilities/vmError.hpp" |
51 #include "utilities/xmlstream.hpp" |
51 #include "utilities/xmlstream.hpp" |
52 |
52 |
|
53 VM_QueueHead VMOperationQueue::_queue_head[VMOperationQueue::nof_priorities]; |
|
54 |
53 VMOperationQueue::VMOperationQueue() { |
55 VMOperationQueue::VMOperationQueue() { |
54 // The queue is a circular doubled-linked list, which always contains |
56 // The queue is a circular doubled-linked list, which always contains |
55 // one element (i.e., one element means empty). |
57 // one element (i.e., one element means empty). |
56 for(int i = 0; i < nof_priorities; i++) { |
58 for(int i = 0; i < nof_priorities; i++) { |
57 _queue_length[i] = 0; |
59 _queue_length[i] = 0; |
58 _queue_counter = 0; |
60 _queue_counter = 0; |
59 _queue[i] = new VM_None("QueueHead"); |
61 _queue[i] = &_queue_head[i]; |
60 _queue[i]->set_next(_queue[i]); |
62 _queue[i]->set_next(_queue[i]); |
61 _queue[i]->set_prev(_queue[i]); |
63 _queue[i]->set_prev(_queue[i]); |
62 } |
64 } |
63 _drain_list = NULL; |
65 _drain_list = NULL; |
64 } |
66 } |
79 n->set_next(q->next()); |
81 n->set_next(q->next()); |
80 q->next()->set_prev(n); |
82 q->next()->set_prev(n); |
81 q->set_next(n); |
83 q->set_next(n); |
82 } |
84 } |
83 |
85 |
84 void VMOperationQueue::queue_add_front(int prio, VM_Operation *op) { |
86 void VMOperationQueue::queue_add(int prio, VM_Operation *op) { |
85 _queue_length[prio]++; |
|
86 insert(_queue[prio]->next(), op); |
|
87 } |
|
88 |
|
89 void VMOperationQueue::queue_add_back(int prio, VM_Operation *op) { |
|
90 _queue_length[prio]++; |
87 _queue_length[prio]++; |
91 insert(_queue[prio]->prev(), op); |
88 insert(_queue[prio]->prev(), op); |
92 } |
89 } |
93 |
90 |
94 |
91 |
152 // High-level interface |
149 // High-level interface |
153 void VMOperationQueue::add(VM_Operation *op) { |
150 void VMOperationQueue::add(VM_Operation *op) { |
154 |
151 |
155 HOTSPOT_VMOPS_REQUEST( |
152 HOTSPOT_VMOPS_REQUEST( |
156 (char *) op->name(), strlen(op->name()), |
153 (char *) op->name(), strlen(op->name()), |
157 op->evaluation_mode()); |
154 op->evaluate_at_safepoint() ? 0 : 1); |
158 |
155 |
159 // Encapsulates VM queue policy. Currently, that |
156 // Encapsulates VM queue policy. Currently, that |
160 // only involves putting them on the right list |
157 // only involves putting them on the right list |
161 queue_add_back(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op); |
158 queue_add(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op); |
162 } |
159 } |
163 |
160 |
164 VM_Operation* VMOperationQueue::remove_next() { |
161 VM_Operation* VMOperationQueue::remove_next() { |
165 // Assuming VMOperation queue is two-level priority queue. If there are |
162 // Assuming VMOperation queue is two-level priority queue. If there are |
166 // more than two priorities, we need a different scheduling algorithm. |
163 // more than two priorities, we need a different scheduling algorithm. |
378 |
375 |
379 static void post_vm_operation_event(EventExecuteVMOperation* event, VM_Operation* op) { |
376 static void post_vm_operation_event(EventExecuteVMOperation* event, VM_Operation* op) { |
380 assert(event != NULL, "invariant"); |
377 assert(event != NULL, "invariant"); |
381 assert(event->should_commit(), "invariant"); |
378 assert(event->should_commit(), "invariant"); |
382 assert(op != NULL, "invariant"); |
379 assert(op != NULL, "invariant"); |
383 const bool is_concurrent = op->evaluate_concurrently(); |
|
384 const bool evaluate_at_safepoint = op->evaluate_at_safepoint(); |
380 const bool evaluate_at_safepoint = op->evaluate_at_safepoint(); |
385 event->set_operation(op->type()); |
381 event->set_operation(op->type()); |
386 event->set_safepoint(evaluate_at_safepoint); |
382 event->set_safepoint(evaluate_at_safepoint); |
387 event->set_blocking(!is_concurrent); |
383 event->set_blocking(true); |
388 // Only write caller thread information for non-concurrent vm operations. |
384 event->set_caller(JFR_THREAD_ID(op->calling_thread())); |
389 // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown. |
|
390 // This is because the caller thread could have exited already. |
|
391 event->set_caller(is_concurrent ? 0 : JFR_THREAD_ID(op->calling_thread())); |
|
392 event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_id() : 0); |
385 event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_id() : 0); |
393 event->commit(); |
386 event->commit(); |
394 } |
387 } |
395 |
388 |
396 void VMThread::evaluate_operation(VM_Operation* op) { |
389 void VMThread::evaluate_operation(VM_Operation* op) { |
398 |
391 |
399 { |
392 { |
400 PerfTraceTime vm_op_timer(perf_accumulated_vm_operation_time()); |
393 PerfTraceTime vm_op_timer(perf_accumulated_vm_operation_time()); |
401 HOTSPOT_VMOPS_BEGIN( |
394 HOTSPOT_VMOPS_BEGIN( |
402 (char *) op->name(), strlen(op->name()), |
395 (char *) op->name(), strlen(op->name()), |
403 op->evaluation_mode()); |
396 op->evaluate_at_safepoint() ? 0 : 1); |
404 |
397 |
405 EventExecuteVMOperation event; |
398 EventExecuteVMOperation event; |
406 op->evaluate(); |
399 op->evaluate(); |
407 if (event.should_commit()) { |
400 if (event.should_commit()) { |
408 post_vm_operation_event(&event, op); |
401 post_vm_operation_event(&event, op); |
409 } |
402 } |
410 |
403 |
411 HOTSPOT_VMOPS_END( |
404 HOTSPOT_VMOPS_END( |
412 (char *) op->name(), strlen(op->name()), |
405 (char *) op->name(), strlen(op->name()), |
413 op->evaluation_mode()); |
406 op->evaluate_at_safepoint() ? 0 : 1); |
414 } |
407 } |
415 |
|
416 // Last access of info in _cur_vm_operation! |
|
417 bool c_heap_allocated = op->is_cheap_allocated(); |
|
418 |
408 |
419 // Mark as completed |
409 // Mark as completed |
420 if (!op->evaluate_concurrently()) { |
410 op->calling_thread()->increment_vm_operation_completed_count(); |
421 op->calling_thread()->increment_vm_operation_completed_count(); |
|
422 } |
|
423 // It is unsafe to access the _cur_vm_operation after the 'increment_vm_operation_completed_count' call, |
|
424 // since if it is stack allocated the calling thread might have deallocated |
|
425 if (c_heap_allocated) { |
|
426 delete _cur_vm_operation; |
|
427 } |
|
428 } |
411 } |
429 |
412 |
430 static VM_None safepointALot_op("SafepointALot"); |
413 static VM_None safepointALot_op("SafepointALot"); |
431 static VM_Cleanup cleanup_op; |
414 static VM_Cleanup cleanup_op; |
432 |
415 |
439 jt->verify_states_for_handshake(); |
422 jt->verify_states_for_handshake(); |
440 #endif |
423 #endif |
441 } |
424 } |
442 }; |
425 }; |
443 |
426 |
|
427 void VMThread::check_for_forced_cleanup() { |
|
428 MonitorLocker mq(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag); |
|
429 mq.notify(); |
|
430 } |
|
431 |
444 VM_Operation* VMThread::no_op_safepoint() { |
432 VM_Operation* VMThread::no_op_safepoint() { |
445 // Check for handshakes first since we may need to return a VMop. |
433 // Check for handshakes first since we may need to return a VMop. |
446 if (HandshakeALot) { |
434 if (HandshakeALot) { |
447 HandshakeALotTC haltc; |
435 HandshakeALotTC haltc; |
448 Handshake::execute(&haltc); |
436 Handshake::execute(&haltc); |
449 } |
437 } |
450 // Check for a cleanup before SafepointALot to keep stats correct. |
438 // Check for a cleanup before SafepointALot to keep stats correct. |
451 long interval_ms = SafepointTracing::time_since_last_safepoint_ms(); |
439 long interval_ms = SafepointTracing::time_since_last_safepoint_ms(); |
452 bool max_time_exceeded = GuaranteedSafepointInterval != 0 && |
440 bool max_time_exceeded = GuaranteedSafepointInterval != 0 && |
453 (interval_ms >= GuaranteedSafepointInterval); |
441 (interval_ms >= GuaranteedSafepointInterval); |
454 if (max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) { |
442 if ((max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) || |
|
443 SafepointSynchronize::is_forced_cleanup_needed()) { |
455 return &cleanup_op; |
444 return &cleanup_op; |
456 } |
445 } |
457 if (SafepointALot) { |
446 if (SafepointALot) { |
458 return &safepointALot_op; |
447 return &safepointALot_op; |
459 } |
448 } |
478 // Look for new operation |
467 // Look for new operation |
479 assert(_cur_vm_operation == NULL, "no current one should be executing"); |
468 assert(_cur_vm_operation == NULL, "no current one should be executing"); |
480 _cur_vm_operation = _vm_queue->remove_next(); |
469 _cur_vm_operation = _vm_queue->remove_next(); |
481 |
470 |
482 // Stall time tracking code |
471 // Stall time tracking code |
483 if (PrintVMQWaitTime && _cur_vm_operation != NULL && |
472 if (PrintVMQWaitTime && _cur_vm_operation != NULL) { |
484 !_cur_vm_operation->evaluate_concurrently()) { |
|
485 long stall = os::javaTimeMillis() - _cur_vm_operation->timestamp(); |
473 long stall = os::javaTimeMillis() - _cur_vm_operation->timestamp(); |
486 if (stall > 0) |
474 if (stall > 0) |
487 tty->print_cr("%s stall: %ld", _cur_vm_operation->name(), stall); |
475 tty->print_cr("%s stall: %ld", _cur_vm_operation->name(), stall); |
488 } |
476 } |
489 |
477 |
490 while (!should_terminate() && _cur_vm_operation == NULL) { |
478 while (!should_terminate() && _cur_vm_operation == NULL) { |
491 // wait with a timeout to guarantee safepoints at regular intervals |
479 // wait with a timeout to guarantee safepoints at regular intervals |
492 bool timedout = |
480 // (if there is cleanup work to do) |
493 mu_queue.wait(GuaranteedSafepointInterval); |
481 (void)mu_queue.wait(GuaranteedSafepointInterval); |
494 |
482 |
495 // Support for self destruction |
483 // Support for self destruction |
496 if ((SelfDestructTimer != 0) && !VMError::is_error_reported() && |
484 if ((SelfDestructTimer != 0) && !VMError::is_error_reported() && |
497 (os::elapsedTime() > (double)SelfDestructTimer * 60.0)) { |
485 (os::elapsedTime() > (double)SelfDestructTimer * 60.0)) { |
498 tty->print_cr("VM self-destructed"); |
486 tty->print_cr("VM self-destructed"); |
499 exit(-1); |
487 exit(-1); |
500 } |
488 } |
501 |
489 |
502 if (timedout) { |
490 // If the queue contains a safepoint VM op, |
|
491 // clean up will be done so we can skip this part. |
|
492 if (!_vm_queue->peek_at_safepoint_priority()) { |
|
493 |
503 // Have to unlock VMOperationQueue_lock just in case no_op_safepoint() |
494 // Have to unlock VMOperationQueue_lock just in case no_op_safepoint() |
504 // has to do a handshake. |
495 // has to do a handshake when HandshakeALot is enabled. |
505 MutexUnlocker mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag); |
496 MutexUnlocker mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag); |
506 if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) { |
497 if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) { |
507 // Force a safepoint since we have not had one for at least |
498 // Force a safepoint since we have not had one for at least |
508 // 'GuaranteedSafepointInterval' milliseconds and we need to clean |
499 // 'GuaranteedSafepointInterval' milliseconds and we need to clean |
509 // something. This will run all the clean-up processing that needs |
500 // something. This will run all the clean-up processing that needs |
622 // |
613 // |
623 // Notify (potential) waiting Java thread(s) |
614 // Notify (potential) waiting Java thread(s) |
624 { MonitorLocker mu(VMOperationRequest_lock, Mutex::_no_safepoint_check_flag); |
615 { MonitorLocker mu(VMOperationRequest_lock, Mutex::_no_safepoint_check_flag); |
625 mu.notify_all(); |
616 mu.notify_all(); |
626 } |
617 } |
627 |
|
628 // We want to make sure that we get to a safepoint regularly |
|
629 // even when executing VMops that don't require safepoints. |
|
630 if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) { |
|
631 HandleMark hm(VMThread::vm_thread()); |
|
632 SafepointSynchronize::begin(); |
|
633 SafepointSynchronize::end(); |
|
634 _cur_vm_operation = NULL; |
|
635 } |
|
636 } |
618 } |
637 } |
619 } |
638 |
620 |
639 // A SkipGCALot object is used to elide the usual effect of gc-a-lot |
621 // A SkipGCALot object is used to elide the usual effect of gc-a-lot |
640 // over a section of execution by a thread. Currently, it's used only to |
622 // over a section of execution by a thread. Currently, it's used only to |
665 Thread* t = Thread::current(); |
647 Thread* t = Thread::current(); |
666 |
648 |
667 if (!t->is_VM_thread()) { |
649 if (!t->is_VM_thread()) { |
668 SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot |
650 SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot |
669 // JavaThread or WatcherThread |
651 // JavaThread or WatcherThread |
670 bool concurrent = op->evaluate_concurrently(); |
652 t->check_for_valid_safepoint_state(); |
671 // only blocking VM operations need to verify the caller's safepoint state: |
|
672 if (!concurrent) { |
|
673 t->check_for_valid_safepoint_state(); |
|
674 } |
|
675 |
653 |
676 // New request from Java thread, evaluate prologue |
654 // New request from Java thread, evaluate prologue |
677 if (!op->doit_prologue()) { |
655 if (!op->doit_prologue()) { |
678 return; // op was cancelled |
656 return; // op was cancelled |
679 } |
657 } |
680 |
658 |
681 // Setup VM_operations for execution |
659 // Setup VM_operations for execution |
682 op->set_calling_thread(t); |
660 op->set_calling_thread(t); |
683 |
661 |
684 // It does not make sense to execute the epilogue, if the VM operation object is getting |
662 // Get ticket number for the VM operation |
685 // deallocated by the VM thread. |
663 int ticket = t->vm_operation_ticket(); |
686 bool execute_epilog = !op->is_cheap_allocated(); |
|
687 assert(!concurrent || op->is_cheap_allocated(), "concurrent => cheap_allocated"); |
|
688 |
|
689 // Get ticket number for non-concurrent VM operations |
|
690 int ticket = 0; |
|
691 if (!concurrent) { |
|
692 ticket = t->vm_operation_ticket(); |
|
693 } |
|
694 |
664 |
695 // Add VM operation to list of waiting threads. We are guaranteed not to block while holding the |
665 // Add VM operation to list of waiting threads. We are guaranteed not to block while holding the |
696 // VMOperationQueue_lock, so we can block without a safepoint check. This allows vm operation requests |
666 // VMOperationQueue_lock, so we can block without a safepoint check. This allows vm operation requests |
697 // to be queued up during a safepoint synchronization. |
667 // to be queued up during a safepoint synchronization. |
698 { |
668 { |
700 log_debug(vmthread)("Adding VM operation: %s", op->name()); |
670 log_debug(vmthread)("Adding VM operation: %s", op->name()); |
701 _vm_queue->add(op); |
671 _vm_queue->add(op); |
702 op->set_timestamp(os::javaTimeMillis()); |
672 op->set_timestamp(os::javaTimeMillis()); |
703 ml.notify(); |
673 ml.notify(); |
704 } |
674 } |
705 |
675 { |
706 if (!concurrent) { |
676 // Wait for completion of request |
707 // Wait for completion of request (non-concurrent) |
|
708 // Note: only a JavaThread triggers the safepoint check when locking |
677 // Note: only a JavaThread triggers the safepoint check when locking |
709 MonitorLocker ml(VMOperationRequest_lock, |
678 MonitorLocker ml(VMOperationRequest_lock, |
710 t->is_Java_thread() ? Mutex::_safepoint_check_flag : Mutex::_no_safepoint_check_flag); |
679 t->is_Java_thread() ? Mutex::_safepoint_check_flag : Mutex::_no_safepoint_check_flag); |
711 while(t->vm_operation_completed_count() < ticket) { |
680 while(t->vm_operation_completed_count() < ticket) { |
712 ml.wait(); |
681 ml.wait(); |
713 } |
682 } |
714 } |
683 } |
715 |
684 op->doit_epilogue(); |
716 if (execute_epilog) { |
|
717 op->doit_epilogue(); |
|
718 } |
|
719 } else { |
685 } else { |
720 // invoked by VM thread; usually nested VM operation |
686 // invoked by VM thread; usually nested VM operation |
721 assert(t->is_VM_thread(), "must be a VM thread"); |
687 assert(t->is_VM_thread(), "must be a VM thread"); |
722 VM_Operation* prev_vm_operation = vm_operation(); |
688 VM_Operation* prev_vm_operation = vm_operation(); |
723 if (prev_vm_operation != NULL) { |
689 if (prev_vm_operation != NULL) { |