RFR(S) 8231125 Improve testing of parallel loading of shared classes by the boot class loader
coleen.phillimore at oracle.com
coleen.phillimore at oracle.com
Thu Sep 19 15:14:28 UTC 2019
On 9/18/19 11:30 PM, Ioi Lam wrote:
>
>
> On 9/18/19 6:47 PM, coleen.phillimore at oracle.com wrote:
>>
>> I have to say that the 01 assert matched better what I thought it
>> should assert, ie. that boot class loaders cannot get to that code in
>> parallel.
>>
>> The mirror has a bunch of other logic with sharing that just
>> complicates this basic premise. Also, by asserting in the code that
>> takes out the lock, it doesn't make it clear that two threads with
>> the bootloader cannot execute that code in parallel.
>>
>
> But the problem with version 01 is two threads could both come to the
> assert at the same time, and both see that the class loader is not
> set, and then both would proceed to restore the class.
I think the assert should show that two threads cannot call
load_shared_class() at the same time, because the second thread is
waiting on the SystemDictionary_lock because it finds the class in the
Placeholder table being loaded by a different thread.
Coleen
>
> Anyway, maybe we should not put the assert in load_shared_class.
> Instead, move the assert to Klass::restore_unsharable_info():
>
> http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v03/
>
>
> I also fixed the spacing in the "for" loops in the other test file as
> requested by David.
>
> Thanks
> - Ioi
>
>> I like 01 better (except the test fixes are good).
>> thanks,
>> Coleen
>>
>> On 9/18/19 2:23 AM, Ioi Lam wrote:
>>>
>>>
>>> On 9/17/19 6:27 PM, David Holmes wrote:
>>>> Hi Ioi,
>>>>
>>>> On 18/09/2019 7:24 am, coleen.phillimore at oracle.com wrote:
>>>>> http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v01/src/hotspot/share/classfile/systemDictionary.cpp.udiff.html
>>>>>
>>>>>
>>>>> Can you add a line something like.
>>>>>
>>>>> + if (class_loader() == NULL) {
>>>>> + // See case 3 in SystemDictionary::resolve_instance_class_or_null
>>>>> + // multiple threads wait on the SystemDictionary_lock if
>>>>> the boot loader class is in the placeholder table, so only
>>>>> + // one thread loads the class.
>>>>> + assert(ik->class_loader_data() == NULL, "boot loader classes are
>>>>> not loaded in parallel");
>>>>> + }
>>>>> +
>>>>
>>>> Even with Coleen's suggested comment I still don't see what this
>>>> code has to do with loading in parallel? AFAICS all you are
>>>> asserting is that if the class is to be loaded by the boot-loader
>>>> then the class should have been dumped by the boot-loader - no?
>>>>
>>> Hi David,
>>>
>>> When we were analyzing a recent random crash that might be caused by
>>> race condition during class loading, we looked at this call to
>>> restore_unshareable_info() in SystemDictionary::load_shared_class()
>>>
>>> ClassLoaderData* loader_data =
>>> ClassLoaderData::class_loader_data(class_loader());
>>> {
>>> HandleMark hm(THREAD);
>>> Handle lockObject = compute_loader_lock_object(class_loader,
>>> THREAD);
>>> check_loader_lock_contention(lockObject, THREAD);
>>> ObjectLocker ol(lockObject, THREAD, true);
>>> // prohibited package check assumes all classes loaded from
>>> archive call
>>> // restore_unshareable_info which calls ik->set_package()
>>> ik->restore_unshareable_info(loader_data, protection_domain,
>>> CHECK_NULL);
>>> }
>>>
>>> Because all the crash seemed to be with shared classes loaded by the
>>> boot loader, we suspect that two threads competing to load the same
>>> class may arrive here simultaneously, and we will end up calling
>>> ik->restore_unshareable_info() twice, with harmful side effects.
>>>
>>> Upon further investigation, we found that this is not the case. But
>>> it will be good to have an assert to check for this -- that we won't
>>> call ik->restore_unshareable_info() more than once.
>>>
>>> I realized that I put the assert at the wrong place, and asserted on
>>> the wrong field (non-boot classes will enter load_shared_class()
>>> with ik->class_loader_data() != NULL). So I changed the assert to be
>>> on the java_mirror. That way, the assert works for shared classes
>>> for all loaders.
>>>
>>> assert(!ik->is_java_mirror_restored(), "don't load the same
>>> shared class twice");
>>> ik->restore_unshareable_info(loader_data, protection_domain,
>>> CHECK_NULL);
>>> assert(ik->is_java_mirror_restored() ||
>>> !SystemDictionary::Class_klass_loaded(), "must be");
>>>
>>> Here's an updated webrev, which also contains fixes you suggested
>>> below.
>>>
>>> Thanks
>>> - Ioi
>>>
>>>> The test seems okay - the proof is in the running :)
>>>>
>>>> One style nit:
>>>>
>>>> ! for (int i=0; i<APP_LOOPS; i++) {
>>>>
>>>> spaces around binary operators please. This seems to impact all for
>>>> loops.
>>>>
>>>> Also:
>>>>
>>>> 175 { // Avoid logging in this block so the threads
>>>> can proceeds without
>>>>
>>>> s/proceeds/proceed/
>>>>
>>>> Thanks,
>>>> David
>>>> -----
>>>>
>>>>> I wonder if the ObjectLocker is really needed for non-bootclass
>>>>> loaders below this code, since it appears to not be needed for
>>>>> boot class loaders.
>>>>>
>>>>> The test changes look good. I think you're supposed to have @bug
>>>>> tags in them.
>>>>>
>>>>> Thanks for going through this code looking for races!
>>>>> Coleen
>>>>>
>>>>>
>>>>> On 9/17/19 1:10 PM, Ioi Lam wrote:
>>>>>> https://bugs.openjdk.java.net/browse/JDK-8231125
>>>>>> http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v01/
>>>>>>
>>>>>>
>>>>>>
>>>>>> [1] Modified ParallelLoadTest.java to also test the loading of
>>>>>> shared classes
>>>>>> into the boot loader.
>>>>>> [2] Modified ParallelLoad.java to minimize the initial time lag
>>>>>> when the 4 parallel
>>>>>> threads compete to load the same class.
>>>>>> [3] Added an assert in the JVM to verify that for a shared
>>>>>> classes loaded
>>>>>> the boot class loader, SystemDictionary::load_shared_class is
>>>>>> not called
>>>>>> multiple times.
>>>>>>
>>>>>
>>>
>>
>
More information about the hotspot-runtime-dev
mailing list