+ } while (next != old_next);
+ TRACE("l2", "ll_remove: logically removed item %p", item, 0);
+ ASSERT(!IS_TAGGED(item->next));
+
+ // This has to be an atomic swap in case another thread is updating the item while we are removing it.
+ uint64_t val = SYNC_SWAP(&item->val, DOES_NOT_EXIST);
+
+ TRACE("l2", "ll_remove: replaced item's val %p with DOES_NOT_EXIT", val, 0);
+
+ // Unlink <item> from <ll>. If we lose a race to another thread just back off. It is safe to leave the
+ // item logically removed for a later call (or some other thread) to physically unlink. By marking the
+ // item earlier, we logically removed it.
+ TRACE("l2", "ll_remove: unlink the item by linking its pred %p to its successor %p", pred, next);
+ node_t *other;
+ if ((other = SYNC_CAS(&pred->next, item, next)) != item) {
+ TRACE("l1", "ll_remove: unlink failed; pred's link changed from %p to %p", item, other);
+ return val;
+ }
+
+ // The thread that completes the unlink should free the memory.
+ node_defer_free((node_t *)item);
+ TRACE("l1", "ll_remove: successfully unlinked item %p from the list", item, 0);
+ return val;