Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Add "lock_next_for_traversal() Helper Function" sub-section.

...

    • L05 tries to lock the list head:
      • get_list_head_locked() returns NULL if the list is empty so we return NULL on L06.
      • Otherwise, 'take' is a pointer to the locked list head.
    • L08 gets the next pointer from take.
    • L11 stores 'next' into 'list_p'.
      You might be asking yourself: Why store instead of cmpxchg?
      • get_list_head_locked() only returns to the caller when it has locked the ObjectMonitor at the head of the list.
      • Because of that guarantee, any prepender or deleter thread that is running in parallel must loop until we have stored 'next' into 'list_p' which unlocks the list head.
    • L12 decrements the counter referred to by 'count_p'.
    • L16 unlocks 'take':
      • Keeping the 'next' value in take's next field allows any lagging list walker to get to the next ObjectMonitor on that list.
      • take's next field will get cleaned up when take is prepended to its target in-use list.
    • L17 returns 'take' to the caller.

lock_next_for_traversal() Helper Function

This last helper function exists for making life easier for list walker code. List walker code calls get_list_head_locked() to get the locked list head and then walks the list applying its particular logic to elements in the list. In order to safely walk to the 'next' ObjectMonitor in a list, the list walker code must lock the 'next' ObjectMonitor before unlocking the 'current' ObjectMonitor that it has locked. If a list walker unlocks 'current' before locking 'next', then there is race where 'current' could be modified to refer to something other than the 'next' value that was in place when 'current' was locked. By locking 'next' first and then unlocking 'current', the list walker can safely advance to 'next'.

    L01:  static ObjectMonitor* lock_next_for_traversal(ObjectMonitor* cur) {
    L02:    assert(is_locked(cur), "cur=" INTPTR_FORMAT " must be locked", p2i(cur));
    L03:    ObjectMonitor* next = unmarked_next(cur);
    L04:    if (next == NULL) {  // Reached the end of the list.
    L05:      om_unlock(cur);
    L06:      return NULL;
    L07:    }
    L08:    om_lock(next);   // Lock next before unlocking current to keep
    L09:    om_unlock(cur);  // from being by-passed by another thread.
    L10:    return next;
    L11:  }

This function is pretty straight forward so there are no detailed notes for it.

Using The New Spin-Lock Monitor List Functions

...