2 * sgen-gray.c: Gray queue management.
4 * Copyright 2001-2003 Ximian, Inc
5 * Copyright 2003-2010 Novell, Inc.
6 * Copyright (C) 2012 Xamarin Inc
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License 2.0 as published by the Free Software Foundation;
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License 2.0 along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "metadata/sgen-gc.h"
25 #include "utils/mono-counters.h"
27 #define GRAY_QUEUE_LENGTH_LIMIT 64
29 #ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS
30 #define STATE_TRANSITION(s,o,n) do { \
32 if (InterlockedCompareExchange ((volatile int*)&(s)->state, (n), __old) != __old) \
33 g_assert_not_reached (); \
35 #define STATE_SET(s,v) (s)->state = (v)
36 #define STATE_ASSERT(s,v) g_assert ((s)->state == (v))
38 #define STATE_TRANSITION(s,o,n)
39 #define STATE_SET(s,v)
40 #define STATE_ASSERT(s,v)
44 sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue)
46 GrayQueueSection *section;
48 if (queue->alloc_prepare_func)
49 queue->alloc_prepare_func (queue);
51 if (queue->free_list) {
52 /* Use the previously allocated queue sections if possible */
53 section = queue->free_list;
54 queue->free_list = section->next;
55 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FREE_LIST, GRAY_QUEUE_SECTION_STATE_FLOATING);
57 /* Allocate a new section */
58 section = sgen_alloc_internal (INTERNAL_MEM_GRAY_QUEUE);
59 STATE_SET (section, GRAY_QUEUE_SECTION_STATE_FLOATING);
64 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
66 /* Link it with the others */
67 section->next = queue->first;
68 queue->first = section;
72 sgen_gray_object_free_queue_section (GrayQueueSection *section)
74 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_FREED);
75 sgen_free_internal (section, INTERNAL_MEM_GRAY_QUEUE);
79 * The following two functions are called in the inner loops of the
80 * collector, so they need to be as fast as possible. We have macros
81 * for them in sgen-gc.h.
85 sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj)
87 SGEN_ASSERT (9, obj, "enqueueing a null object");
88 //sgen_check_objref (obj);
90 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
91 if (queue->enqueue_check_func)
92 queue->enqueue_check_func (obj);
95 if (G_UNLIKELY (!queue->first || queue->first->end == SGEN_GRAY_QUEUE_SECTION_SIZE))
96 sgen_gray_object_alloc_queue_section (queue);
97 STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
98 SGEN_ASSERT (9, queue->first->end < SGEN_GRAY_QUEUE_SECTION_SIZE, "gray queue %p overflow, first %p, end %d", queue, queue->first, queue->first->end);
99 queue->first->objects [queue->first->end++] = obj;
103 sgen_gray_object_dequeue (SgenGrayQueue *queue)
107 if (sgen_gray_object_queue_is_empty (queue))
110 STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
111 SGEN_ASSERT (9, queue->first->end, "gray queue %p underflow, first %p, end %d", queue, queue->first, queue->first->end);
113 obj = queue->first->objects [--queue->first->end];
115 if (G_UNLIKELY (queue->first->end == 0)) {
116 GrayQueueSection *section = queue->first;
117 queue->first = section->next;
118 section->next = queue->free_list;
120 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FREE_LIST);
122 queue->free_list = section;
129 sgen_gray_object_dequeue_section (SgenGrayQueue *queue)
131 GrayQueueSection *section;
136 section = queue->first;
137 queue->first = section->next;
139 section->next = NULL;
141 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FLOATING);
147 sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section)
149 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
151 section->next = queue->first;
152 queue->first = section;
153 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
154 if (queue->enqueue_check_func) {
156 for (i = 0; i < section->end; ++i)
157 queue->enqueue_check_func (section->objects [i]);
163 sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func)
165 GrayQueueSection *section, *next;
168 g_assert (sgen_gray_object_queue_is_empty (queue));
170 queue->alloc_prepare_func = NULL;
171 queue->alloc_prepare_data = NULL;
172 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
173 queue->enqueue_check_func = enqueue_check_func;
176 /* Free the extra sections allocated during the last collection */
178 for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next) {
179 STATE_ASSERT (section, GRAY_QUEUE_SECTION_STATE_FREE_LIST);
184 while (section->next) {
185 next = section->next;
186 section->next = next->next;
187 STATE_TRANSITION (next, GRAY_QUEUE_SECTION_STATE_FREE_LIST, GRAY_QUEUE_SECTION_STATE_FLOATING);
188 sgen_gray_object_free_queue_section (next);
193 invalid_prepare_func (SgenGrayQueue *queue)
195 g_assert_not_reached ();
199 sgen_gray_object_queue_init_invalid (SgenGrayQueue *queue)
201 sgen_gray_object_queue_init (queue, FALSE);
202 queue->alloc_prepare_func = invalid_prepare_func;
203 queue->alloc_prepare_data = NULL;
207 sgen_gray_object_queue_init_with_alloc_prepare (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func,
208 GrayQueueAllocPrepareFunc alloc_prepare_func, void *data)
210 sgen_gray_object_queue_init (queue, enqueue_check_func);
211 queue->alloc_prepare_func = alloc_prepare_func;
212 queue->alloc_prepare_data = data;
216 sgen_gray_object_queue_deinit (SgenGrayQueue *queue)
218 g_assert (!queue->first);
219 while (queue->free_list) {
220 GrayQueueSection *next = queue->free_list->next;
221 STATE_TRANSITION (queue->free_list, GRAY_QUEUE_SECTION_STATE_FREE_LIST, GRAY_QUEUE_SECTION_STATE_FLOATING);
222 sgen_gray_object_free_queue_section (queue->free_list);
223 queue->free_list = next;
228 sgen_gray_object_queue_disable_alloc_prepare (SgenGrayQueue *queue)
230 queue->alloc_prepare_func = NULL;
231 queue->alloc_prepare_data = NULL;
235 lock_section_queue (SgenSectionGrayQueue *queue)
240 mono_mutex_lock (&queue->lock);
244 unlock_section_queue (SgenSectionGrayQueue *queue)
249 mono_mutex_unlock (&queue->lock);
253 sgen_section_gray_queue_init (SgenSectionGrayQueue *queue, gboolean locked, GrayQueueEnqueueCheckFunc enqueue_check_func)
255 g_assert (sgen_section_gray_queue_is_empty (queue));
257 queue->locked = locked;
259 mono_mutex_init_recursive (&queue->lock);
262 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
263 queue->enqueue_check_func = enqueue_check_func;
268 sgen_section_gray_queue_is_empty (SgenSectionGrayQueue *queue)
270 return !queue->first;
274 sgen_section_gray_queue_dequeue (SgenSectionGrayQueue *queue)
276 GrayQueueSection *section;
278 lock_section_queue (queue);
281 section = queue->first;
282 queue->first = section->next;
284 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FLOATING);
286 section->next = NULL;
291 unlock_section_queue (queue);
297 sgen_section_gray_queue_enqueue (SgenSectionGrayQueue *queue, GrayQueueSection *section)
299 STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
301 lock_section_queue (queue);
303 section->next = queue->first;
304 queue->first = section;
305 #ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
306 if (queue->enqueue_check_func) {
308 for (i = 0; i < section->end; ++i)
309 queue->enqueue_check_func (section->objects [i]);
313 unlock_section_queue (queue);