RFR: 8210832: Remove sneaky locking in class Monitor
Patricio Chilano
patricio.chilano.mateo at oracle.com
Wed Jan 30 00:39:11 UTC 2019
Hi Dan,
On 1/29/19 11:00 AM, Daniel D. Daugherty wrote:
> Hi Patricio,
>
> I'm stripping this down to just the possible issue in mutex.cpp...
>
>
> On 1/28/19 6:13 PM, Patricio Chilano wrote:
>> On 1/28/19 4:29 PM, Daniel D. Daugherty wrote:
>>> On 1/28/19 2:18 PM, Patricio Chilano wrote:
>>>> Full: http://cr.openjdk.java.net/~pchilanomate/8210832/v02/webrev
>>> src/hotspot/share/runtime/mutex.cpp
>>> L205: jt->java_suspend_self();
>>> L206: }
>>> L207: }
>>> L208:
>>> L209: if (in_flight_monitor != NULL) {
>>> L210: // Conceptually reestablish ownership of the lock.
>>> L211: assert(_owner == NULL, "should be NULL: owner="
>>> INTPTR_FORMAT, p2i(_owner));
>>> L212: set_owner(self);
>>> L213: } else {
>>> L214: lock();
>>> L215: }
>>> The lock reacquire on L214 used to be done after the
>>> java_suspend_self() on L205 which is inside the block
>>> context for the ThreadLockBlockInVM and OSThreadWaitState
>>> helps. If the lock() blocks due to a racing thread, then
>>> the calling JavaThread won't have the right thread state
>>> of OS thread wait state, etc...
>>> So after java_suspend_self(), you have to re-lock() so that
>>> a potential block on that re-lock has the right states. This
>>> also means that this line has to be deleted:
>>>
>>> L204 in_flight_monitor = NULL;
>>>
>>> so that ThreadLockBlockInVM destructor can do the right thing
>>> if the thread is suspended and then relocks.
>> Yes, I see your point. The problem is that after executing the TLBIVM
>> destructor (which executes after the OSThreadWaitState destructor
>> with the current order) there is always the possibility that we had
>> to release the lock, and so afterwards we will have to re-acquire it
>> with a different state. One simple way of solving this could be
>> moving the OSThreadWaitState object outside the TLBIVM block. Based
>> on David's comment about OSThreadWaitState I don't think changing the
>> order should break things, since it seems more like a debugging tool.
>> What do you think then of doing something like this: (I also included
>> a re-lock after java_suspend_self() and removed
>> in_flight_monitor=NULL as you suggested.)
>>
>> diff --git a/src/hotspot/share/runtime/mutex.cpp
>> b/src/hotspot/share/runtime/mutex.cpp
>> --- a/src/hotspot/share/runtime/mutex.cpp
>> +++ b/src/hotspot/share/runtime/mutex.cpp
>> @@ -182,9 +186,9 @@
>> JavaThread *jt = (JavaThread *)self;
>> Monitor* in_flight_monitor = NULL;
>>
>> + OSThreadWaitState osts(self->osthread(), false /* not
>> Object.wait() */);
>> {
>> ThreadLockBlockInVM tlbivm(jt, &in_flight_monitor);
>> - OSThreadWaitState osts(self->osthread(), false /* not
>> Object.wait() */);
>> if (as_suspend_equivalent) {
>> jt->set_suspend_equivalent();
>> // cleared by handle_special_suspend_equivalent_condition() or
>> @@ -201,8 +205,8 @@
>> // want to hold the lock while suspended because that
>> // would surprise the thread that suspended us.
>> _lock.unlock();
>> - in_flight_monitor = NULL;
>> jt->java_suspend_self();
>> + _lock.lock();
>> }
>> }
>>
>>> Also after lock() on L214, you never call set_owner(self)
>>> so the ownership is not complete for that relocated code.
>>> You won't need the set_owner(self) call if you move the
>>> lock() on L214 back to after java_suspend_self().
>> That lock() is actually Monitor::lock(). But I agree is confusing,
>> every time I look at it I say the same. Maybe I can rewrite it as
>> Monitor::lock() ?
>
> The fact that the lock() on L214 is really Monitor::lock()
> changes everything with respect to my comment. I'm sorry
> I missed that crucial detail. Please ignore the above from
> me and undo the changes that I suggested.
>
> Here's a new set of comments:
>
> L195: in_flight_monitor = this;
> Please consider adding a comment:
>
> in_flight_monitor = this; // save for
> ~ThreadLockBlockInVM
>
> L204: in_flight_monitor = NULL;
> Please consider adding a comment:
>
> in_flight_monitor = this; // ~ThreadLockBlockInVM
> does not need to unlock
>
> L209: if (in_flight_monitor != NULL) {
> Please consider adding a comment below L209:
>
> // Not unlocked by ~ThreadLockBlockInVM or
> self-suspend above.
>
> L214: lock();
> I missed the fact that this is Monitor::lock(). However, the
> problem with Monitor::lock() here is that if this call blocks,
> then we don't have a ThreadLockBlockInVM to change our state
> so we won't be recognized as blocking.
>
> Please consider changing to:
>
> Monitor::lock(self);
>
> that will give us full locking semantics.
>
> Okay, I think this new set of comments is on the right track, but
> obviously I need other reviewers to point out my silliness... :-)
>
> I am a bit worried about whether our use of a ThreadLockBlockInVM
> in wait() and another in lock(self) on this code path could cause
> any confusion by observing threads. I don't think so, but I haven't
> traced it all out from beginning to end yet.
If you mean observing a state of _thread_blocked and performing a
safepoint or handshake by the VMThread, the blocked thread will still
stop in the destructor of the TLBIVM anyways. If the JavaThread has to
execute in a new TLBIVM jacket then the same logic applies. But that
would be the same as in Monitor::lock, since by looping around you can
also execute different TLBIVM jackets. Not sure if that's what you meant.
I sent v03 adding your fixes and Per suggestions:
Full: http://cr.openjdk.java.net/~pchilanomate/8210832/v03/webrev/
Inc: http://cr.openjdk.java.net/~pchilanomate/8210832/v03/inc/webrev/
Thanks!
Patricio
> Dan
>
More information about the hotspot-dev
mailing list