in src/clds_hazard_pointers.c [291:344]
static void hp_thread_cleanup_func(void* context)
{
CLDS_HAZARD_POINTERS_HANDLE clds_hazard_pointers = context;
// Clean up the inactive threads in case reclaim hasn't been running
(void)interlocked_increment(&clds_hazard_pointers->pending_reclaim_calls);
int64_t current_epoch = interlocked_add_64(&clds_hazard_pointers->epoch, 0);
if (interlocked_decrement(&clds_hazard_pointers->pending_reclaim_calls) == 0)
{
if (interlocked_compare_exchange_64(&clds_hazard_pointers->epoch, current_epoch + 1, current_epoch) != current_epoch)
{
// epoch already incremented by other thread, let them do the cleanup
}
else
{
free_inactive_threads_in_previous_epochs(clds_hazard_pointers, current_epoch + 1);
}
}
void* volatile_atomic* current_thread_address = (void* volatile_atomic*)&clds_hazard_pointers->head;
CLDS_HAZARD_POINTERS_THREAD_HANDLE current_thread = interlocked_compare_exchange_pointer((void* volatile_atomic*)&clds_hazard_pointers->head, NULL, NULL);
while (current_thread != NULL)
{
CLDS_HAZARD_POINTERS_THREAD_HANDLE next_thread = interlocked_compare_exchange_pointer((void* volatile_atomic*)¤t_thread->next, NULL, NULL);
if (interlocked_add(¤t_thread->active, 0) == 1)
{
current_thread_address = (void* volatile_atomic*)¤t_thread->next;
current_thread = next_thread;
}
else
{
// remove from the list, no longer active
if (interlocked_compare_exchange_pointer(current_thread_address, next_thread, current_thread) == current_thread)
{
// removed, great, we won't see this any longer
// add it to the inactive threads
if (add_to_inactive_threads(clds_hazard_pointers, current_thread) != 0)
{
LogCriticalAndTerminate("Too many inactive threads");
// should not happen
}
// current_thread_address stays the same
current_thread = next_thread;
}
else
{
// not removed, changed in the meanwhile, this should not really happen, but we don't care either
break;
}
}
}
}