+ node_t *next;
+ node_t *old_next = item->next[0];
+ do {
+ next = old_next;
+ old_next = SYNC_CAS(&item->next[0], next, TAG_VALUE(next));
+ if (IS_TAGGED(old_next)) {
+ TRACE("s2", "sl_remove: %p is already marked for removal by another thread at level 0", item, 0);
+ return DOES_NOT_EXIST;
+ }
+ } while (next != old_next);
+ TRACE("s1", "sl_remove: marked item %p removed at level 0", item, 0);
+
+ // Atomically swap out the item's value in case another thread is updating the item while we are
+ // removing it. This establishes which one occurs first, the update or the remove.
+ uint64_t val = SYNC_SWAP(&item->val, DOES_NOT_EXIST);
+ TRACE("s2", "sl_remove: replaced item %p's value with DOES_NOT_EXIT", item, 0);
+
+ node_t *pred = preds[0];
+ TRACE("s2", "sl_remove: linking the item's pred %p to the item's successor %p", pred, STRIP_TAG(next));
+ if (SYNC_CAS(&pred->next[0], item, STRIP_TAG(next))) {
+ TRACE("s2", "sl_remove: unlinked item %p from the skiplist at level 0", item, 0);
+ // The thread that completes the unlink should free the memory.
+ if (sl->clone_fun != NULL) {
+ nbd_defer_free(item->key);
+ }
+ nbd_defer_free(item);
+ }