RFR: 8231289: Disentangle JvmtiRawMonitor from ObjectMonitor and clean it up
David Holmes
david.holmes at oracle.com
Mon Oct 7 11:33:16 UTC 2019
Hi Serguei,
One follow up ...
On 7/10/2019 5:45 pm, serguei.spitsyn at oracle.com wrote:
> Hi David,
>
> Thank you for replies!
>
>
> On 10/3/19 18:59, David Holmes wrote:
>> Hi Serguei,
>>
>> Just coming back to your original review emails to ensure everything
>> covered.
>>
>> On 2/10/2019 6:57 pm, serguei.spitsyn at oracle.com wrote:
>>> I forgot to say, the fix looks pretty good to me.
>>> Also, it is quite educational. :)
>>
>> Thanks :)
>>
>>> On 10/2/19 01:51, serguei.spitsyn at oracle.com wrote:
>>>> Hi David,
>>>>
>>>> http://cr.openjdk.java.net/~dholmes/8231289/webrev/src/hotspot/share/services/threadService.cpp.frames.html
>>>>
>>>>
>>>> Minor comment:
>>>> 397 waitingToLockMonitor = jt->current_pending_monitor();
>>>> 398 if (waitingToLockMonitor == NULL) {
>>>> 399 // we can only be blocked on a raw monitor if not blocked on an
>>>> ObjectMonitor
>>>> 400 waitingToLockRawMonitor = jt->current_pending_raw_monitor();
>>>> 401 }
>>>> 402 if (concurrent_locks) {
>>>> 403 waitingToLockBlocker = jt->current_park_blocker();
>>>> 404 }
>>>> If I understand correctly, a thread can wait to lock only one of the
>>>> three locks.
>>>> So, we could rewrite the line 402 as:
>>>> if (concurrent_locks &&waitingToLockRawMonitor == NULL) {
>>>>
>>>> But I do not care much about this pre-existed logic.
>>
>> We now know this is not true.
>
> Right, thanks.
>
>
>>>>
>>>> Maybe adding an assert after the line 404 would make sense:
>>>> assert(waitingToLockRawMonitor == NULL || waitingToLockBlocker ==
>>>> NULL, "invariant");
>>>
>>> This assert above can be enhanced:
>>> assert(waitingToLockMonitor == NULL || waitingToLockRawMonitor ==
>>> NULL
>>> || waitingToLockBlocker ==
>>> NULL, "invariant");
>>
>> Again we now know this is not a valid assert.
>
> Right. But this one has to be valid:
> assert((waitingToLockMonitor == NULL && waitingToLockRawMonitor ==
> NULL) ||
> waitingToLockBlocker == NULL, "invariant");
I don't quite follow what that is asserting. But I'm not certain that
the waitingToBlockLocker must be NULL if either of the other two is
non-NULL. Given there exists a "method entry" event it would seem
possible to enter a JVMTI callback for that event after setting the
object that "waitingToBlockLocker" returns - which is done in
LockSupport.park.
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, 0L);
setBlocker(t, null);
}
David
-----
>
>>> http://cr.openjdk.java.net/~dholmes/8231289/webrev/src/hotspot/share/runtime/thread.hpp.frames.html
>>>
>>>> 801 ParkEvent * _ParkEvent; // for Object monitors and JVMTI raw
>>>> monitors
>>>> We have an enhancement about the ParkEvent shared between
>>>> ObjectMonitor's and RawMonitor's:
>>>> https://bugs.openjdk.java.net/browse/JDK-8033399
>>>>
>>>> Just wanted to hear your quick opinion if this enhancement still
>>>> needs to be fixed.
>>>> I see you comment in the bug report but confused why this is not a
>>>> problem anymore.
>>>> We may want to discuss it separately (e.g in the bug report comments).
>>
>> Discussed elsewhere.
>>>
>>>>
>>>> It would be good to also run the jdk com/sun/jdi tests.
>>>> The jdwp agent library is using the JVMTI RawMonitor's.
>>
>> Tests run - no issues.
>
> Thank you for checking!
>
> Thanks,
> Serguei
>
>>
>> Thanks,
>> David
>>>>
>>>> Thanks,
>>>> Serguei
>>>>
>>>>
>>>> On 9/23/19 22:09, David Holmes wrote:
>>>>> Bug: https://bugs.openjdk.java.net/browse/JDK-8231289
>>>>> webrev: http://cr.openjdk.java.net/~dholmes/8231289/webrev/
>>>>>
>>>>> The earlier attempt to rewrite JvmtiRawMonitor as a simple wrapper
>>>>> around PlatformMonitor proved not so simple and ultimately had too
>>>>> many issues due to the need to support Thread.interrupt.
>>>>>
>>>>> I'd previously stated in the bug report:
>>>>>
>>>>> "In the worst-case I suppose we could just copy ObjectMonitor to a
>>>>> new class and have JvmtiRawMonitor continue to extend that (with
>>>>> some additional minor adjustments) - or even just inline it all as
>>>>> needed."
>>>>>
>>>>> but hadn't looked at it in detail. Richard Reingruber did look at
>>>>> it and pointed out that it is actually quite simple - we barely use
>>>>> any actual code from ObjectMonitor, mainly just the state. So
>>>>> thanks Richard! :)
>>>>>
>>>>> So this change basically copies or moves anything needed by
>>>>> JvmtiRawMonitor from ObjectMonitor, breaking the connection between
>>>>> the two. We also copy and simplify ObjectWaiter, turning it into a
>>>>> QNode internal class. There is then a lot of cleanup that was
>>>>> applied (and a lot more that could still be done):
>>>>>
>>>>> - Removed the never implemented/used PROPER_TRANSITIONS ifdefs
>>>>> - Fixed the disconnect between the types of non-JavaThreads
>>>>> expected by the upper layer code and lower layer code
>>>>> - cleaned up and simplified return codes
>>>>> - consolidated code that is identical for JavaThreads and
>>>>> non-JavaThreads (e.g. notify/notifyAll).
>>>>> - removed used of TRAPS/THREAD where not appropriate and replaced
>>>>> with "Thread * Self" in the style of the rest of the code
>>>>> - changed recursions to be int rather than intptr_t (a "fixme" in
>>>>> the ObjectMonitor code)
>>>>>
>>>>>
>>>>> I have not changed the many style flaws with this code:
>>>>> - Capitalized names
>>>>> - extra spaces before ;
>>>>> - ...
>>>>>
>>>>> but could do so if needed. I wanted to try and keep it more obvious
>>>>> that the fundamental functional code is actually unmodified.
>>>>>
>>>>> There is one aspect that requires further explanation: the notion
>>>>> of current pending monitor. The "current pending monitor" is stored
>>>>> in the Thread and used by a number of introspection APIs for things
>>>>> like finding monitors, doing deadlock detection, etc. The
>>>>> JvmtiRawMonitor code would also set/clear itself as "current
>>>>> pending monitor". Most uses of the current pending monitor
>>>>> actually, explicitly or implicitly, ignore the case when the
>>>>> monitor is a JvmtiRawMonitor (observed by the fact the
>>>>> mon->object() query returns NULL). The exception to that is
>>>>> deadlock detection where raw monitors are at least partially
>>>>> accounted for. To preserve that I added the notion of "current
>>>>> pending raw monitor" and updated the deadlock detection code to use
>>>>> that.
>>>>>
>>>>> The test:
>>>>>
>>>>>
>>>>> test/hotspot/jtreg/vmTestbase/nsk/jvmti/RawMonitorWait/rawmnwait005/rawmnwait005.cpp
>>>>>
>>>>>
>>>>> was updated because I'd noticed previously that it was the only
>>>>> test that used interrupt with raw monitors, but was in fact broken:
>>>>> the test thread is a daemon thread so the main thread could
>>>>> terminate the VM immediately after the interrupt() call, thus you
>>>>> would never know if the interruption actually worked as expected.
>>>>>
>>>>> Testing:
>>>>> - tiers 1 - 3
>>>>> - vmTestbase/nsk/monitoring/ (for deadlock detection**)
>>>>> - vmTestbase/nsk/jdwp
>>>>> - vmTestbase/nsk/jdb/
>>>>> - vmTestbase/nsk/jdi/
>>>>> - vmTestbase/nsk/jvmti/
>>>>> - serviceability/jvmti/
>>>>> - serviceability/jdwp
>>>>> - JDK: java/lang/management
>>>>>
>>>>> ** There are no existing deadlock related tests involving
>>>>> JvmtiRawMonitor. It would be interesting/useful to add them to the
>>>>> existing nsk/monitoring tests that cover synchronized and JNI
>>>>> locking. But it's a non-trivial enhancement that I don't really
>>>>> have time to do.
>>>>>
>>>>> Thanks,
>>>>> David
>>>>> -----
>>>>
>>>
>
More information about the serviceability-dev
mailing list