Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Add missing code to om_release() and update wording a bit.

...

    L01:  static bool mark_list_head(ObjectMonitor* volatile * list_p,
    L02:                             ObjectMonitor** mid_p, ObjectMonitor** next_p) {
    L03:    while (true) {
    L04:      ObjectMonitor* mid = OrderAccess::load_acquire(list_p);
    L05:      if (mid == NULL) {
    L06:        return false;  // The list is empty so nothing to mark.
    L07:      }
    L08:      if (mark_next(mid, next_p)) {
    L09:        if (OrderAccess::load_acquire(list_p) != mid) {
    L10:          // The list head changed so we have to retry.
    L11:          set_next(mid, *next_p);  // unmark mid
    L12:          continue;
    L13:        }
    L14:        // We marked next field to guard against races.
    L15:        *mid_p = mid;
    L16:        return true;
    L17:      }
    L18:    }
    L19: }

The above function tries to mark the next field in the list head's ObjectMonitor:

...

ObjectSynchronizer::om_release() is responsible for putting an ObjectMonitor on self's free list. If 'from_per_thread_alloc' is true, then om_release() is also responsible for extracting the ObjectMonitor from self's in-use list. The extraction from self's in-use list must happen first:

    L01:  if (from_per_thread_alloc) {
    L02:    mark_list_head(&self->om_in_use_list, &mid, &next);
    L02L03:     while (true) {
    L03L04:         if (m == mid) {
    L04L05:             if (Atomic::cmpxchg(next, &self->om_in_use_list, mid) != mid) {
    L05L06:                 ObjectMonitor* marked_mid = mark_om_ptr(mid);
    L06L07:                 Atomic::cmpxchg(next, &cur_mid_in_use->_next_om, marked_mid);
    L07L08:             }
    L08L09:             extracted = true;
    L09L10:             Atomic::dec(&self->om_in_use_count);
    L10L11:             set_next(mid, next);
    L11L12:             break;
    L12L13:         }
    L13L14:         if (cur_mid_in_use != NULL) {
    L14L15:             set_next(cur_mid_in_use, mid);  // umark cur_mid_in_use
    L15L16:         }
    L16L17:         cur_mid_in_use = mid;
    L17L18:         mid = next;
    L18L19:         next = mark_next_loop(mid);
    L20:    L19}
    L21:  }
    L22:  prepend_to_om_free_list(self, m);

Most of the The above code block extracts 'm' from self's in-use list; it is not an exact quote from om_release(), but it is the highlights:

    • L01 L02 is used mark self's in-use list head:
      • 'mid' is self's in-use list head and its next field is marked.
      • 'next' is the unmarked next field from 'mid'.
    • L02 L03 L19L20: self's in-use list is traversed looking for the target ObjectMonitor 'm':
      • L03L04: if the current 'mid' matches 'm':
        • L04L05: if we can't cmpxchg self's in-use list head to the 'next' ObjectMonitor*:
          Note: This cmpxchg only works if 'm' is self's in-use list head and no-harm-no-foul if 'm' is not self's in-use list head. This is faster than doing a load-acquire of self's in-use list head, checking the value and then calling cmpxchg.
          • L05L06: make a marked copy of 'mid'
          • L06L07: we cmpxchg cur_mid_in_use's next field to 'marked_mid'.
            Note: We use cmpxchg here instead of release-store so that we can sanity check the result; see the real code.
        • L08 L09 L11L12: we've successfully extracted 'm' from self's in-use list so we decrement self's in-use counter, unmark the next field in 'mid' and we're done.
      • L1[3445]: if cur_mid_in_use != NULL, then unmark its next field.
      • L16L17: set 'cur_mid_in_use' to 'mid'
        Note: cur_mid_in_use keeps the marked next field so that it remains stable for a possible next field change. It cannot be deflated while it is marked.
      • L17L18: set 'mid' to 'next'.
      • L18L19: mark next field in the new 'mid' and update 'next'

The last line of the code block (L22) prepends 'm' to self's free list.

mark_next_loop() Helper Function

...