Question about GetObjectMonitorUsage() JVMTI function

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


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.

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