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