Merge pull request #551 from jack-pappas/sgen-patch
[mono.git] / mono / utils / lock-free-alloc.c
index 83c2fc8de73f548584c04309d7e143d924fb6b2a..916a1aac0886a4e0f17c18a82c2bc8dcba4edb95 100644 (file)
@@ -2,6 +2,25 @@
  * 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.
  */
 
 /*
@@ -63,7 +82,7 @@
 #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>
@@ -92,14 +111,14 @@ typedef struct _MonoLockFreeAllocDescriptor Descriptor;
 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
@@ -113,15 +132,17 @@ struct _MonoLockFreeAllocDescriptor {
 
 /* 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
@@ -134,21 +155,7 @@ mono_sgen_free_os_memory (void *addr, size_t size)
 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
@@ -245,7 +252,7 @@ desc_retire (Descriptor *desc)
        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;
@@ -297,7 +304,7 @@ static void
 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
@@ -316,7 +323,7 @@ list_remove_empty_desc (MonoLockFreeAllocSizeClass *sc)
                        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;
                }
@@ -367,7 +374,7 @@ alloc_from_active_or_partial (MonoLockFreeAllocator *heap)
        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);
@@ -470,7 +477,7 @@ mono_lock_free_free (gpointer ptr)
        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);
@@ -524,7 +531,11 @@ descriptor_check_consistency (Descriptor *desc, gboolean print)
 {
        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;