8210155: Lock ClassLoaderDataGraph
Summary: In preparation for concurrent class unloading.
Reviewed-by: hseigel, eosterlund
--- a/src/hotspot/share/classfile/classLoaderData.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/classfile/classLoaderData.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -544,6 +544,7 @@
static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator;
InstanceKlass* ClassLoaderDataGraph::try_get_next_class() {
+ assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
return static_klass_iterator.try_get_next_class();
}
@@ -895,6 +896,7 @@
}
void ClassLoaderDataGraph::clean_deallocate_lists(bool walk_previous_versions) {
+ assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint");
uint loaders_processed = 0;
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
// is_alive check will be necessary for concurrent class unloading.
@@ -1065,43 +1067,43 @@
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) {
- NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the
- // ClassLoaderData in the graph since the CLD
- // contains oops in _handles that must be walked.
+
- ClassLoaderData* cld = new ClassLoaderData(loader, is_unsafe_anonymous);
+ ClassLoaderData* cld;
+ {
+ NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the
+ // ClassLoaderData in the loader since the CLD
+ // contains oops in _handles that must be walked.
+ // GC will find the CLD through the loader after this.
- if (!is_unsafe_anonymous) {
- // First, Atomically set it
- ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL);
- if (old != NULL) {
- delete cld;
- // Returns the data.
- return old;
+ cld = new ClassLoaderData(loader, is_unsafe_anonymous);
+
+ if (!is_unsafe_anonymous) {
+ // First, Atomically set it
+ ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL);
+ if (old != NULL) {
+ delete cld;
+ // Returns the data.
+ return old;
+ }
}
}
+ MutexLocker ml(ClassLoaderDataGraph_lock);
+
// We won the race, and therefore the task of adding the data to the list of
// class loader data
- ClassLoaderData** list_head = &_head;
- ClassLoaderData* next = _head;
-
- do {
- cld->set_next(next);
- ClassLoaderData* exchanged = Atomic::cmpxchg(cld, list_head, next);
- if (exchanged == next) {
- LogTarget(Trace, class, loader, data) lt;
- if (lt.is_enabled()) {
- ResourceMark rm;
- LogStream ls(lt);
- ls.print("create ");
- cld->print_value_on(&ls);
- ls.cr();
- }
- return cld;
- }
- next = exchanged;
- } while (true);
+ cld->set_next(_head);
+ _head = cld;
+ LogTarget(Trace, class, loader, data) lt;
+ if (lt.is_enabled()) {
+ ResourceMark rm;
+ LogStream ls(lt);
+ ls.print("create ");
+ cld->print_value_on(&ls);
+ ls.cr();
+ }
+ return cld;
}
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) {
@@ -1115,13 +1117,14 @@
}
void ClassLoaderDataGraph::cld_do(CLDClosure* cl) {
- for (ClassLoaderData* cld = _head; cl != NULL && cld != NULL; cld = cld->next()) {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
+ for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
cl->do_cld(cld);
}
}
void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
// Only walk the head until any clds not purged from prior unloading
// (CMS doesn't purge right away).
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
@@ -1131,6 +1134,7 @@
}
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
CLDClosure* closure = cld->keep_alive() ? strong : weak;
if (closure != NULL) {
@@ -1140,6 +1144,7 @@
}
void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
if (ClassUnloading) {
roots_cld_do(cl, NULL);
} else {
@@ -1147,41 +1152,90 @@
}
}
+// Closure for locking and iterating through classes.
+LockedClassesDo::LockedClassesDo(classes_do_func_t f) : _function(f) {
+ ClassLoaderDataGraph_lock->lock();
+}
+
+LockedClassesDo::LockedClassesDo() : _function(NULL) {
+ // callers provide their own do_klass
+ ClassLoaderDataGraph_lock->lock();
+}
+
+LockedClassesDo::~LockedClassesDo() { ClassLoaderDataGraph_lock->unlock(); }
+
+
+// Iterating over the CLDG needs to be locked because
+// unloading can remove entries concurrently soon.
+class ClassLoaderDataGraphIterator : public StackObj {
+ ClassLoaderData* _next;
+ HandleMark _hm; // clean up handles when this is done.
+ Handle _holder;
+ Thread* _thread;
+
+ void hold_next() {
+ if (_next != NULL) {
+ _holder = Handle(_thread, _next->holder_phantom());
+ }
+ }
+public:
+ ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head) {
+ _thread = Thread::current();
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
+ hold_next();
+ }
+
+ bool repeat() const {
+ return _next != NULL;
+ }
+
+ ClassLoaderData* get_next() {
+ ClassLoaderData* next = _next;
+ if (_next != NULL) {
+ _next = _next->next();
+ hold_next();
+ }
+ return next;
+ }
+};
+
+// These functions assume that the caller has locked the ClassLoaderDataGraph_lock
+// if they are not calling the function from a safepoint.
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
- Thread* thread = Thread::current();
- for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- Handle holder(thread, cld->holder_phantom());
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
cld->classes_do(klass_closure);
}
}
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
- Thread* thread = Thread::current();
- for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- Handle holder(thread, cld->holder_phantom());
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
cld->classes_do(f);
}
}
void ClassLoaderDataGraph::methods_do(void f(Method*)) {
- Thread* thread = Thread::current();
- for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- Handle holder(thread, cld->holder_phantom());
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
cld->methods_do(f);
}
}
void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
assert_locked_or_safepoint(Module_lock);
- Thread* thread = Thread::current();
- for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- Handle holder(thread, cld->holder_phantom());
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
cld->modules_do(f);
}
}
void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
// Only walk the head until any clds not purged from prior unloading
// (CMS doesn't purge right away).
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
@@ -1192,15 +1246,15 @@
void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
assert_locked_or_safepoint(Module_lock);
- Thread* thread = Thread::current();
- for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- Handle holder(thread, cld->holder_phantom());
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
cld->packages_do(f);
}
}
void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
// Only walk the head until any clds not purged from prior unloading
// (CMS doesn't purge right away).
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
@@ -1210,15 +1264,23 @@
}
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
- Thread* thread = Thread::current();
- for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- Handle holder(thread, cld->holder_phantom());
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
cld->loaded_classes_do(klass_closure);
}
}
+// This case can block but cannot do unloading (called from CDS)
+void ClassLoaderDataGraph::unlocked_loaded_classes_do(KlassClosure* klass_closure) {
+ for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+ cld->loaded_classes_do(klass_closure);
+ }
+}
+
+
void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
// Only walk the head until any clds not purged from prior unloading
// (CMS doesn't purge right away).
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
@@ -1227,24 +1289,22 @@
}
}
-#define FOR_ALL_DICTIONARY(X) for (ClassLoaderData* X = _head; X != NULL; X = X->next()) \
- if (X->dictionary() != NULL)
+#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \
+ ClassLoaderData* X; \
+ while ((X = iter.get_next()) != NULL) \
+ if (X->dictionary() != NULL)
// Walk classes in the loaded class dictionaries in various forms.
// Only walks the classes defined in this class loader.
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
- Thread* thread = Thread::current();
FOR_ALL_DICTIONARY(cld) {
- Handle holder(thread, cld->holder_phantom());
cld->dictionary()->classes_do(f);
}
}
// Only walks the classes defined in this class loader.
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
- Thread* thread = Thread::current();
FOR_ALL_DICTIONARY(cld) {
- Handle holder(thread, cld->holder_phantom());
cld->dictionary()->classes_do(f, CHECK);
}
}
@@ -1275,6 +1335,7 @@
}
GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
@@ -1301,6 +1362,7 @@
#ifndef PRODUCT
bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
if (loader_data == data) {
return true;
@@ -1314,6 +1376,7 @@
// Move class loader data from main list to the unloaded list for unloading
// and deallocation later.
bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
// Indicate whether safepoint cleanup is needed.
_safepoint_cleanup_needed |= do_cleaning;
@@ -1362,6 +1425,8 @@
// There's at least one dead class loader. Purge refererences of healthy module
// reads lists and package export lists to modules belonging to dead loaders.
void ClassLoaderDataGraph::clean_module_and_package_info() {
+ assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
+
ClassLoaderData* data = _head;
while (data != NULL) {
// Remove entries in the dictionary of live class loader that have
@@ -1418,6 +1483,7 @@
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
: _next_klass(NULL) {
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
Klass* klass = NULL;
@@ -1474,6 +1540,7 @@
}
ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() {
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
_data = ClassLoaderDataGraph::_head;
}
@@ -1488,14 +1555,18 @@
}
void ClassLoaderDataGraph::verify() {
- for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
- data->verify();
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
+ cld->verify();
}
}
void ClassLoaderDataGraph::print_on(outputStream * const out) {
- for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
- data->print_on(out);
+ ClassLoaderDataGraphIterator iter;
+ while (iter.repeat()) {
+ ClassLoaderData* cld = iter.get_next();
+ cld->print_on(out);
}
}
#endif // PRODUCT
--- a/src/hotspot/share/classfile/classLoaderData.hpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/classfile/classLoaderData.hpp Fri Aug 31 07:03:46 2018 -0400
@@ -70,6 +70,7 @@
friend class ClassLoaderDataGraphMetaspaceIterator;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphKlassIteratorStatic;
+ friend class ClassLoaderDataGraphIterator;
friend class VMStructs;
private:
// All CLDs (except the null CLD) can be reached by walking _head->_next->...
@@ -118,6 +119,7 @@
static void packages_do(void f(PackageEntry*));
static void packages_unloading_do(void f(PackageEntry*));
static void loaded_classes_do(KlassClosure* klass_closure);
+ static void unlocked_loaded_classes_do(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const));
static bool do_unloading(bool do_cleaning);
@@ -177,6 +179,20 @@
#endif
};
+class LockedClassesDo : public KlassClosure {
+ typedef void (*classes_do_func_t)(Klass*);
+ classes_do_func_t _function;
+public:
+ LockedClassesDo(); // For callers who provide their own do_klass
+ LockedClassesDo(classes_do_func_t function);
+ ~LockedClassesDo();
+
+ void do_klass(Klass* k) {
+ (*_function)(k);
+ }
+};
+
+
// ClassLoaderData class
class ClassLoaderData : public CHeapObj<mtClass> {
@@ -213,6 +229,7 @@
};
friend class ClassLoaderDataGraph;
+ friend class ClassLoaderDataGraphIterator;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphKlassIteratorStatic;
friend class ClassLoaderDataGraphMetaspaceIterator;
--- a/src/hotspot/share/classfile/systemDictionary.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/classfile/systemDictionary.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -1919,6 +1919,7 @@
void SystemDictionary::methods_do(void f(Method*)) {
// Walk methods in loaded classes
+ MutexLocker ml(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::methods_do(f);
// Walk method handle intrinsics
invoke_method_table()->methods_do(f);
@@ -1936,6 +1937,7 @@
void SystemDictionary::remove_classes_in_error_state() {
ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
RemoveClassesClosure rcc;
+ MutexLocker ml(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::cld_do(&rcc);
}
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -4074,6 +4074,8 @@
// The freelist lock is needed to prevent asserts, is it really needed?
void CMSCollector::preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) {
+ // Needed to walk CLDG
+ MutexLocker ml(ClassLoaderDataGraph_lock);
cl->set_freelistLock(freelistLock);
--- a/src/hotspot/share/jfr/periodic/jfrModuleEvent.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/jfr/periodic/jfrModuleEvent.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -121,12 +121,14 @@
void JfrModuleEvent::generate_module_dependency_events() {
invocation_time = JfrTicks::now();
- MutexLockerEx module_lock(Module_lock);
+ MutexLocker cld_lock(ClassLoaderDataGraph_lock);
+ MutexLocker module_lock(Module_lock);
ClassLoaderDataGraph::modules_do(&module_dependency_event_callback);
}
void JfrModuleEvent::generate_module_export_events() {
invocation_time = JfrTicks::now();
- MutexLockerEx module_lock(Module_lock);
+ MutexLocker cld_lock(ClassLoaderDataGraph_lock);
+ MutexLocker module_lock(Module_lock);
ClassLoaderDataGraph::packages_do(&module_export_event_callback);
}
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -149,7 +149,9 @@
void JfrTypeManager::write_type_set() {
// can safepoint here because of Module_lock
+ MutexLockerEx cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock);
MutexLockerEx lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock);
+
JfrCheckpointWriter writer(true, true, Thread::current());
TypeSet set;
set.serialize(writer);
--- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -74,6 +74,10 @@
Module_lock->unlock();
}
+ if (ClassLoaderDataGraph_lock->owned_by_self()) {
+ ClassLoaderDataGraph_lock->unlock();
+ }
+
if (Heap_lock->owned_by_self()) {
Heap_lock->unlock();
}
--- a/src/hotspot/share/memory/heapInspection.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/memory/heapInspection.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -153,11 +153,17 @@
}
}
-void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) {
- // This has the SIDE EFFECT of creating a KlassInfoEntry
- // for <k>, if one doesn't exist yet.
- _table->lookup(k);
-}
+class KlassInfoTable::AllClassesFinder : public LockedClassesDo {
+ KlassInfoTable *_table;
+public:
+ AllClassesFinder(KlassInfoTable* table) : _table(table) {}
+ virtual void do_klass(Klass* k) {
+ // This has the SIDE EFFECT of creating a KlassInfoEntry
+ // for <k>, if one doesn't exist yet.
+ _table->lookup(k);
+ }
+};
+
KlassInfoTable::KlassInfoTable(bool add_all_classes) {
_size_of_instances_in_words = 0;
--- a/src/hotspot/share/memory/heapInspection.hpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/memory/heapInspection.hpp Fri Aug 31 07:03:46 2018 -0400
@@ -247,12 +247,7 @@
uint hash(const Klass* p);
KlassInfoEntry* lookup(Klass* k); // allocates if not found!
- class AllClassesFinder : public KlassClosure {
- KlassInfoTable *_table;
- public:
- AllClassesFinder(KlassInfoTable* table) : _table(table) {}
- virtual void do_klass(Klass* k);
- };
+ class AllClassesFinder;
public:
KlassInfoTable(bool add_all_classes);
--- a/src/hotspot/share/memory/metaspaceShared.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -1619,7 +1619,7 @@
LinkSharedClassesClosure link_closure(THREAD);
do {
link_closure.reset();
- ClassLoaderDataGraph::loaded_classes_do(&link_closure);
+ ClassLoaderDataGraph::unlocked_loaded_classes_do(&link_closure);
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
} while (link_closure.made_progress());
@@ -1631,7 +1631,7 @@
// we should come here only if there are unverifiable classes, which
// shouldn't happen in normal cases. So better safe than sorry.
check_closure.reset();
- ClassLoaderDataGraph::loaded_classes_do(&check_closure);
+ ClassLoaderDataGraph::unlocked_loaded_classes_do(&check_closure);
} while (check_closure.made_progress());
if (IgnoreUnverifiableClassesDuringDump) {
--- a/src/hotspot/share/memory/universe.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/memory/universe.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -545,6 +545,7 @@
void Universe::reinitialize_itables(TRAPS) {
+ MutexLocker mcld(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::dictionary_classes_do(initialize_itable_for_klass, CHECK);
}
--- a/src/hotspot/share/oops/klassVtable.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/oops/klassVtable.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -1595,7 +1595,8 @@
}
static void compute() {
- ClassLoaderDataGraph::classes_do(do_class);
+ LockedClassesDo locked_do_class(&do_class);
+ ClassLoaderDataGraph::classes_do(&locked_do_class);
fixed = no_klasses * oopSize; // vtable length
// filler size is a conservative approximation
filler = oopSize * (no_klasses - no_instance_klasses) * (sizeof(InstanceKlass) - sizeof(ArrayKlass) - 1);
--- a/src/hotspot/share/prims/jvmtiEnvBase.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -1489,6 +1489,7 @@
jvmtiError
JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr) {
ResourceMark rm;
+ MutexLocker mcld(ClassLoaderDataGraph_lock);
MutexLocker ml(Module_lock);
_tbl = new GrowableArray<OopHandle>(77);
--- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -107,6 +107,7 @@
// Iterate through all classes in ClassLoaderDataGraph
// and collect them using the LoadedClassesClosure
+ MutexLocker mcld(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::loaded_classes_do(&closure);
}
--- a/src/hotspot/share/prims/whitebox.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/prims/whitebox.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -146,7 +146,7 @@
return os::large_page_size();
WB_END
-class WBIsKlassAliveClosure : public KlassClosure {
+class WBIsKlassAliveClosure : public LockedClassesDo {
Symbol* _name;
bool _found;
public:
--- a/src/hotspot/share/runtime/java.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/runtime/java.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -346,6 +346,7 @@
if (PrintSystemDictionaryAtExit) {
ResourceMark rm;
+ MutexLocker mcld(ClassLoaderDataGraph_lock);
SystemDictionary::print();
ClassLoaderDataGraph::print();
}
@@ -494,6 +495,7 @@
Universe::print_on(&ls_info);
if (log.is_trace()) {
LogStream ls_trace(log.trace());
+ MutexLocker mcld(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::print_on(&ls_trace);
}
}
--- a/src/hotspot/share/runtime/mutexLocker.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/runtime/mutexLocker.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -147,6 +147,7 @@
Monitor* CodeHeapStateAnalytics_lock = NULL;
Mutex* MetaspaceExpand_lock = NULL;
+Mutex* ClassLoaderDataGraph_lock = NULL;
#define MAX_NUM_MUTEX 128
static Monitor * _mutex_array[MAX_NUM_MUTEX];
@@ -224,6 +225,7 @@
def(OopMapCacheAlloc_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_always); // used for oop_map_cache allocation.
def(MetaspaceExpand_lock , PaddedMutex , leaf-1, true, Monitor::_safepoint_check_never);
+ def(ClassLoaderDataGraph_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always);
def(Patching_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never); // used for safepointing and code patching.
def(Service_lock , PaddedMonitor, special, true, Monitor::_safepoint_check_never); // used for service thread operations
--- a/src/hotspot/share/runtime/mutexLocker.hpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/runtime/mutexLocker.hpp Fri Aug 31 07:03:46 2018 -0400
@@ -145,6 +145,7 @@
#endif
extern Mutex* MetaspaceExpand_lock; // protects Metaspace virtualspace and chunk expansions
+extern Mutex* ClassLoaderDataGraph_lock; // protects CLDG list, needed for concurrent unloading
extern Monitor* CodeHeapStateAnalytics_lock; // lock print functions against concurrent analyze functions.
--- a/src/hotspot/share/services/heapDumper.cpp Fri Aug 31 12:41:00 2018 +0200
+++ b/src/hotspot/share/services/heapDumper.cpp Fri Aug 31 07:03:46 2018 -0400
@@ -1464,6 +1464,7 @@
bool skip_operation() const;
// writes a HPROF_LOAD_CLASS record
+ class ClassesDo;
static void do_load_class(Klass* k);
// writes a HPROF_GC_CLASS_DUMP record for the given class
@@ -1821,7 +1822,10 @@
SymbolTable::symbols_do(&sym_dumper);
// write HPROF_LOAD_CLASS records
- ClassLoaderDataGraph::classes_do(&do_load_class);
+ {
+ LockedClassesDo locked_load_classes(&do_load_class);
+ ClassLoaderDataGraph::classes_do(&locked_load_classes);
+ }
Universe::basic_type_classes_do(&do_load_class);
// write HPROF_FRAME and HPROF_TRACE records
@@ -1832,7 +1836,10 @@
DumperSupport::write_dump_header(writer());
// Writes HPROF_GC_CLASS_DUMP records
- ClassLoaderDataGraph::classes_do(&do_class_dump);
+ {
+ LockedClassesDo locked_dump_class(&do_class_dump);
+ ClassLoaderDataGraph::classes_do(&locked_dump_class);
+ }
Universe::basic_type_classes_do(&do_basic_type_array_class_dump);
check_segment_length();