# HG changeset patch # User ysr # Date 1244749200 25200 # Node ID 821269eca47959231598a4bf90102c41d737702f # Parent 7295839252dee314e2914ed1ce4d7ed23c7ce097 6820167: GCALotAtAllSafepoints + FullGCALot(ScavengeALot) options crash JVM Summary: Short-circuit gc-a-lot attempts by non-JavaThreads; SkipGCALot c'tor to elide re-entrant gc-a-lot attempts. Reviewed-by: apetrusenko, jcoomes, jmasa, kamg diff -r 7295839252de -r 821269eca479 src/share/vm/memory/gcLocker.hpp --- a/src/share/vm/memory/gcLocker.hpp Wed Jun 10 14:57:21 2009 -0700 +++ b/src/share/vm/memory/gcLocker.hpp Thu Jun 11 12:40:00 2009 -0700 @@ -242,6 +242,31 @@ #endif }; +// A SkipGCALot object is used to elide the usual effect of gc-a-lot +// over a section of execution by a thread. Currently, it's used only to +// prevent re-entrant calls to GC. +class SkipGCALot : public StackObj { + private: + bool _saved; + Thread* _t; + + public: +#ifdef ASSERT + SkipGCALot(Thread* t) : _t(t) { + _saved = _t->skip_gcalot(); + _t->set_skip_gcalot(true); + } + + ~SkipGCALot() { + assert(_t->skip_gcalot(), "Save-restore protocol invariant"); + _t->set_skip_gcalot(_saved); + } +#else + SkipGCALot(Thread* t) { } + ~SkipGCALot() { } +#endif +}; + // JRT_LEAF currently can be called from either _thread_in_Java or // _thread_in_native mode. In _thread_in_native, it is ok // for another thread to trigger GC. The rest of the JRT_LEAF diff -r 7295839252de -r 821269eca479 src/share/vm/runtime/interfaceSupport.cpp --- a/src/share/vm/runtime/interfaceSupport.cpp Wed Jun 10 14:57:21 2009 -0700 +++ b/src/share/vm/runtime/interfaceSupport.cpp Thu Jun 11 12:40:00 2009 -0700 @@ -66,11 +66,14 @@ void InterfaceSupport::gc_alot() { Thread *thread = Thread::current(); - if (thread->is_VM_thread()) return; // Avoid concurrent calls + if (!thread->is_Java_thread()) return; // Avoid concurrent calls // Check for new, not quite initialized thread. A thread in new mode cannot initiate a GC. JavaThread *current_thread = (JavaThread *)thread; if (current_thread->active_handles() == NULL) return; + // Short-circuit any possible re-entrant gc-a-lot attempt + if (thread->skip_gcalot()) return; + if (is_init_completed()) { if (++_fullgc_alot_invocation < FullGCALotStart) { diff -r 7295839252de -r 821269eca479 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Jun 10 14:57:21 2009 -0700 +++ b/src/share/vm/runtime/thread.cpp Thu Jun 11 12:40:00 2009 -0700 @@ -127,6 +127,7 @@ debug_only(_owned_locks = NULL;) debug_only(_allow_allocation_count = 0;) NOT_PRODUCT(_allow_safepoint_count = 0;) + NOT_PRODUCT(_skip_gcalot = false;) CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) _jvmti_env_iteration_count = 0; _vm_operation_started_count = 0; @@ -784,7 +785,6 @@ // We could enter a safepoint here and thus have a gc InterfaceSupport::check_gc_alot(); } - #endif } #endif diff -r 7295839252de -r 821269eca479 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Jun 10 14:57:21 2009 -0700 +++ b/src/share/vm/runtime/thread.hpp Thu Jun 11 12:40:00 2009 -0700 @@ -191,6 +191,9 @@ NOT_PRODUCT(int _allow_safepoint_count;) // If 0, thread allow a safepoint to happen debug_only (int _allow_allocation_count;) // If 0, the thread is allowed to allocate oops. + // Used by SkipGCALot class. + NOT_PRODUCT(bool _skip_gcalot;) // Should we elide gc-a-lot? + // Record when GC is locked out via the GC_locker mechanism CHECK_UNHANDLED_OOPS_ONLY(int _gc_locked_out_count;) @@ -308,6 +311,11 @@ bool is_gc_locked_out() { return _gc_locked_out_count > 0; } #endif // CHECK_UNHANDLED_OOPS +#ifndef PRODUCT + bool skip_gcalot() { return _skip_gcalot; } + void set_skip_gcalot(bool v) { _skip_gcalot = v; } +#endif + public: // Installs a pending exception to be inserted later static void send_async_exception(oop thread_oop, oop java_throwable); diff -r 7295839252de -r 821269eca479 src/share/vm/runtime/vmThread.cpp --- a/src/share/vm/runtime/vmThread.cpp Wed Jun 10 14:57:21 2009 -0700 +++ b/src/share/vm/runtime/vmThread.cpp Thu Jun 11 12:40:00 2009 -0700 @@ -531,6 +531,7 @@ 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(true);