Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Update ObjectSynchronizer::deflate_monitor_list_using_JT.

...

ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor* volatile * list_p, int volatile * count_p, ObjectMonitor** free_head_p, ObjectMonitor** free_tail_p, ObjectMonitor** saved_mid_p)

*** THIS SUBSECTION NEEDS SUBSTANTIAL REWORK WITH v2.11 ***

ObjectSynchronizer::deflate_monitor_list_using_JT() is responsible for asynchronously deflating idle ObjectMonitors using a JavaThread. This function uses the more complicated lock-cur_mid_in_use-and-mid-as-we-go protocol because om_release() can do list deletions in parallel. We also lock-next-next-as-we-go to prevent an om_flush() that is behind this thread from passing us. Because this function can asynchronously interact with so many other functions, this is the largest clip of code:

    L01:  int ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor** list_p,
    L02:                                                                                                              int* count_p,
    L03:                                                                                                              ObjectMonitor** free_head_p,
    L04:                                                                                                              ObjectMonitor** free_tail_p,
    L05:                                                                                                              ObjectMonitor** saved_mid_in_use_p) {
    L06:      JavaThread* self = JavaThread::current();
    L07:      ObjectMonitor* cur_mid_in_use = NULL;
    L08:      ObjectMonitor* mid = NULL;
    L09:      ObjectMonitor* next = NULL;
    L10:      ObjectMonitor* next_next = NULL;
    L11:      int deflated_count = 0;
    L12:   NoSafepointVerifier nsv;
    L13:   if (*saved_mid_in_use_p == NULL) {
    L13L14:          if ((mid = get_list_head_locked(list_p)) == NULL) {
    L14L15:              return 0;  // The list is empty so nothing to deflate.
    L15L16:          }
    L16L17:          next = unmarked_next(mid);
    L17L18:      } else {
    L18L19:          cur_mid_in_use = *saved_mid_in_use_p;
    L19L20:          om_lock(cur_mid_in_use);
    L20L21:          mid = unmarked_next(cur_mid_in_use);
    L21L22:          if (mid == NULL) {
    L22L23:              om_unlock(cur_mid_in_use);
    L23L24:              *saved_mid_in_use_p = NULL;
    L24L25:              return 0;  // The remainder is empty so nothing more to deflate.
    L25L26:          }
    L26L27:          om_lock(mid);
    L27L28:          next = unmarked_next(mid);
    L28L29:      }
    L29L30:      while (true) {
    L30L31:          if (next != NULL) {
    L31L32:              om_lock(next);
    L32L33:              next_next = unmarked_next(next);
    L33L34:          }
    L34L35:          if (mid->object() != NULL && mid->is_old() &&
    L35L36:                  deflate_monitor_using_JT(mid, free_head_p, free_tail_p)) {
    L36L37:              if (cur_mid_in_use == NULL) {
    L37L38:                  Atomic::store(list_p, next);
    L38L39:              } else {
    L39L40:                  ObjectMonitor* locked_next = mark_om_ptr(next);
    L40L41:                  cur_mid_in_use->set_next_om(locked_next);
    L41L42:              }
    L42L43:              deflated_count++;
    L43L44:              Atomic::dec(count_p);
    L44L45:              mid->set_next_om(NULL);
    L45L46:              mid = next;  // mid keeps non-NULL next's locked state
    L46L47:              next = next_next;
    L47L48:          } else {
    L48L49:              if (cur_mid_in_use != NULL) {
    L49L50:                  om_unlock(cur_mid_in_use);
    L50L51:              }
    L51L52:              cur_mid_in_use = mid;
    L52L53:              mid = next;  // mid keeps non-NULL next's locked state
    L53L54:              next = next_next;
    L54L55:              if (SafepointMechanism::should_block(self) &&
    L55L56:                      cur_mid_in_use != Atomic::load(list_p) && cur_mid_in_use->is_old()) {
    L56L57:                  *saved_mid_in_use_p = cur_mid_in_use;
    L57L58:                  om_unlock(cur_mid_in_use);
    L58L59:                  if (mid != NULL) {
    L59L60:                      om_unlock(mid);
    L60L61:                  }
    L61L62:                  return deflated_count;
    L62L63:              }
    L63L64:          }
    L64L65:          if (mid == NULL) {
    L65L66:              if (cur_mid_in_use != NULL) {
    L66L67:                  om_unlock(cur_mid_in_use);
    L67L68:              }
    L68L69:              break;  // Reached end of the list so nothing more to deflate.
    L69L70:          }
    L70L71:      }
    L71L72:      *saved_mid_in_use_p = NULL;
    L72L73:      return deflated_count;
    L73L74:    }

The above is not an exact copy of the code block from deflate_monitor_list_using_JT(), but it is the highlights. What the above code block needs to do is pretty simple:

...

Since we're using the more complicated lock-cur_mid_in_use-and-mid-as-we-go protocol and also the lock-next-next-as-we-go protocol, there is a mind numbing amount of detail:

    • L1[23-67]: Handle the initial setup if we are not resuming after a safepoint or a handshake:
      • L13L14: locks the 'list_p' head (if it is not empty):
      • L16L17: 'next' is the unmarked next field from 'mid'.
    • L17L18-L27L28: Handle the initial setup if we are resuming after a safepoint or a handshake:
      • L19L20: lock 'cur_mid_in_use'
      • L20L21: update 'mid'
      • L21L22-L24L25: If 'mid' == NULL, then we've resumed context at the end of the list so we're done.
      • L26L27: lock 'mid'
      • L27L28: update 'next'
    • L29L30-L70L71: We walk each 'mid' in the list and determine if it can be deflated:
      • L3[01-23]: if next != NULL, then lock 'next' and update 'next_next'
      • L34L35-L46L47: if 'mid' is associated with an object, 'mid' is old, and can be deflated:
        • L36L37: if cur_mid_in_use is NULL, we're still processing the head of the in-use list so...
          • L37L38: we store the list head to 'next'.
        • else
          • L39L40: make a locked copy of 'next'
          • L40L41: we set cur_mid_in_use's next field to 'locked_next'.
        • L42 L43 L44L45: we've successfully extracted 'mid' from 'list_p's list so we increment 'deflated_count', decrement the counter referred to by 'count_p', set 'mid's next field to NULL and we're done.
          Note: 'mid' is the current tail in the 'free_head_p' list so we have to NULL terminate it (which also unlocks it).
        • L45L46: advance 'mid' to 'next'.
          Note: 'mid' keeps non-NULL 'next's locked state
        • L46L47: advance 'next' to 'next_next'.
      • L47L48-L62L63: 'mid' can't be deflated so we have to carefully advance the list pointers:
        • L4[89]L49,50: if cur_mid_in_use != NULL, then unlock 'cur_mid_in_use'.
        • L51L52: advance 'cur_mid_in_use' to 'mid'.
          Note: 'mid' is still locked and 'cur_mid_in_use' keeps that state.
        • L52L53: advance 'mid' to 'next'.
          Note: A non-NULL 'next' is still locked and 'mid' keeps that state.
        • L53L54: advance 'next' to 'next_next'.
        • L54L55-L61L62: Handle a safepoint or a handshake if one has started and it is safe to do so.
      • L64L65-L68L69: we reached the end of the list:
        • L6[5667]: if cur_mid_in_use != NULL, then unlock 'cur_mid_in_use'.
        • L68L69: break out of the loop because we are done
    • L71L72: not pausing for a safepoint or handshake so clear saved state.
    • L72L73: all done so return 'deflated_count'.

...