* lock-free-alloc.c: 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.
*/
/*
#include <glib.h>
#include <stdlib.h>
-#include <mono/io-layer/atomic.h>
+#include <mono/io-layer/io-layer.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/hazard-pointer.h>
struct _MonoLockFreeAllocDescriptor {
MonoLockFreeQueueNode node;
MonoLockFreeAllocator *heap;
- Anchor anchor;
+ volatile Anchor anchor;
unsigned int slot_size;
unsigned int max_count;
gpointer sb;
#ifndef DESC_AVAIL_DUMMY
- Descriptor *next;
+ Descriptor * volatile next;
#endif
- gboolean in_use;
+ gboolean in_use; /* used for debugging only */
};
#define NUM_DESC_BATCH 64
/* Taken from SGen */
-static void*
-mono_sgen_alloc_os_memory (size_t size, int activate)
+static unsigned long
+prot_flags_for_activate (int activate)
{
- void *ptr;
unsigned long prot_flags = activate? MONO_MMAP_READ|MONO_MMAP_WRITE: MONO_MMAP_NONE;
+ return prot_flags | MONO_MMAP_PRIVATE | MONO_MMAP_ANON;
+}
- prot_flags |= MONO_MMAP_PRIVATE | MONO_MMAP_ANON;
- ptr = mono_valloc (0, size, prot_flags);
- return ptr;
+static void*
+mono_sgen_alloc_os_memory (size_t size, int activate)
+{
+ return mono_valloc (0, size, prot_flags_for_activate (activate));
}
static void
static void*
mono_sgen_alloc_os_memory_aligned (size_t size, size_t alignment, gboolean activate)
{
- /* Allocate twice the memory to be able to put the block on an aligned address */
- char *mem = mono_sgen_alloc_os_memory (size + alignment, activate);
- char *aligned;
-
- g_assert (mem);
-
- aligned = (char*)((gulong)(mem + (alignment - 1)) & ~(alignment - 1));
- g_assert (aligned >= mem && aligned + size <= mem + size + alignment && !((gulong)aligned & (alignment - 1)));
-
- if (aligned > mem)
- mono_sgen_free_os_memory (mem, aligned - mem);
- if (aligned + size < mem + size + alignment)
- mono_sgen_free_os_memory (aligned + size, (mem + size + alignment) - (aligned + size));
-
- return aligned;
+ return mono_valloc_aligned (size, alignment, prot_flags_for_activate (activate));
}
static gpointer
g_assert (desc->in_use);
desc->in_use = FALSE;
free_sb (desc->sb);
- mono_thread_hazardous_free_or_queue (desc, desc_enqueue_avail);
+ mono_thread_hazardous_free_or_queue (desc, desc_enqueue_avail, FALSE, TRUE);
}
#else
MonoLockFreeQueue available_descs;
list_put_partial (Descriptor *desc)
{
g_assert (desc->anchor.data.state != STATE_FULL);
- mono_thread_hazardous_free_or_queue (desc, desc_put_partial);
+ mono_thread_hazardous_free_or_queue (desc, desc_put_partial, FALSE, TRUE);
}
static void
desc_retire (desc);
} else {
g_assert (desc->heap->sc == sc);
- mono_thread_hazardous_free_or_queue (desc, desc_put_partial);
+ mono_thread_hazardous_free_or_queue (desc, desc_put_partial, FALSE, TRUE);
if (++num_non_empty >= 2)
return;
}
do {
unsigned int next;
- new_anchor = old_anchor = (Anchor)*(volatile gint32*)&desc->anchor.value;
+ new_anchor = old_anchor = *(volatile Anchor*)&desc->anchor.value;
if (old_anchor.data.state == STATE_EMPTY) {
/* We must free it because we own it. */
desc_retire (desc);
g_assert (SB_HEADER_FOR_ADDR (ptr) == SB_HEADER_FOR_ADDR (sb));
do {
- new_anchor = old_anchor = (Anchor)*(volatile gint32*)&desc->anchor.value;
+ 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 < SB_USABLE_SIZE / desc->slot_size);
{
int count = desc->anchor.data.count;
int max_count = SB_USABLE_SIZE / desc->slot_size;
+#if _MSC_VER
+ gboolean* linked = alloca(max_count*sizeof(gboolean));
+#else
gboolean linked [max_count];
+#endif
int i, last;
unsigned int index;