First set of licensing changes
[mono.git] / mono / metadata / handle.c
1 /*
2  * handle.c: Handle to object in native code
3  *
4  * Authors:
5  *  - Ludovic Henry <ludovic@xamarin.com>
6  *
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.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13
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>
20
21 #define HANDLES_PER_CHUNK (16 - 2)
22
23 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
24 struct _MonoHandleArenaChunk {
25         /* if next is NULL, this is the first chunk.
26          *
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
30          * stack-allocated.
31          */
32         MonoHandleArenaChunk *next;
33         gsize handles_size;
34         MonoHandleStorage handles [HANDLES_PER_CHUNK];
35 };
36
37 struct _MonoHandleArena {
38         MonoHandleArenaChunk *chunk;
39         MonoHandleArena *prev;
40 };
41
42 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
43
44 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
45
46 static MonoHandleArenaChunk *chunk_free_list = NULL;
47
48 static inline MonoHandleArenaChunk*
49 chunk_alloc (void)
50 {
51         MonoHandleArenaChunk *old, *new;
52
53         do {
54                 old = chunk_free_list;
55                 if (!old) {
56                         MonoHandleArenaChunk *chunk;
57
58                         chunk = g_malloc0 (sizeof (MonoHandleArenaChunk));
59                         g_assert (chunk);
60
61                         return chunk;
62                 }
63
64                 new = old->next;
65         } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
66
67         memset (old, 0, sizeof (MonoHandleArenaChunk));
68         return old;
69 }
70
71 static inline void
72 chunk_free (MonoHandleArenaChunk *chunk)
73 {
74         if (chunk == NULL)
75                 return;
76         while (chunk->next != NULL) {
77                 MonoHandleArenaChunk *next = chunk->next;
78                 chunk->next = NULL;
79                 do {
80                         chunk->next = chunk_free_list;
81                 } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
82                 chunk = next;
83         }
84 }
85
86 static MonoHandle
87 handle_new (MonoHandleArena *arena, MonoObject *obj)
88 {
89         MonoHandleArenaChunk *chunk;
90
91         g_assert (arena->chunk);
92
93         chunk = arena->chunk;
94
95         if (chunk->handles_size < HANDLES_PER_CHUNK) {
96                 chunk->handles [chunk->handles_size].__private_obj = obj;
97                 chunk->handles_size += 1;
98
99                 return &chunk->handles [chunk->handles_size - 1];
100         } else {
101
102                 MonoHandleArenaChunk *new_chunk = chunk_alloc ();
103                 new_chunk->next = chunk;
104                 arena->chunk = chunk = new_chunk;
105
106                 chunk->handles [0].__private_obj = obj;
107                 chunk->handles_size = 1;
108
109                 return &chunk->handles [0];
110         }
111 }
112
113 MonoHandle
114 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
115 {
116         g_assert (arena);
117         return handle_new (arena, obj);
118 }
119
120 /*
121  * Elevate the handle to the parent arena
122  */
123 MonoHandle
124 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
125 {
126         g_assert (handle);
127         g_assert (arena);
128         g_assert (arena->prev);
129
130         return handle_new (arena->prev, handle->__private_obj);
131 }
132
133 gsize
134 mono_handle_arena_size (void)
135 {
136         return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk);
137 }
138
139 void
140 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena)
141 {
142         g_assert (arena_stack);
143         g_assert (arena);
144
145         arena->prev = *arena_stack;
146         arena->chunk = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
147
148         arena->chunk->next = NULL;
149         arena->chunk->handles_size = 0;
150         memset (&arena->chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
151
152         *arena_stack = arena;
153 }
154
155 void
156 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena)
157 {
158         MonoHandleArenaChunk *chunk, *next;
159
160         g_assert (arena);
161         g_assert (arena->chunk);
162         g_assert (arena_stack);
163
164         *arena_stack = arena->prev;
165
166         for (chunk = arena->chunk; chunk; chunk = next) {
167                 next = chunk->next;
168                 memset (&chunk->handles [0], 0, sizeof (MonoHandleStorage) * HANDLES_PER_CHUNK);
169                 if (next != NULL)
170                         chunk_free (chunk);
171         }
172 }
173
174 static void
175 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
176 {
177         MonoHandleArena *arena;
178         MonoHandleArenaChunk *chunk;
179         int i;
180
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);
186                         }
187                 }
188         }
189 }
190
191 static void
192 initialize (void)
193 {
194         arena_desc = mono_gc_make_root_descr_user (arena_scan);
195 }
196
197 void
198 mono_handle_arena_init (MonoHandleArena **arena_stack)
199 {
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");
202 }
203
204 void
205 mono_handle_arena_cleanup (MonoHandleArena **arena_stack)
206 {
207         mono_gc_deregister_root ((char*) arena_stack);
208 }
209
210 MonoHandleArena*
211 mono_handle_arena_current (void)
212 {
213         return (MonoHandleArena*) mono_thread_info_current ()->handle_arena;
214 }
215
216 MonoHandleArena**
217 mono_handle_arena_current_addr (void)
218 {
219         return (MonoHandleArena**) &mono_thread_info_current ()->handle_arena;
220 }