Question about GetObjectMonitorUsage() JVMTI function

Daniel D. Daugherty daniel.daugherty at oracle.com
Mon Jun 15 15:13:02 UTC 2020


On 6/15/20 10:45 AM, Yasumasa Suenaga wrote:
> On 2020/06/15 22:38, Daniel D. Daugherty wrote:
>> On 6/15/20 3:26 AM, David Holmes wrote:
>>> On 15/06/2020 4:02 pm, Yasumasa Suenaga wrote:
>>>> Hi David,
>>>>
>>>> On 2020/06/15 14:15, David Holmes wrote:
>>>>> Hi Yasumasa,
>>>>>
>>>>> On 15/06/2020 2:49 pm, Yasumasa Suenaga wrote:
>>>>>> Hi all,
>>>>>>
>>>>>> I wonder why JvmtiEnvBase::get_object_monitor_usage() 
>>>>>> (implementation of GetObjectMonitorUsage()) does not perform at 
>>>>>> safepoint.
>>>>>
>>>>> GetObjectMonitorUsage will use a safepoint if the target is not 
>>>>> suspended:
>>>>>
>>>>> jvmtiError
>>>>> JvmtiEnv::GetObjectMonitorUsage(jobject object, jvmtiMonitorUsage* 
>>>>> info_ptr) {
>>>>>    JavaThread* calling_thread = JavaThread::current();
>>>>>    jvmtiError err = get_object_monitor_usage(calling_thread, 
>>>>> object, info_ptr);
>>>>>    if (err == JVMTI_ERROR_THREAD_NOT_SUSPENDED) {
>>>>>      // Some of the critical threads were not suspended. go to a 
>>>>> safepoint and try again
>>>>>      VM_GetObjectMonitorUsage op(this, calling_thread, object, 
>>>>> info_ptr);
>>>>>      VMThread::execute(&op);
>>>>>      err = op.result();
>>>>>    }
>>>>>    return err;
>>>>> } /* end GetObject */
>>>>
>>>> I saw this code, so I guess there are some cases when 
>>>> JVMTI_ERROR_THREAD_NOT_SUSPENDED is not returned from 
>>>> get_object_monitor_usage().
>>>>
>>>>
>>>>>> Monitor owner would be acquired from monitor object at first [1], 
>>>>>> but it would perform concurrently.
>>>>>> If owner thread is not suspended, the owner might be changed to 
>>>>>> others in subsequent code.
>>>>>>
>>>>>> For example, the owner might release the monitor before [2].
>>>>>
>>>>> The expectation is that when we find an owner thread it is either 
>>>>> suspended or not. If it is suspended then it cannot release the 
>>>>> monitor. If it is not suspended we detect that and redo the whole 
>>>>> query at a safepoint.
>>>>
>>>> I think the owner thread might resume unfortunately after 
>>>> suspending check.
>>>
>>> Yes you are right. I was thinking resuming also required a safepoint 
>>> but it only requires the Threads_lock. So yes the code is wrong.
>>
>> Which code is wrong?
>>
>> Yes, a rogue resume can happen when the GetObjectMonitorUsage() caller
>> has started the process of gathering the information while not at a
>> safepoint. Thus the information returned by GetObjectMonitorUsage()
>> might be stale, but that's a bug in the agent code.
>
> I don't think so.
>
> For example, JVMTI agent might attempt to get monitor owner from 
> sleeping thread or in native (e.g. during socket operation) thread, 
> and it might resume during GetObjectMonitorUsage() call.

A "sleeping thread" or a thread "in native" does not count as being
suspended so GetObjectMonitorUsage() will take the safepoint code
path.


> Agent code can (should) not control application threads as an observer.

The agent writer has the choice of using JVM/TI SuspendThread() and
JVM/TI ResumeThread() along with GetObjectMonitorUsage() or it can
use GetObjectMonitorUsage() without direct calls to SuspendThread()
and ResumeThread. It's the agent writer's choice.

If the agent is only interested in a single thread, then doing:

     SuspendThread()            // might safepoint
     GetObjectMonitorUsage()    // won't safepoint
     ResumeThread()             // won't safepoint

is more performant than doing just GetObjectMonitorUsage() which
is guaranteed to safepoint (implementation detail).


> IMHO GetObjectMonitorUsage() should perform at safepoint or should 
> start direct handshake immediately after getting owner thread from 
> monitor.

Handshakes are a separate matter all together. I'm talking about
the way the code works now and I don't think we've switched JVM/TI
GetObjectMonitorUsage() to use handshakes yet or have we done so?

Dan



>
>
> Yasumasa
>
>
>> Dan
>>
>>
>>>
>>>
>>>> JavaThread::is_ext_suspend_completed() is used to check thread 
>>>> state, it returns `true` when the thread is sleeping [3], or when 
>>>> it performs in native [4].
>>>
>>> Sure but if the thread is actually suspended it can't continue 
>>> execution in the VM or in Java code.
>>>
>>>>
>>>>> This appears to be an optimisation for the assumed common case 
>>>>> where threads are first suspended and then the monitors are queried.
>>>>
>>>> I agree with this, but I could find out it from JVMTI spec - it 
>>>> just says "Get information about the object's monitor."
>>>
>>> Yes it was just an implementation optimisation, nothing to do with 
>>> the spec.
>>>
>>>> GetObjectMonitorUsage() might return incorrect information in some 
>>>> case.
>>>>
>>>> It starts with finding owner thread, but the owner might be just 
>>>> before wakeup.
>>>> So I think it is more safe if GetObjectMonitorUsage() is called at 
>>>> safepoint in any case.
>>>
>>> Except we're moving away from safepoints to using Handshakes, so 
>>> this particular operation will require that the apparent owner is 
>>> Handshake-safe (by entering a handshake with it) before querying the 
>>> monitor. This would still be preferable I think to always using a 
>>> safepoint for the entire operation.
>>>
>>> Cheers,
>>> David
>>> -----
>>>
>>>>
>>>> Thanks,
>>>>
>>>> Yasumasa
>>>>
>>>>
>>>> [3] 
>>>> http://hg.openjdk.java.net/jdk/jdk/file/76a17c8143d8/src/hotspot/share/runtime/thread.cpp#l671
>>>> [4] 
>>>> http://hg.openjdk.java.net/jdk/jdk/file/76a17c8143d8/src/hotspot/share/runtime/thread.cpp#l684
>>>>
>>>>
>>>>> However there is still a potential bug as the thread reported as 
>>>>> the owner may not be suspended at the time we first see it, and 
>>>>> may release the monitor, but then it may get suspended before we 
>>>>> call:
>>>>>
>>>>>   owning_thread = 
>>>>> Threads::owning_thread_from_monitor_owner(tlh.list(), owner);
>>>>>
>>>>> and so we think it is still the monitor owner and proceed to query 
>>>>> the monitor information in a racy way. This can't happen when 
>>>>> suspension itself requires a safepoint as the current thread won't 
>>>>> go to that safepoint during this code. However, if suspension is 
>>>>> implemented via a direct handshake with the target thread then we 
>>>>> have a problem.
>>>>>
>>>>> David
>>>>> -----
>>>>>
>>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Yasumasa
>>>>>>
>>>>>>
>>>>>> [1] 
>>>>>> http://hg.openjdk.java.net/jdk/jdk/file/76a17c8143d8/src/hotspot/share/prims/jvmtiEnvBase.cpp#l973
>>>>>> [2] 
>>>>>> http://hg.openjdk.java.net/jdk/jdk/file/76a17c8143d8/src/hotspot/share/prims/jvmtiEnvBase.cpp#l996
>>



More information about the serviceability-dev mailing list