2 * handle.c: Handle to object in native code
5 * - Ludovic Henry <ludovic@xamarin.com>
7 * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
13 #include <mono/metadata/handle.h>
14 #include <mono/metadata/object-internals.h>
15 #include <mono/metadata/gc-internals.h>
16 #include <mono/utils/atomic.h>
17 #include <mono/utils/mono-lazy-init.h>
18 #include <mono/utils/mono-threads.h>
20 #define HANDLES_PER_CHUNK (16 - 2)
22 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
23 struct _MonoHandleArenaChunk {
24 /* if next is NULL, this is the first chunk.
26 * The first chunk is special - it was allocated together with
27 * its owning arena and must not be deallocated unless the
28 * arena is being deallocated. N.B: Arenas are
31 MonoHandleArenaChunk *next;
33 MonoHandleStorage handles [HANDLES_PER_CHUNK];
36 struct _MonoHandleArena {
37 MonoHandleArenaChunk *chunk;
38 MonoHandleArena *prev;
41 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
43 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
45 static MonoHandleArenaChunk *chunk_free_list = NULL;
47 static inline MonoHandleArenaChunk*
50 MonoHandleArenaChunk *old, *new;
53 old = chunk_free_list;
55 MonoHandleArenaChunk *chunk;
57 chunk = g_malloc0 (sizeof (MonoHandleArenaChunk));
64 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
66 memset (old, 0, sizeof (MonoHandleArenaChunk));
71 chunk_free (MonoHandleArenaChunk *chunk)
75 while (chunk->next != NULL) {
76 MonoHandleArenaChunk *next = chunk->next;
79 chunk->next = chunk_free_list;
80 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
86 handle_new (MonoHandleArena *arena, MonoObject *obj)
88 MonoHandleArenaChunk *chunk;
90 g_assert (arena->chunk);
94 if (chunk->handles_size < HANDLES_PER_CHUNK) {
95 chunk->handles [chunk->handles_size].__private_obj = obj;
96 chunk->handles_size += 1;
98 return &chunk->handles [chunk->handles_size - 1];
101 MonoHandleArenaChunk *new_chunk = chunk_alloc ();
102 new_chunk->next = chunk;
103 arena->chunk = chunk = new_chunk;
105 chunk->handles [0].__private_obj = obj;
106 chunk->handles_size = 1;
108 return &chunk->handles [0];
113 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
116 return handle_new (arena, obj);
120 * Elevate the handle to the parent arena
123 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
127 g_assert (arena->prev);
129 return handle_new (arena->prev, handle->__private_obj);
133 mono_handle_arena_size (void)
135 return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk);
139 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena)
141 g_assert (arena_stack);
144 arena->prev = *arena_stack;
145 arena->chunk = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
147 arena->chunk->next = NULL;
148 arena->chunk->handles_size = 0;
149 memset (&arena->chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
151 *arena_stack = arena;
155 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena)
157 MonoHandleArenaChunk *chunk, *next;
160 g_assert (arena->chunk);
161 g_assert (arena_stack);
163 *arena_stack = arena->prev;
165 for (chunk = arena->chunk; chunk; chunk = next) {
167 memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
174 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
176 MonoHandleArena *arena;
177 MonoHandleArenaChunk *chunk;
180 for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
181 for (chunk = arena->chunk; chunk; chunk = chunk->next) {
182 for (i = 0; i < chunk->handles_size; ++i) {
183 if (chunk->handles [i].__private_obj != NULL)
184 mark_func (&chunk->handles [i].__private_obj, gc_data);
193 arena_desc = mono_gc_make_root_descr_user (arena_scan);
197 mono_handle_arena_init (MonoHandleArena **arena_stack)
199 mono_lazy_initialize (&arena_status, initialize);
200 mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
204 mono_handle_arena_cleanup (MonoHandleArena **arena_stack)
206 mono_gc_deregister_root ((char*) arena_stack);
210 mono_handle_arena_current (void)
212 return (MonoHandleArena*) mono_thread_info_current ()->handle_arena;
216 mono_handle_arena_current_addr (void)
218 return (MonoHandleArena**) &mono_thread_info_current ()->handle_arena;