template void async_list::nasync_remove_node()

in Source/PLCrashAsyncLinkedList.hpp [338:396]


template <typename V> void async_list<V>::nasync_remove_node (node *deleted_node) {
    /* Lock the list from other writers. */
    PLCR_COMPAT_LOCK_LOCK(&_write_lock); {
        /* Find the record. */
        node *item = _head;
        while (item != NULL) {
            if (item == deleted_node)
                break;
            
            item = item->_next;
        }
        
        /* If not found, nothing to do */
        if (item == NULL) {
            PLCR_COMPAT_LOCK_UNLOCK(&_write_lock);
            return;
        }
        
        /*
         * Atomically make the item unreachable by readers.
         *
         * This serves as a synchronization point -- after the CAS, the item is no longer reachable via the list.
         */
        if (item == _head) {
            if (!_head.compare_exchange_strong(item, item->_next)) {
                PLCF_DEBUG("Failed to remove image list head despite holding lock");
            }
        } else {
            /* There MUST be a non-NULL prev pointer, as this is not HEAD. */
            if (!item->_prev->_next.compare_exchange_strong(item, item->_next)) {
                PLCF_DEBUG("Failed to remove image list item despite holding lock");
            }
        }
        
        /* Now that the item is unreachable, update the prev/tail pointers. These are never accessed without a lock,
         * and need not be updated atomically. */
        if (item->_next != NULL) {
            /* Item is not the tail (otherwise next would be NULL), so simply update the next item's prev pointer. */
            ((node *)item->_next)->_prev = item->_prev;
        } else {
            /* Item is the tail (next is NULL). Simply update the tail record. */
            _tail = item->_prev;
        }
        
        /* If a reader is active, place the node on the free list. The item is unreachable here when readers
         * aren't active, so if we have a 0 refcount, we can safely delete the item, and be sure that no
         * reader holds a reference to it. */
        if (_refcount > 0) {
            item->_prev = NULL;
            item->_next = _free;
            
            if (_free != NULL)
                _free->_prev = item;
            _free = item;
        } else {
            delete item;
        }
    } PLCR_COMPAT_LOCK_UNLOCK(&_write_lock);
}