2 * handle.c: Handle to object in native code
5 * - Ludovic Henry <ludovic@xamarin.com>
7 * Copyright 2015 Xamarin, Inc. (www.xamarin.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <mono/metadata/handle.h>
15 #include <mono/metadata/object-internals.h>
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/utils/atomic.h>
18 #include <mono/utils/mono-lazy-init.h>
19 #include <mono/utils/mono-threads.h>
21 #define HANDLES_PER_CHUNK (16 - 2)
23 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
24 struct _MonoHandleArenaChunk {
25 /* if next is NULL, this is the first chunk.
27 * The first chunk is special - it was allocated together with
28 * its owning arena and must not be deallocated unless the
29 * arena is being deallocated. N.B: Arenas are
32 MonoHandleArenaChunk *next;
34 MonoHandleStorage handles [HANDLES_PER_CHUNK];
37 struct _MonoHandleArena {
38 MonoHandleArenaChunk *chunk;
39 MonoHandleArena *prev;
42 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
44 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
46 static MonoHandleArenaChunk *chunk_free_list = NULL;
48 static inline MonoHandleArenaChunk*
51 MonoHandleArenaChunk *old, *new;
54 old = chunk_free_list;
56 MonoHandleArenaChunk *chunk;
58 chunk = g_malloc0 (sizeof (MonoHandleArenaChunk));
65 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
67 memset (old, 0, sizeof (MonoHandleArenaChunk));
72 chunk_free (MonoHandleArenaChunk *chunk)
76 while (chunk->next != NULL) {
77 MonoHandleArenaChunk *next = chunk->next;
80 chunk->next = chunk_free_list;
81 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
87 handle_new (MonoHandleArena *arena, MonoObject *obj)
89 MonoHandleArenaChunk *chunk;
91 g_assert (arena->chunk);
95 if (chunk->handles_size < HANDLES_PER_CHUNK) {
96 chunk->handles [chunk->handles_size].__private_obj = obj;
97 chunk->handles_size += 1;
99 return &chunk->handles [chunk->handles_size - 1];
102 MonoHandleArenaChunk *new_chunk = chunk_alloc ();
103 new_chunk->next = chunk;
104 arena->chunk = chunk = new_chunk;
106 chunk->handles [0].__private_obj = obj;
107 chunk->handles_size = 1;
109 return &chunk->handles [0];
114 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
117 return handle_new (arena, obj);
121 * Elevate the handle to the parent arena
124 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
128 g_assert (arena->prev);
130 return handle_new (arena->prev, handle->__private_obj);
134 mono_handle_arena_size (void)
136 return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk);
140 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena)
142 g_assert (arena_stack);
145 arena->prev = *arena_stack;
146 arena->chunk = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
148 arena->chunk->next = NULL;
149 arena->chunk->handles_size = 0;
150 memset (&arena->chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
152 *arena_stack = arena;
156 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena)
158 MonoHandleArenaChunk *chunk, *next;
161 g_assert (arena->chunk);
162 g_assert (arena_stack);
164 *arena_stack = arena->prev;
166 for (chunk = arena->chunk; chunk; chunk = next) {
168 memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
175 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
177 MonoHandleArena *arena;
178 MonoHandleArenaChunk *chunk;
181 for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
182 for (chunk = arena->chunk; chunk; chunk = chunk->next) {
183 for (i = 0; i < chunk->handles_size; ++i) {
184 if (chunk->handles [i].__private_obj != NULL)
185 mark_func (&chunk->handles [i].__private_obj, gc_data);
194 arena_desc = mono_gc_make_root_descr_user (arena_scan);
198 mono_handle_arena_init (MonoHandleArena **arena_stack)
200 mono_lazy_initialize (&arena_status, initialize);
201 mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
205 mono_handle_arena_cleanup (MonoHandleArena **arena_stack)
207 mono_gc_deregister_root ((char*) arena_stack);
211 mono_handle_arena_current (void)
213 return (MonoHandleArena*) mono_thread_info_current ()->handle_arena;
217 mono_handle_arena_current_addr (void)
219 return (MonoHandleArena**) &mono_thread_info_current ()->handle_arena;