static gpointer alloc_from_active_or_partial (MonoLockFreeAllocator *heap) { Descriptor *desc; Anchor old_anchor, new_anchor; gpointer addr; retry: desc = heap->active; if (desc) { if (InterlockedCompareExchangePointer ((gpointer * volatile)&heap->active, NULL, desc) != desc) goto retry; } else { desc = heap_get_partial (heap); if (!desc) return NULL; } /* Now we own the desc. */ do { unsigned int next; new_anchor = old_anchor = (Anchor)*(volatile gint32*)&desc->anchor.value; if (old_anchor.data.state == STATE_EMPTY) { /* We must free it because we own it. */ desc_retire (desc); goto retry; } g_assert (old_anchor.data.state == STATE_PARTIAL); g_assert (old_anchor.data.count > 0); addr = (char*)desc->sb + old_anchor.data.avail * desc->slot_size; mono_memory_read_barrier (); next = *(unsigned int*)addr; g_assert (next < SB_USABLE_SIZE / desc->slot_size); new_anchor.data.avail = next; --new_anchor.data.count; if (new_anchor.data.count == 0) new_anchor.data.state = STATE_FULL; } while (!set_anchor (desc, old_anchor, new_anchor)); /* If the desc is partial we have to give it back. */ if (new_anchor.data.state == STATE_PARTIAL) { if (InterlockedCompareExchangePointer ((gpointer * volatile)&heap->active, desc, NULL) != NULL) heap_put_partial (desc); } return addr; }
void mono_lock_free_free (gpointer ptr, size_t block_size) { Anchor old_anchor, new_anchor; Descriptor *desc; gpointer sb; MonoLockFreeAllocator *heap = NULL; desc = *(Descriptor**) sb_header_for_addr (ptr, block_size); g_assert (block_size == desc->block_size); sb = desc->sb; do { new_anchor = old_anchor = *(volatile Anchor*)&desc->anchor.value; *(unsigned int*)ptr = old_anchor.data.avail; new_anchor.data.avail = ((char*)ptr - (char*)sb) / desc->slot_size; g_assert (new_anchor.data.avail < LOCK_FREE_ALLOC_SB_USABLE_SIZE (block_size) / desc->slot_size); if (old_anchor.data.state == STATE_FULL) new_anchor.data.state = STATE_PARTIAL; if (++new_anchor.data.count == desc->max_count) { heap = desc->heap; new_anchor.data.state = STATE_EMPTY; } } while (!set_anchor (desc, old_anchor, new_anchor)); if (new_anchor.data.state == STATE_EMPTY) { g_assert (old_anchor.data.state != STATE_EMPTY); if (InterlockedCompareExchangePointer ((gpointer * volatile)&heap->active, NULL, desc) == desc) { /* We own it, so we free it. */ desc_retire (desc); } else { /* * Somebody else must free it, so we do some * freeing for others. */ list_remove_empty_desc (heap->sc); } } else if (old_anchor.data.state == STATE_FULL) { /* * Nobody owned it, now we do, so we need to give it * back. */ g_assert (new_anchor.data.state == STATE_PARTIAL); if (InterlockedCompareExchangePointer ((gpointer * volatile)&desc->heap->active, desc, NULL) != NULL) heap_put_partial (desc); } }