-/*
- * lock-free-alloc.c: Lock free allocator.
+/**
+ * \file
+ * Lock free allocator.
*
* (C) Copyright 2011 Novell, Inc
*
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
pagesize = mono_pagesize ();
sb_header = desc->block_size == pagesize ?
- mono_valloc (NULL, desc->block_size, prot_flags_for_activate (TRUE)) :
- mono_valloc_aligned (desc->block_size, desc->block_size, prot_flags_for_activate (TRUE));
+ mono_valloc (NULL, desc->block_size, prot_flags_for_activate (TRUE), desc->heap->account_type) :
+ mono_valloc_aligned (desc->block_size, desc->block_size, prot_flags_for_activate (TRUE), desc->heap->account_type);
g_assert (sb_header == sb_header_for_addr (sb_header, desc->block_size));
}
static void
-free_sb (gpointer sb, size_t block_size)
+free_sb (gpointer sb, size_t block_size, MonoMemAccountType type)
{
gpointer sb_header = sb_header_for_addr (sb, block_size);
g_assert ((char*)sb_header + LOCK_FREE_ALLOC_SB_HEADER_SIZE == sb);
- mono_vfree (sb_header, block_size);
+ mono_vfree (sb_header, block_size, type);
//g_print ("free sb %p\n", sb_header);
}
static Descriptor * volatile desc_avail;
static Descriptor*
-desc_alloc (void)
+desc_alloc (MonoMemAccountType type)
{
MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
Descriptor *desc;
for (;;) {
gboolean success;
- desc = (Descriptor *) get_hazardous_pointer ((gpointer * volatile)&desc_avail, hp, 1);
+ desc = (Descriptor *) mono_get_hazardous_pointer ((gpointer * volatile)&desc_avail, hp, 1);
if (desc) {
Descriptor *next = desc->next;
success = (InterlockedCompareExchangePointer ((gpointer * volatile)&desc_avail, next, desc) == desc);
Descriptor *d;
int i;
- desc = (Descriptor *) mono_valloc (NULL, desc_size * NUM_DESC_BATCH, prot_flags_for_activate (TRUE));
+ desc = (Descriptor *) mono_valloc (NULL, desc_size * NUM_DESC_BATCH, prot_flags_for_activate (TRUE), type);
/* Organize into linked list. */
d = desc;
success = (InterlockedCompareExchangePointer ((gpointer * volatile)&desc_avail, desc->next, NULL) == NULL);
if (!success)
- mono_vfree (desc, desc_size * NUM_DESC_BATCH);
+ mono_vfree (desc, desc_size * NUM_DESC_BATCH, type);
}
mono_hazard_pointer_clear (hp, 1);
g_assert (desc->anchor.data.state == STATE_EMPTY);
g_assert (desc->in_use);
desc->in_use = FALSE;
- free_sb (desc->sb, desc->block_size);
- mono_thread_hazardous_free_or_queue (desc, desc_enqueue_avail, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ free_sb (desc->sb, desc->block_size, desc->heap->account_type);
+ mono_thread_hazardous_try_free (desc, desc_enqueue_avail);
}
#else
MonoLockFreeQueue available_descs;
static Descriptor*
-desc_alloc (void)
+desc_alloc (MonoMemAccountType type)
{
Descriptor *desc = (Descriptor*)mono_lock_free_queue_dequeue (&available_descs);
if (desc)
return desc;
- return calloc (1, sizeof (Descriptor));
+ return g_calloc (1, sizeof (Descriptor));
}
static void
desc_retire (Descriptor *desc)
{
- free_sb (desc->sb, desc->block_size);
+ free_sb (desc->sb, desc->block_size, desc->heap->account_type);
mono_lock_free_queue_enqueue (&available_descs, &desc->node);
}
#endif
g_assert (desc->anchor.data.state != STATE_FULL);
- mono_lock_free_queue_node_free (&desc->node);
+ mono_lock_free_queue_node_unpoison (&desc->node);
mono_lock_free_queue_enqueue (&desc->heap->sc->partial, &desc->node);
}
list_put_partial (Descriptor *desc)
{
g_assert (desc->anchor.data.state != STATE_FULL);
- mono_thread_hazardous_free_or_queue (desc, desc_put_partial, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ mono_thread_hazardous_try_free (desc, desc_put_partial);
}
static void
desc_retire (desc);
} else {
g_assert (desc->heap->sc == sc);
- mono_thread_hazardous_free_or_queue (desc, desc_put_partial, HAZARD_FREE_NO_LOCK, HAZARD_FREE_ASYNC_CTX);
+ mono_thread_hazardous_try_free (desc, desc_put_partial);
if (++num_non_empty >= 2)
return;
}
alloc_from_new_sb (MonoLockFreeAllocator *heap)
{
unsigned int slot_size, block_size, count, i;
- Descriptor *desc = desc_alloc ();
+ Descriptor *desc = desc_alloc (heap->account_type);
slot_size = desc->slot_size = heap->sc->slot_size;
block_size = desc->block_size = heap->sc->block_size;
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);
+ /*
+ * We own desc, check if it's still empty, in which case we retire it.
+ * If it's partial we need to put it back either on the active slot or
+ * on the partial list.
+ */
+ if (desc->anchor.data.state == STATE_EMPTY) {
+ desc_retire (desc);
+ } else if (desc->anchor.data.state == STATE_PARTIAL) {
+ if (InterlockedCompareExchangePointer ((gpointer * volatile)&heap->active, desc, NULL) != NULL)
+ heap_put_partial (desc);
+
+ }
} else {
/*
* Somebody else must free it, so we do some
}
void
-mono_lock_free_allocator_init_allocator (MonoLockFreeAllocator *heap, MonoLockFreeAllocSizeClass *sc)
+mono_lock_free_allocator_init_allocator (MonoLockFreeAllocator *heap, MonoLockFreeAllocSizeClass *sc, MonoMemAccountType account_type)
{
heap->sc = sc;
heap->active = NULL;
+ heap->account_type = account_type;
}