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>
19 #define HANDLES_PER_CHUNK (16 - 2)
21 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
22 struct _MonoHandleArenaChunk {
23 MonoHandleArenaChunk *next;
25 MonoHandleStorage handles [HANDLES_PER_CHUNK];
28 struct _MonoHandleArena {
29 MonoHandleArenaChunk *chunk;
30 MonoHandleArenaChunk *chunk_last;
31 MonoHandleArena *prev;
34 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
36 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
38 static MonoHandleArenaChunk *chunk_free_list = NULL;
40 static inline MonoHandleArenaChunk*
43 MonoHandleArenaChunk *old, *new;
46 old = chunk_free_list;
48 MonoHandleArenaChunk *chunk;
50 chunk = g_malloc0 (sizeof (MonoHandleArenaChunk));
57 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
59 memset (old, 0, sizeof (MonoHandleArenaChunk));
64 chunk_free (MonoHandleArenaChunk *chunk)
67 chunk->next = chunk_free_list;
68 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
72 handle_new (MonoHandleArena *arena, MonoObject *obj)
74 MonoHandleArenaChunk *chunk;
76 g_assert (arena->chunk);
77 g_assert (arena->chunk_last);
79 chunk = arena->chunk_last;
81 if (chunk->handles_size < HANDLES_PER_CHUNK) {
82 chunk->handles [chunk->handles_size].__private_obj = obj;
83 chunk->handles_size += 1;
85 return &chunk->handles [chunk->handles_size - 1];
88 chunk = chunk->next = chunk_alloc ();
90 chunk->handles [0].__private_obj = obj;
91 chunk->handles_size = 1;
93 arena->chunk_last = chunk;
95 return &chunk->handles [0];
99 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
102 return handle_new (arena, obj);
106 * Elevate the handle to the parent arena
109 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
113 g_assert (arena->prev);
115 return handle_new (arena->prev, handle->__private_obj);
119 mono_handle_arena_size (void)
121 return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk);
125 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena)
127 g_assert (arena_stack);
130 arena->prev = *arena_stack;
131 arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
133 arena->chunk->next = NULL;
134 arena->chunk->handles_size = 0;
135 memset (&arena->chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
137 *arena_stack = arena;
141 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena)
143 MonoHandleArenaChunk *chunk, *next;
146 g_assert (arena->chunk);
147 g_assert (arena->chunk_last);
148 g_assert (arena_stack);
150 *arena_stack = arena->prev;
152 for (chunk = arena->chunk; chunk; chunk = next) {
154 memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
155 if (chunk != arena->chunk)
161 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
163 MonoHandleArena *arena;
164 MonoHandleArenaChunk *chunk;
167 for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
168 for (chunk = arena->chunk; chunk; chunk = chunk->next) {
169 for (i = 0; i < chunk->handles_size; ++i) {
170 if (chunk->handles [i].__private_obj != NULL)
171 mark_func (&chunk->handles [i].__private_obj, gc_data);
180 arena_desc = mono_gc_make_root_descr_user (arena_scan);
184 mono_handle_arena_initialize (MonoHandleArena **arena_stack)
186 mono_lazy_initialize (&arena_status, initialize);
187 mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
191 mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
193 mono_gc_deregister_root ((char*) arena_stack);
197 mono_handle_arena_current (void)
199 g_assert_not_reached ();
203 mono_handle_arena_current_addr (void)
205 g_assert_not_reached ();