Merge branch 'sgen-job-distribution'
[mono.git] / mono / metadata / sgen-gray.c
index 5db675164082b1797381fcea503191e407948017..5c57fb42551bd72b0258d3a36dc7987318023986 100644 (file)
-#define GRAY_QUEUE_SECTION_SIZE        (128 - 3)
-#define GRAY_QUEUE_LENGTH_LIMIT        64
-
 /*
- * This is a stack now instead of a queue, so the most recently added items are removed
- * first, improving cache locality, and keeping the stack size manageable.
+ * Copyright 2001-2003 Ximian, Inc
+ * Copyright 2003-2010 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.
  */
-typedef struct _GrayQueueSection GrayQueueSection;
-struct _GrayQueueSection {
-       int end;
-       GrayQueueSection *next, *prev;
-       char *objects [GRAY_QUEUE_SECTION_SIZE];
-};
-
-static GrayQueueSection *gray_queue_start = NULL;
-static GrayQueueSection *gray_queue_end = NULL;
+#define GRAY_QUEUE_LENGTH_LIMIT        64
 
-static int gray_queue_balance = 0;
-static int num_gray_queue_sections = 0;
+static GrayQueue gray_queue;
 
 static void
-gray_object_alloc_queue_section (void)
+gray_object_alloc_queue_section (GrayQueue *queue)
 {
        GrayQueueSection *section;
 
-       /* Use the previously allocated queue sections if possible */
-       if (!gray_queue_end && gray_queue_start) {
-               gray_queue_end = gray_queue_start;
-               gray_queue_end->end = 0;
-               return;
-       }
-       if (gray_queue_end && gray_queue_end->next) {
-               gray_queue_end = gray_queue_end->next;
-               gray_queue_end->end = 0;
-               return;
-       }
+       if (queue->alloc_prepare_func)
+               queue->alloc_prepare_func (queue);
 
-       /* Allocate a new section */
-       section = get_internal_mem (sizeof (GrayQueueSection), INTERNAL_MEM_GRAY_QUEUE);
-       ++num_gray_queue_sections;
+       if (queue->free_list) {
+               /* Use the previously allocated queue sections if possible */
+               section = queue->free_list;
+               queue->free_list = section->next;
+       } else {
+               /* Allocate a new section */
+               section = mono_sgen_alloc_internal_fixed (queue->allocator, INTERNAL_MEM_GRAY_QUEUE);
+       }
 
        section->end = 0;
-       section->next = NULL;
-       section->prev = NULL;
 
        /* Link it with the others */
-       if (gray_queue_end) {
-               gray_queue_end->next = section;
-               section->prev = gray_queue_end;
-       } else {
-               g_assert (!gray_queue_start);
-               gray_queue_start = section;
-       }
-       gray_queue_end = section;
+       section->next = queue->first;
+       queue->first = section;
 }
 
 static void
-gray_object_free_queue_section (GrayQueueSection *section)
+gray_object_free_queue_section (GrayQueueSection *section, SgenInternalAllocator *thread_allocator)
 {
-       free_internal_mem (section, INTERNAL_MEM_GRAY_QUEUE);
-       --num_gray_queue_sections;
+       mono_sgen_free_internal_delayed (section, INTERNAL_MEM_GRAY_QUEUE, thread_allocator);
 }
 
-/* 
- * The following three functions are called in the inner loops of the collector, so they
- * need to be as fast as possible.
- */
-
-static inline void
-gray_object_enqueue (char *obj)
+static inline gboolean
+gray_object_queue_is_empty (GrayQueue *queue)
 {
-       g_assert (obj);
-       if (G_UNLIKELY (!gray_queue_end || gray_queue_end->end == GRAY_QUEUE_SECTION_SIZE))
-               gray_object_alloc_queue_section ();
-       g_assert (gray_queue_end && gray_queue_end->end < GRAY_QUEUE_SECTION_SIZE);
-       gray_queue_end->objects [gray_queue_end->end++] = obj;
-
-       ++gray_queue_balance;
+       return queue->first == NULL;
 }
 
-static inline gboolean
-gray_object_queue_is_empty (void)
+/*
+ * The following two functions are called in the inner loops of the
+ * collector, so they need to be as fast as possible.  We have macros
+ * for them in sgen-gc.h.
+ */
+
+void
+mono_sgen_gray_object_enqueue (GrayQueue *queue, char *obj)
 {
-       return gray_queue_end == NULL;
+       DEBUG (9, g_assert (obj));
+       if (G_UNLIKELY (!queue->first || queue->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE))
+               gray_object_alloc_queue_section (queue);
+       DEBUG (9, g_assert (queue->first && queue->first->end < SGEN_GRAY_QUEUE_SECTION_SIZE));
+       queue->first->objects [queue->first->end++] = obj;
+
+       DEBUG (9, ++queue->balance);
 }
 
-static inline char*
-gray_object_dequeue (void)
+char*
+mono_sgen_gray_object_dequeue (GrayQueue *queue)
 {
        char *obj;
 
-       if (gray_object_queue_is_empty ())
+       if (gray_object_queue_is_empty (queue))
                return NULL;
 
-       g_assert (gray_queue_end->end);
+       DEBUG (9, g_assert (queue->first->end));
 
-       obj = gray_queue_end->objects [--gray_queue_end->end];
+       obj = queue->first->objects [--queue->first->end];
 
-       if (G_UNLIKELY (gray_queue_end->end == 0))
-               gray_queue_end = gray_queue_end->prev;
+       if (G_UNLIKELY (queue->first->end == 0)) {
+               GrayQueueSection *section = queue->first;
+               queue->first = section->next;
+               section->next = queue->free_list;
+               queue->free_list = section;
+       }
 
-       --gray_queue_balance;
+       DEBUG (9, --queue->balance);
 
        return obj;
 }
 
+static GrayQueueSection*
+gray_object_dequeue_section (GrayQueue *queue)
+{
+       GrayQueueSection *section;
+
+       if (!queue->first)
+               return NULL;
+
+       section = queue->first;
+       queue->first = section->next;
+
+       section->next = NULL;
+
+       return section;
+}
+
 static void
-gray_object_queue_init (void)
+gray_object_enqueue_section (GrayQueue *queue, GrayQueueSection *section)
+{
+       section->next = queue->first;
+       queue->first = section;
+}
+
+static void
+gray_object_queue_init (GrayQueue *queue, SgenInternalAllocator *allocator)
 {
        GrayQueueSection *section, *next;
        int i;
 
-       g_assert (gray_object_queue_is_empty ());
-       g_assert (sizeof (GrayQueueSection) < MAX_FREELIST_SIZE);
-       g_assert (gray_queue_balance == 0);
+       g_assert (gray_object_queue_is_empty (queue));
+       DEBUG (9, g_assert (queue->balance == 0));
+
+       queue->allocator = allocator;
 
        /* Free the extra sections allocated during the last collection */
        i = 0;
-       for (section = gray_queue_start; section && i < GRAY_QUEUE_LENGTH_LIMIT; section = section->next)
+       for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next)
                i ++;
-       if (section) {
-               if (section->prev)
-                       section->prev->next = NULL;
-               for (; section; section = next) {
-                       next = section->next;
-                       gray_object_free_queue_section (section);
-               }
+       if (!section)
+               return;
+       while (section->next) {
+               next = section->next;
+               section->next = next->next;
+               gray_object_free_queue_section (next, allocator);
        }
 }
+
+static void
+gray_object_queue_init_with_alloc_prepare (GrayQueue *queue, SgenInternalAllocator *allocator, GrayQueueAllocPrepareFunc func, void *data)
+{
+       gray_object_queue_init (queue, allocator);
+       queue->alloc_prepare_func = func;
+       queue->alloc_prepare_data = data;
+}