Mercurial > hg > graal-jvmci-8
comparison src/share/vm/classfile/classLoaderData.cpp @ 9075:ba42fd5e00e6
8010196: NPG: Internal Error: Metaspace allocation lock -- possible deadlock
Summary: Refactor the CLD dependency list into a separate class. Use an ObjectLocker to synchronize additions to the CLD dependency list.
Reviewed-by: stefank, coleenp
author | mgerdin |
---|---|
date | Wed, 10 Apr 2013 13:27:35 +0200 |
parents | 16885e702c88 |
children | d587a5c30bd8 c23dbf0e8ab7 |
comparison
equal
deleted
inserted
replaced
9074:63f57a8c5283 | 9075:ba42fd5e00e6 |
---|---|
68 ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) : | 68 ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) : |
69 _class_loader(h_class_loader()), | 69 _class_loader(h_class_loader()), |
70 _is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially | 70 _is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially |
71 _metaspace(NULL), _unloading(false), _klasses(NULL), | 71 _metaspace(NULL), _unloading(false), _klasses(NULL), |
72 _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), | 72 _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), |
73 _next(NULL), _dependencies(NULL), | 73 _next(NULL), _dependencies(), |
74 _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { | 74 _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { |
75 // empty | 75 // empty |
76 } | 76 } |
77 | 77 |
78 void ClassLoaderData::init_dependencies(TRAPS) { | 78 void ClassLoaderData::init_dependencies(TRAPS) { |
79 _dependencies.init(CHECK); | |
80 } | |
81 | |
82 void ClassLoaderData::Dependencies::init(TRAPS) { | |
79 // Create empty dependencies array to add to. CMS requires this to be | 83 // Create empty dependencies array to add to. CMS requires this to be |
80 // an oop so that it can track additions via card marks. We think. | 84 // an oop so that it can track additions via card marks. We think. |
81 _dependencies = (oop)oopFactory::new_objectArray(2, CHECK); | 85 _list_head = oopFactory::new_objectArray(2, CHECK); |
82 } | 86 } |
83 | 87 |
84 bool ClassLoaderData::claim() { | 88 bool ClassLoaderData::claim() { |
85 if (_claimed == 1) { | 89 if (_claimed == 1) { |
86 return false; | 90 return false; |
93 if (must_claim && !claim()) { | 97 if (must_claim && !claim()) { |
94 return; | 98 return; |
95 } | 99 } |
96 | 100 |
97 f->do_oop(&_class_loader); | 101 f->do_oop(&_class_loader); |
98 f->do_oop(&_dependencies); | 102 _dependencies.oops_do(f); |
99 _handles->oops_do(f); | 103 _handles->oops_do(f); |
100 if (klass_closure != NULL) { | 104 if (klass_closure != NULL) { |
101 classes_do(klass_closure); | 105 classes_do(klass_closure); |
102 } | 106 } |
107 } | |
108 | |
109 void ClassLoaderData::Dependencies::oops_do(OopClosure* f) { | |
110 f->do_oop((oop*)&_list_head); | |
103 } | 111 } |
104 | 112 |
105 void ClassLoaderData::classes_do(KlassClosure* klass_closure) { | 113 void ClassLoaderData::classes_do(KlassClosure* klass_closure) { |
106 for (Klass* k = _klasses; k != NULL; k = k->next_link()) { | 114 for (Klass* k = _klasses; k != NULL; k = k->next_link()) { |
107 klass_closure->do_klass(k); | 115 klass_closure->do_klass(k); |
152 } | 160 } |
153 | 161 |
154 // It's a dependency we won't find through GC, add it. This is relatively rare | 162 // It's a dependency we won't find through GC, add it. This is relatively rare |
155 // Must handle over GC point. | 163 // Must handle over GC point. |
156 Handle dependency(THREAD, to); | 164 Handle dependency(THREAD, to); |
157 from_cld->add_dependency(dependency, CHECK); | 165 from_cld->_dependencies.add(dependency, CHECK); |
158 } | 166 } |
159 | 167 |
160 | 168 |
161 void ClassLoaderData::add_dependency(Handle dependency, TRAPS) { | 169 void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) { |
162 // Check first if this dependency is already in the list. | 170 // Check first if this dependency is already in the list. |
163 // Save a pointer to the last to add to under the lock. | 171 // Save a pointer to the last to add to under the lock. |
164 objArrayOop ok = (objArrayOop)_dependencies; | 172 objArrayOop ok = _list_head; |
165 objArrayOop last = NULL; | 173 objArrayOop last = NULL; |
166 while (ok != NULL) { | 174 while (ok != NULL) { |
167 last = ok; | 175 last = ok; |
168 if (ok->obj_at(0) == dependency()) { | 176 if (ok->obj_at(0) == dependency()) { |
169 // Don't need to add it | 177 // Don't need to add it |
182 | 190 |
183 // Must handle over GC points | 191 // Must handle over GC points |
184 objArrayHandle new_dependency(THREAD, deps); | 192 objArrayHandle new_dependency(THREAD, deps); |
185 | 193 |
186 // Add the dependency under lock | 194 // Add the dependency under lock |
187 locked_add_dependency(last_handle, new_dependency); | 195 locked_add(last_handle, new_dependency, THREAD); |
188 } | 196 } |
189 | 197 |
190 void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle, | 198 void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle, |
191 objArrayHandle new_dependency) { | 199 objArrayHandle new_dependency, |
200 Thread* THREAD) { | |
192 | 201 |
193 // Have to lock and put the new dependency on the end of the dependency | 202 // Have to lock and put the new dependency on the end of the dependency |
194 // array so the card mark for CMS sees that this dependency is new. | 203 // array so the card mark for CMS sees that this dependency is new. |
195 // Can probably do this lock free with some effort. | 204 // Can probably do this lock free with some effort. |
196 MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); | 205 ObjectLocker ol(Handle(THREAD, _list_head), THREAD); |
197 | 206 |
198 oop loader_or_mirror = new_dependency->obj_at(0); | 207 oop loader_or_mirror = new_dependency->obj_at(0); |
199 | 208 |
200 // Since the dependencies are only added, add to the end. | 209 // Since the dependencies are only added, add to the end. |
201 objArrayOop end = last_handle(); | 210 objArrayOop end = last_handle(); |