* - Ludovic Henry <ludovic@xamarin.com>
*
* Copyright 2015 Xamarin, Inc. (www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
#include <mono/metadata/gc-internals.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-lazy-init.h>
+#include <mono/utils/mono-threads.h>
#define HANDLES_PER_CHUNK (16 - 2)
typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
struct _MonoHandleArenaChunk {
+ /* if next is NULL, this is the first chunk.
+ *
+ * The first chunk is special - it was allocated together with
+ * its owning arena and must not be deallocated unless the
+ * arena is being deallocated. N.B: Arenas are
+ * stack-allocated.
+ */
MonoHandleArenaChunk *next;
gsize handles_size;
MonoHandleStorage handles [HANDLES_PER_CHUNK];
struct _MonoHandleArena {
MonoHandleArenaChunk *chunk;
- MonoHandleArenaChunk *chunk_last;
MonoHandleArena *prev;
};
static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
-#ifdef HAVE_SGEN_GC
static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
-#endif
static MonoHandleArenaChunk *chunk_free_list = NULL;
static inline void
chunk_free (MonoHandleArenaChunk *chunk)
{
- do {
- chunk->next = chunk_free_list;
- } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
+ if (chunk == NULL)
+ return;
+ while (chunk->next != NULL) {
+ MonoHandleArenaChunk *next = chunk->next;
+ chunk->next = NULL;
+ do {
+ chunk->next = chunk_free_list;
+ } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
+ chunk = next;
+ }
}
static MonoHandle
MonoHandleArenaChunk *chunk;
g_assert (arena->chunk);
- g_assert (arena->chunk_last);
- chunk = arena->chunk_last;
+ chunk = arena->chunk;
if (chunk->handles_size < HANDLES_PER_CHUNK) {
- chunk->handles [chunk->handles_size].obj = obj;
+ chunk->handles [chunk->handles_size].__private_obj = obj;
chunk->handles_size += 1;
return &chunk->handles [chunk->handles_size - 1];
- }
+ } else {
- chunk = chunk->next = chunk_alloc ();
+ MonoHandleArenaChunk *new_chunk = chunk_alloc ();
+ new_chunk->next = chunk;
+ arena->chunk = chunk = new_chunk;
- chunk->handles [0].obj = obj;
- chunk->handles_size = 1;
+ chunk->handles [0].__private_obj = obj;
+ chunk->handles_size = 1;
- arena->chunk_last = chunk;
-
- return &chunk->handles [0];
+ return &chunk->handles [0];
+ }
}
MonoHandle
g_assert (arena);
g_assert (arena->prev);
- return handle_new (arena->prev, handle->obj);
+ return handle_new (arena->prev, handle->__private_obj);
}
gsize
g_assert (arena);
arena->prev = *arena_stack;
- arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
+ arena->chunk = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
arena->chunk->next = NULL;
arena->chunk->handles_size = 0;
g_assert (arena);
g_assert (arena->chunk);
- g_assert (arena->chunk_last);
g_assert (arena_stack);
*arena_stack = arena->prev;
for (chunk = arena->chunk; chunk; chunk = next) {
next = chunk->next;
memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
- if (chunk != arena->chunk)
+ if (next != NULL)
chunk_free (chunk);
}
}
for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
for (chunk = arena->chunk; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->handles_size; ++i) {
- if (chunk->handles [i].obj != NULL)
- mark_func (&chunk->handles [i].obj, gc_data);
+ if (chunk->handles [i].__private_obj != NULL)
+ mark_func (&chunk->handles [i].__private_obj, gc_data);
}
}
}
static void
initialize (void)
{
-#ifdef HAVE_SGEN_GC
arena_desc = mono_gc_make_root_descr_user (arena_scan);
-#endif
}
void
-mono_handle_arena_initialize (MonoHandleArena **arena_stack)
+mono_handle_arena_init (MonoHandleArena **arena_stack)
{
-#ifdef HAVE_SGEN_GC
mono_lazy_initialize (&arena_status, initialize);
mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
-#endif
}
void
-mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
+mono_handle_arena_cleanup (MonoHandleArena **arena_stack)
{
-#ifdef HAVE_SGEN_GC
mono_gc_deregister_root ((char*) arena_stack);
-#endif
}
MonoHandleArena*
mono_handle_arena_current (void)
{
- g_assert_not_reached ();
+ return (MonoHandleArena*) mono_thread_info_current ()->handle_arena;
}
MonoHandleArena**
mono_handle_arena_current_addr (void)
{
- g_assert_not_reached ();
+ return (MonoHandleArena**) &mono_thread_info_current ()->handle_arena;
}