RFR: 8210832: Remove sneaky locking in class Monitor

Daniel D. Daugherty daniel.daugherty at oracle.com
Tue Jan 29 16:00:16 UTC 2019


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.

Dan



More information about the hotspot-dev mailing list