Merge pull request #2274 from esdrubal/udpclientreceive
[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  */
9
10 #include <config.h>
11 #include <glib.h>
12
13 #include <mono/metadata/handle.h>
14 #include <mono/metadata/handle-private.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
20 #define HANDLES_PER_CHUNK (16 - 3)
21
22 typedef struct _MonoHandleArenaChunk MonoHandleArenaChunk;
23 struct _MonoHandleArenaChunk {
24         MonoHandleArenaChunk *next;
25         gsize handles_capacity;
26         gsize handles_size;
27         MonoHandleStorage handles [MONO_ZERO_LEN_ARRAY];
28 };
29
30 struct _MonoHandleArena {
31         MonoHandleArenaChunk *chunk;
32         MonoHandleArenaChunk *chunk_last;
33         MonoHandleArena *prev;
34 };
35
36 static mono_lazy_init_t arena_status = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
37
38 #ifdef HAVE_SGEN_GC
39 static MonoGCDescriptor arena_desc = MONO_GC_DESCRIPTOR_NULL;
40 #endif
41
42 static MonoHandleArenaChunk *chunk_free_list = NULL;
43
44 static inline MonoHandleArenaChunk*
45 chunk_alloc (void)
46 {
47         MonoHandleArenaChunk *old, *new;
48
49         do {
50                 old = chunk_free_list;
51                 if (!old) {
52                         MonoHandleArenaChunk *chunk;
53
54                         chunk = g_malloc0 (sizeof (MonoHandleArenaChunk) + sizeof (MonoHandleStorage) * (HANDLES_PER_CHUNK - MONO_ZERO_LEN_ARRAY));
55                         chunk->handles_capacity = HANDLES_PER_CHUNK;
56
57                         return chunk;
58                 }
59
60                 new = old->next;
61         } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, new, old) != old);
62
63         memset (old, 0, sizeof (MonoHandleArenaChunk));
64         return old;
65 }
66
67 static inline void
68 chunk_free (MonoHandleArenaChunk *chunk)
69 {
70         do {
71                 chunk->next = chunk_free_list;
72         } while (InterlockedCompareExchangePointer ((gpointer*) &chunk_free_list, chunk, chunk->next) != chunk->next);
73 }
74
75 static MonoHandle
76 handle_new (MonoHandleArena *arena, MonoObject *obj)
77 {
78         MonoHandleArenaChunk *chunk;
79
80         g_assert (arena->chunk);
81         g_assert (arena->chunk_last);
82
83         chunk = arena->chunk_last;
84
85         if (chunk->handles_size < chunk->handles_capacity) {
86                 chunk->handles [chunk->handles_size].obj = obj;
87                 chunk->handles_size += 1;
88
89                 return &chunk->handles [chunk->handles_size - 1];
90         }
91
92         chunk = chunk->next = chunk_alloc ();
93
94         chunk->handles [0].obj = obj;
95         chunk->handles_size = 1;
96
97         arena->chunk_last = chunk;
98
99         return &chunk->handles [0];
100 }
101
102 MonoHandle
103 mono_handle_arena_new (MonoHandleArena *arena, MonoObject *obj)
104 {
105         g_assert (arena);
106         return handle_new (arena, obj);
107 }
108
109 MonoHandle
110 mono_handle_new (MonoObject *obj)
111 {
112         /* TODO: finish implementation by placing an arena somewhere
113          * in the current thread */
114         g_assert_not_reached ();
115         MonoHandleArena *arena = NULL;
116         return mono_handle_arena_new (arena, obj);
117 }
118
119 /*
120  * Elevate the handle to the parent arena
121  */
122 MonoHandle
123 mono_handle_arena_elevate (MonoHandleArena *arena, MonoHandle handle)
124 {
125         g_assert (handle);
126         g_assert (arena);
127         g_assert (arena->prev);
128
129         return handle_new (arena->prev, handle->obj);
130 }
131
132 MonoHandle
133 mono_handle_elevate (MonoHandle handle)
134 {
135         /* TODO: finish implementation by placing an arena somewhere
136          * in the current thread */
137         g_assert_not_reached ();
138         MonoHandleArena *arena = NULL;
139         return mono_handle_arena_elevate (arena, handle);
140 }
141
142 gsize
143 mono_handle_arena_size (gsize nb_handles)
144 {
145         g_assert (nb_handles > 0);
146         return sizeof (MonoHandleArena) + sizeof (MonoHandleArenaChunk) + sizeof (MonoHandle) * (MAX (nb_handles, HANDLES_PER_CHUNK) - MONO_ZERO_LEN_ARRAY);
147 }
148
149 void
150 mono_handle_arena_stack_push(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
151 {
152         g_assert (arena_stack);
153         g_assert (arena);
154
155         arena->prev = *arena_stack;
156         arena->chunk = arena->chunk_last = (MonoHandleArenaChunk*) (((char*) arena) + sizeof (MonoHandleArena));
157
158         arena->chunk->next = NULL;
159         arena->chunk->handles_capacity = MAX (nb_handles, HANDLES_PER_CHUNK);
160         arena->chunk->handles_size = 0;
161         memset (&arena->chunk->handles [0], 0, sizeof (MonoHandle) * arena->chunk->handles_capacity);
162
163         *arena_stack = arena;
164 }
165
166 void
167 mono_handle_arena_stack_pop(MonoHandleArena **arena_stack, MonoHandleArena *arena, gsize nb_handles)
168 {
169         MonoHandleArenaChunk *chunk, *next;
170
171         g_assert (arena);
172         g_assert (arena->chunk);
173         g_assert (arena->chunk_last);
174         g_assert (arena_stack);
175
176         *arena_stack = arena->prev;
177
178         for (chunk = arena->chunk; chunk; chunk = next) {
179                 next = chunk->next;
180                 memset (&chunk->handles [0], 0, sizeof (MonoHandle) * chunk->handles_capacity);
181                 if (chunk != arena->chunk)
182                         chunk_free (chunk);
183         }
184 }
185
186 static void
187 arena_scan (gpointer addr, MonoGCMarkFunc mark_func, gpointer gc_data)
188 {
189         MonoHandleArena *arena;
190         MonoHandleArenaChunk *chunk;
191         int i;
192
193         for (arena = *(MonoHandleArena**) addr; arena; arena = arena->prev) {
194                 for (chunk = arena->chunk; chunk; chunk = chunk->next) {
195                         for (i = 0; i < chunk->handles_size; ++i) {
196                                 if (chunk->handles [i].obj != NULL)
197                                         mark_func (&chunk->handles [i].obj, gc_data);
198                         }
199                 }
200         }
201 }
202
203 static void
204 initialize (void)
205 {
206 #ifdef HAVE_SGEN_GC
207         arena_desc = mono_gc_make_root_descr_user (arena_scan);
208 #endif
209 }
210
211 void
212 mono_handle_arena_initialize (MonoHandleArena **arena_stack)
213 {
214 #ifdef HAVE_SGEN_GC
215         mono_lazy_initialize (&arena_status, initialize);
216         mono_gc_register_root ((char*) arena_stack, sizeof (MonoHandleArena*), arena_desc, MONO_ROOT_SOURCE_HANDLE, "runtime threads handle arena");
217 #endif
218 }
219
220 void
221 mono_handle_arena_deinitialize (MonoHandleArena **arena_stack)
222 {
223 #ifdef HAVE_SGEN_GC
224         mono_gc_deregister_root ((char*) arena_stack);
225 #endif
226 }
227