Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Update "An Example of ObjectMonitor Interference" for "count" -> "contentions" rename and add "deflate_monitor_using_JT() {" to diagrams; also add markers to "T-enter Wins By A-B-A" diagram since there is more than one ObjectMonitor box shown.

...

ObjectMonitor::install_displaced_markword_in_object() is the new piece of code that handles all the racy situations with restoring an object's header asynchronously. The function is called from a couple of places (deflation and object monitor entry) and can also race with installation of a hash for the object. The restoration protocol for the object's header uses the mark bit along with the hash() value staying at zero to indicate that the object's header
is being restored. Only one of the three possible racing scenarios can win and the losing scenarios all adapt to the winning scenario's object header value.

3) Using "owner" or "

...

contentions" With Interference Detection

Various code paths have been updated to recognize an owner field equal to DEFLATER_MARKER or a negative count contentions field and those code paths will retry their operation. This is the shortest "Key Part" description, but don't be fooled. See "Gory Details" below.

...

For example, when ObjectMonitor::enter() detects genuine contention via the owner field, it atomically increments the count contentions field to indicate that the ObjectMonitor is busy. The thread calling enter() (T-enter) is potentially racing with an Async Monitor Deflation by another JavaThread (T-deflate) so both threads have to check the result of the race.

...

                      ObjectMonitor              T-deflate
T-enter           +-----------------------+  ----------------------------------------
----------------  | owner=NULL            |  cmpxchg(DEFLATER_MARKER, &owner, NULL) deflate_monitor_using_JT() {
                   | countcontentions=0              0         | cmpxchg(DEFLATER_MARKER, &owner, NULL)
                   +-----------------------+

...

Racing Threads

                            ObjectMonitor              T-deflate
    T-enter           +-----------------------+  --------------------------------------------
    ---------------- ------ | owner=DEFLATER_MARKER | deflate_monitor_using_JT() {
    owner contended    | contentions=0         cmpxchg(DEFLATER_MARKER, &owner, NULL)
    owneratomic contended   | count=0               |  :
    atomic inc count  inc contentions  +-----------------------+  :
prev = cmpxchg(-max_jint, &countcontentions, 0)
    • T-deflate has executed cmpxchg() and set owner to DEFLATE_MARKER.
    • T-enter has observed the contended owner field.
    • T-enter and T-deflate are racing to update the count contentions field.

T-deflate Wins

                                                                 ObjectMonitor              T-deflate
    T-enter                   enter                     +-----------------------+  --------------------------------------------
    ----------------------           | owner-------  | owner=DEFLATER_MARKER |  cmpxchg(DEFLATER_MARKER, &owner, NULL)deflate_monitor_using_JT() {
    owner contended          contended              | countcontentions=-max_jint      jint : cmpxchg(DEFLATER_MARKER, &owner, NULL)
    atomic inc contentions     count           +-----------------------+  :
    if (contentions <= 0 && owner                              prev = cmpxchg(-max_jint, &countcontentions, 0)
    if (count <= 0 && owner                                      == DEFLATER_MARKER) {                             if (prev == 0 &&
        == DEFLATER_MARKER) {                                      restore header                                         owner == DEFLATER_MARKER) {
      restore header                                        retry enter                                          restore object header
      retry enter                                              }                                                       finish the deflation
    }                                                     }
    • This diagram starts after "Racing Threads".
    • T-enter and T-deflate both observe owner == DEFLATER_MARKER and a negative count contentions field.
    • T-enter has lost the race and it retries.
    • T-deflate finishes deflation of the ObjectMonitor.

T-enter Wins

                                                 ObjectMonitor              T-deflate
    T-enter           +-----------------------+  --------------------------------------------
    ----------------------  | owner=DEFLATER_MARKER |  cmpxchg(DEFLATER_MARKER, &owner, NULL)deflate_monitor_using_JT() {
    owner contended   contended    | countcontentions=1              1         : cmpxchg(DEFLATER_MARKER, &owner, NULL)
    atomic inc count contentions  +-----------------------+  :
    if (contentions > 0)                               prev = cmpxchg(-max_jint, &countcontentions, 0)
    if (count > 0)                                    do contended                                if (prev != 0 ||
      do contended                                   enter work                                 owner != DEFLATER_MARKER)
      enter work                                 bailout on deflation (nothing to undo)
    • This diagram starts after "Racing Threads".
    • T-enter and T-deflate both observe a count contentions field > 0.
    • T-enter has won the race and it proceeds with the normal contended enter work.
    • T-deflate detects that it has lost the race and bails out on deflating the ObjectMonitor.
    • In this example, T-deflate never reaches the DEFLATER_MARKER check and it has nothing to undo.

...

                                                ObjectMonitor                T-deflate
    T-enter           +-------------------------+  ------------------------------------------
    ------------------------------------------ | owner=DEFLATER_MARKER |  cmpxchg(DEFLATER_MARKER, &owner, NULL)deflate_monitor_using_JT() {
    owner contended   | count=1             contentions=1           |    |  : <thread_stalls> cmpxchg(DEFLATER_MARKER, &owner, NULL)
    atomic inc count contentions  +-------------------------+  2> : <thread_stalls>
    if (countcontentions > 0)                                                       || :
      EnterI()                               \/ :
      cmpxchg(Self, &owner, DEFLATER_MARKER)  +-------------------------+ :
atomic dec countcontentions | owner=Self/T-enter | : <thread_resumes>
2> } | countcontentions=0 | | prev = cmpxchg(-max_jint, &count, 0): <thread_resumes>
// finished with enter +-------------------------+ if (prev !== cmpxchg(-max_jint, &contentions, 0)
3> : <does app work> || bailoutif on deflation (nothingprev to!= undo0)
exit() monitor \/ \/ bailout elseon ifdeflation owner(nothing != DEFLATER_MARKER) {to undo)
owner = NULL +-------------------------+ else if atomicowner add!= maxDEFLATER_jint to countMARKER) {
| owner=Self/T-enter|NULL | bailout on deflation atomic add max_jint to contentions
| countcontentions=0 | 3> bailout on | }deflation
+-------------------------+ }
    • This diagram starts after "Racing Threads".
    • T-enter observes a count contentions field > 0.
    • T-deflate stalls after setting the owner field to DEFLATER_MARKER.
    • T-enter has won the race and calls EnterI() to do the contended enter work.
      • EnterI() observes owner == DEFLATER_MARKER and uses cmpxchg() to set the owner field to Self/T-enter.
      • T-enter decrements the count contentions field because it is no longer contending for the monitor; it owns the monitor.
    • The second ObjectMonitor box is showing the fields at this point and the "2>" markers are showing where each thread is at for that ObjectMonitor box.
    • T-deflate resumes, sets the count contentions field to -max_jint, and passes the first part of the bailout expression because "prev == 0".
    • T-deflate observes that "owner != DEFLATE_MARKER" and bails out on deflation.
      • Depending on when T-deflate resumes after the stall, it will see "owner == T-enter" or "owner == NULL".
      • Both of those values will cause deflation to bailout, but in this case we have to undo setting count contentions to -max_jint by atomically adding max_jint to count contentions which will restore count contentions to its proper value.
    • The third ObjectMonitor box is showing the fields at this pointpointand the "3>" markers are showing where each thread is at for that ObjectMonitor box.
    • If the T-enter thread has managed to enter but not exit the monitor during the T-deflate stall, then our owner field A-B-A transition is:
          NULL → DEFLATE_MARKER → Self/T-enter
      so we really have A1-B-A2, but the A-B-A principal still holds.

    • If the T-enter thread has managed to enter and exit the monitor during the T-deflate stall, then our owner field A-B-A transition is:
          NULL → DEFLATE_MARKER → Self/T-enter  → NULL
      so we really have A-B1-B2-A, but the A-B-A principal still holds.

...