...
ObjectMonitor T-deflate
T-enter +-----------------------+ ----------------------------------------
---------------- | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
owner contended | count=1 | :
atomic inc count +-----------------------+ prev = cmpxchg(-max_jint, &count, 0)
if (count > 0) if (prev != 0 ||
do contended 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 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.
T-enter Wins By A-B-A
ObjectMonitor T-deflate
T-enter +-------------------------+ ----------------------------------------
------------------------------------------ | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
owner contended | count=1 | : <thread_stalls>
atomic inc count +-------------------------+ :
if (count > 0) || :
EnterI() \/ :
cmpxchg(Self, &owner, DEFLATER_MARKER) +-------------------------+ :
atomic dec count | owner=Self/T-enter | : <thread_resumes>
} | count=0 | prev = cmpxchg(-max_jint, &count, 0)
// finished with enter +-------------------------+ if (prev != 0 ||)
: <does app work> || bailout on owner != DEFLATER_MARKERdeflation (nothing to undo)
exit() monitor \/ else if bailout on deflationowner != DEFLATER_MARKER) {
owner = NULL +-------------------------+ atomic add max_jint to count
| owner=Self/T-enter|NULL | bailout on deflation
| count=-max_jint0 | }
+-------------------------+
- This diagram starts after "Racing Threads".
- T-enter observes a count 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 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.
- T-deflate resumes, sets the count 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 to -max_jint by atomically adding max_jint to count which will restore count to its proper value.
- The third ObjectMonitor box is showing the fields at this point.
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.
...