mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8241390: 'Deadlock' with VM_RedefineClasses::lock_classes()
Reviewed-by: coleenp, sspitsyn
This commit is contained in:
parent
2e30ff61b0
commit
f800af978c
4 changed files with 179 additions and 9 deletions
|
@ -96,31 +96,69 @@ static inline InstanceKlass* get_ik(jclass def) {
|
|||
// If any of the classes are being redefined, wait
|
||||
// Parallel constant pool merging leads to indeterminate constant pools.
|
||||
void VM_RedefineClasses::lock_classes() {
|
||||
JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
|
||||
GrowableArray<Klass*>* redef_classes = state->get_classes_being_redefined();
|
||||
|
||||
MonitorLocker ml(RedefineClasses_lock);
|
||||
|
||||
if (redef_classes == NULL) {
|
||||
redef_classes = new(ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(1, mtClass);
|
||||
state->set_classes_being_redefined(redef_classes);
|
||||
}
|
||||
|
||||
bool has_redefined;
|
||||
do {
|
||||
has_redefined = false;
|
||||
// Go through classes each time until none are being redefined.
|
||||
// Go through classes each time until none are being redefined. Skip
|
||||
// the ones that are being redefined by this thread currently. Class file
|
||||
// load hook event may trigger new class redefine when we are redefining
|
||||
// a class (after lock_classes()).
|
||||
for (int i = 0; i < _class_count; i++) {
|
||||
if (get_ik(_class_defs[i].klass)->is_being_redefined()) {
|
||||
ml.wait();
|
||||
has_redefined = true;
|
||||
break; // for loop
|
||||
InstanceKlass* ik = get_ik(_class_defs[i].klass);
|
||||
// Check if we are currently redefining the class in this thread already.
|
||||
if (redef_classes->contains(ik)) {
|
||||
assert(ik->is_being_redefined(), "sanity");
|
||||
} else {
|
||||
if (ik->is_being_redefined()) {
|
||||
ml.wait();
|
||||
has_redefined = true;
|
||||
break; // for loop
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (has_redefined);
|
||||
|
||||
for (int i = 0; i < _class_count; i++) {
|
||||
get_ik(_class_defs[i].klass)->set_is_being_redefined(true);
|
||||
InstanceKlass* ik = get_ik(_class_defs[i].klass);
|
||||
redef_classes->push(ik); // Add to the _classes_being_redefined list
|
||||
ik->set_is_being_redefined(true);
|
||||
}
|
||||
ml.notify_all();
|
||||
}
|
||||
|
||||
void VM_RedefineClasses::unlock_classes() {
|
||||
JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
|
||||
GrowableArray<Klass*>* redef_classes = state->get_classes_being_redefined();
|
||||
assert(redef_classes != NULL, "_classes_being_redefined is not allocated");
|
||||
|
||||
MonitorLocker ml(RedefineClasses_lock);
|
||||
for (int i = 0; i < _class_count; i++) {
|
||||
assert(get_ik(_class_defs[i].klass)->is_being_redefined(),
|
||||
|
||||
for (int i = _class_count - 1; i >= 0; i--) {
|
||||
InstanceKlass* def_ik = get_ik(_class_defs[i].klass);
|
||||
if (redef_classes->length() > 0) {
|
||||
// Remove the class from _classes_being_redefined list
|
||||
Klass* k = redef_classes->pop();
|
||||
assert(def_ik == k, "unlocking wrong class");
|
||||
}
|
||||
assert(def_ik->is_being_redefined(),
|
||||
"should be being redefined to get here");
|
||||
get_ik(_class_defs[i].klass)->set_is_being_redefined(false);
|
||||
|
||||
// Unlock after we finish all redefines for this class within
|
||||
// the thread. Same class can be pushed to the list multiple
|
||||
// times (not more than once by each recursive redefinition).
|
||||
if (!redef_classes->contains(def_ik)) {
|
||||
def_ik->set_is_being_redefined(false);
|
||||
}
|
||||
}
|
||||
ml.notify_all();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue