CLDS_HAZARD_POINTER_RECORD_HANDLE clds_hazard_pointers_acquire()

in src/clds_hazard_pointers.c [495:577]


CLDS_HAZARD_POINTER_RECORD_HANDLE clds_hazard_pointers_acquire(CLDS_HAZARD_POINTERS_THREAD_HANDLE clds_hazard_pointers_thread, void* node)
{
    CLDS_HAZARD_POINTER_RECORD_HANDLE result;

    if (clds_hazard_pointers_thread == NULL)
    {
        LogError("Invalid arguments: CLDS_HAZARD_POINTERS_THREAD_HANDLE clds_hazard_pointers_thread=%p, void* node=%p",
            clds_hazard_pointers_thread, node);
        result = NULL;
    }
    else
    {
        bool restart_needed;
        CLDS_HAZARD_POINTER_RECORD_HANDLE hazard_ptr;

        // get a hazard pointer for the node from the free list
        do
        {
            hazard_ptr = interlocked_compare_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers_thread->free_pointers, NULL, NULL);
            if (hazard_ptr != NULL)
            {
                if (interlocked_compare_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers_thread->free_pointers, hazard_ptr->next, hazard_ptr) != hazard_ptr)
                {
                    restart_needed = true;
                }
                else
                {
                    // got it
                    restart_needed = false;
                }
            }
            else
            {
                // no free one
                restart_needed = false;
            }
        }
        while (restart_needed);

        if (hazard_ptr == NULL)
        {
            // no more pointers in free list, create one
            hazard_ptr = malloc(sizeof(CLDS_HAZARD_POINTER_RECORD));
            if (hazard_ptr == NULL)
            {
                LogError("Error allocating hazard pointer");
                result = NULL;
            }
            else
            {
                CLDS_HAZARD_POINTER_RECORD* current_list_head;

                // add it to the hazard pointer list
                current_list_head = interlocked_compare_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers_thread->pointers, NULL, NULL);

                (void)interlocked_exchange_pointer(&hazard_ptr->node, node);
                hazard_ptr->next = current_list_head;

                (void)interlocked_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers_thread->pointers, hazard_ptr);

                // inserted in the used hazard pointer list, we are done
                result = hazard_ptr;
            }
        }
        else
        {
            CLDS_HAZARD_POINTER_RECORD* current_list_head;

            // add it to the hazard pointer list
            current_list_head = interlocked_compare_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers_thread->pointers, NULL, NULL);

            (void)interlocked_exchange_pointer(&hazard_ptr->node, node);
            hazard_ptr->next = current_list_head;

            (void)interlocked_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers_thread->pointers, hazard_ptr);

            // inserted in the used hazard pointer list, we are done
            result = hazard_ptr;
        }
    }

    return result;
}