in src/common/garbage_list.h [208:259]
virtual Status Push(void* removed_item, DestroyCallback callback,
void* context) {
Epoch removal_epoch = epoch_manager_->GetCurrentEpoch();
const uint64_t invalid_epoch = ~0llu;
for(;;) {
int64_t slot = (tail_.fetch_add(1) - 1) & (item_count_ - 1);
// Everytime we work through 25% of the capacity of the list roll
// the epoch over.
if(((slot << 2) & (item_count_ - 1)) == 0)
epoch_manager_->BumpCurrentEpoch();
Item& item = items_[slot];
Epoch priorItemEpoch = item.removal_epoch;
if(priorItemEpoch == invalid_epoch) {
// Someone is modifying this slot. Try elsewhere.
continue;
}
Epoch result = CompareExchange64<Epoch>(&item.removal_epoch,
invalid_epoch, priorItemEpoch);
if(result != priorItemEpoch) {
// Someone else is now modifying the slot or it has been
// replaced with a new item. If someone replaces the old item
// with a new one of the same epoch number, that's ok.
continue;
}
// Ensure it is safe to free the old entry.
if(priorItemEpoch) {
if(!epoch_manager_->IsSafeToReclaim(priorItemEpoch)) {
// Uh-oh, we couldn't free the old entry. Things aren't looking
// good, but maybe it was just the result of a race. Replace the
// epoch number we mangled and try elsewhere.
*((volatile Epoch*) &item.removal_epoch) = priorItemEpoch;
continue;
}
item.destroy_callback(item.destroy_callback_context,
item.removed_item);
}
// Now populate the entry with the new item.
item.destroy_callback = callback;
item.destroy_callback_context = context;
item.removed_item = removed_item;
*((volatile Epoch*) &item.removal_epoch) = removal_epoch;
return Status::OK();
}
}