Fix call to mono_sgen_gc_unlock () in mono_gc_toggleref_add ().
[mono.git] / mono / metadata / sgen-toggleref.c
1 /*
2  *
3  * sgen-toggleref.c: toggleref support for sgen
4  *
5  * Copyright 2011 Xamarin, Inc.
6  *
7  * Author:
8  *  Rodrigo Kumpera (kumpera@gmail.com)
9  * 
10  * Permission is hereby granted, free of charge, to any person obtaining
11  * a copy of this software and associated documentation files (the
12  * "Software"), to deal in the Software without restriction, including
13  * without limitation the rights to use, copy, modify, merge, publish,
14  * distribute, sublicense, and/or sell copies of the Software, and to
15  * permit persons to whom the Software is furnished to do so, subject to
16  * the following conditions:
17  * 
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  * 
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28  */
29
30
31 #include "config.h"
32
33 #ifdef HAVE_SGEN_GC
34
35 #include "sgen-gc.h"
36 #include "sgen-toggleref.h"
37
38
39 /*only one of the two can be non null at a given time*/
40 typedef struct {
41         void *strong_ref;
42         void *weak_ref;
43 } MonoGCToggleRef;
44
45 static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
46 static MonoGCToggleRef *toggleref_array;
47 static int toogleref_array_size;
48 static int toogleref_array_capacity;
49
50 void
51 mono_sgen_process_togglerefs (void)
52 {
53         int i, w;
54         int toggle_ref_counts [3] = { 0 };
55
56         DEBUG (4, fprintf (gc_debug_file, "Proccessing ToggleRefs %d\n", toogleref_array_size));
57
58         for (i = w = 0; i < toogleref_array_size; ++i) {
59                 int res;
60                 MonoGCToggleRef r = toggleref_array [i];
61
62                 MonoObject *obj;
63
64                 if (r.strong_ref)
65                         obj = r.strong_ref;
66                 else if (r.weak_ref)
67                         obj = r.weak_ref;
68                 else
69                         continue;
70
71                 res = toggleref_callback (obj);
72                 ++toggle_ref_counts [res];
73                 switch (res) {
74                 case MONO_TOGGLE_REF_DROP:
75                         break;
76                 case MONO_TOGGLE_REF_STRONG:
77                         toggleref_array [w].strong_ref = obj;
78                         toggleref_array [w].weak_ref = NULL;
79                         ++w;
80                         break;
81                 case MONO_TOGGLE_REF_WEAK:
82                         toggleref_array [w].strong_ref = NULL;
83                         toggleref_array [w].weak_ref = obj;
84                         ++w;
85                         break;
86                 default:
87                         g_assert_not_reached ();
88                 }
89         }
90
91         toogleref_array_size = w;
92
93         DEBUG (4, fprintf (gc_debug_file, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d\n",
94                 toggle_ref_counts [MONO_TOGGLE_REF_DROP],
95                 toggle_ref_counts [MONO_TOGGLE_REF_STRONG],
96                 toggle_ref_counts [MONO_TOGGLE_REF_WEAK],
97                 w));
98 }
99
100 void
101 mono_sgen_scan_togglerefs (CopyOrMarkObjectFunc copy_func, char *start, char *end, SgenGrayQueue *queue)
102 {
103         int i;
104
105         DEBUG (4, fprintf (gc_debug_file, "Scanning ToggleRefs %d\n", toogleref_array_size));
106
107         for (i = 0; i < toogleref_array_size; ++i) {
108                 if (toggleref_array [i].strong_ref) {
109                         char *object = toggleref_array [i].strong_ref;
110                         if (object >= start && object < end) {
111                                 DEBUG (6, fprintf (gc_debug_file, "\tcopying strong slot %d\n", i));
112                                 copy_func (&toggleref_array [i].strong_ref, queue);
113                         }
114                 } else if (toggleref_array [i].weak_ref) {
115                         char *object = toggleref_array [i].weak_ref;
116
117                         if (object >= start && object < end) {
118                                 if (mono_sgen_gc_is_object_ready_for_finalization (object)) {
119                                         DEBUG (6, fprintf (gc_debug_file, "\tcleaning weak slot %d\n", i));
120                                         toggleref_array [i].weak_ref = NULL; /* We defer compaction to only happen on the callback step. */
121                                 } else {
122                                         DEBUG (6, fprintf (gc_debug_file, "\tkeeping weak slot %d\n", i));
123                                         copy_func (&toggleref_array [i].weak_ref, queue);
124                                 }
125                         }
126                 }
127         }
128 }
129
130 static void
131 ensure_toggleref_capacity (int capacity)
132 {
133         if (!toggleref_array) {
134                 toogleref_array_capacity = 32;
135                 toggleref_array = mono_sgen_alloc_internal_dynamic (
136                         toogleref_array_capacity * sizeof (MonoGCToggleRef),
137                         INTERNAL_MEM_TOGGLEREF_DATA);   
138         }
139         if (toogleref_array_size + capacity >= toogleref_array_capacity) {
140                 MonoGCToggleRef *tmp;
141                 int old_capacity = toogleref_array_capacity;
142                 while (toogleref_array_capacity < toogleref_array_size + capacity)
143                         toogleref_array_size *= 2;
144                 
145                 tmp = mono_sgen_alloc_internal_dynamic (
146                         toogleref_array_capacity * sizeof (MonoGCToggleRef),
147                         INTERNAL_MEM_TOGGLEREF_DATA);
148
149                 memcpy (tmp, toggleref_array, toogleref_array_size * sizeof (MonoGCToggleRef));
150
151                 mono_sgen_free_internal_dynamic (toggleref_array, old_capacity * sizeof (MonoGCToggleRef), INTERNAL_MEM_TOGGLEREF_DATA);
152                 toggleref_array = tmp;
153         }
154 }
155
156 /**
157  * mono_gc_toggleref_add:
158  * @object object to register for toggleref processing
159  * @strong_ref if true the object is registered with a strong ref, a weak one otherwise
160  *
161  * Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
162  * on it until it returns MONO_TOGGLE_REF_DROP or is collected.
163 */
164 void
165 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
166 {
167         if (!toggleref_callback)
168                 return;
169
170         DEBUG (4, fprintf (gc_debug_file, "Adding toggleref %p %d\n", object, strong_ref));
171
172         mono_sgen_gc_lock ();
173
174         ensure_toggleref_capacity (1);
175         if (strong_ref)
176                 toggleref_array [toogleref_array_size++].strong_ref = object;
177         else
178                 toggleref_array [toogleref_array_size++].weak_ref = object;
179
180         mono_sgen_gc_unlock ();
181 }
182
183 /**
184  * mono_gc_toggleref_register_callback:
185  * @callback callback used to determine the new state of the given object.
186  *
187  * The callback must decide the status of a given object. It must return one of the values in the MONO_TOGGLE_REF_ enum.
188  * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
189  * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
190  *gchandles, storing to reference fields or interacting with other threads that might perform such operations.
191  */
192 void
193 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
194 {
195         toggleref_callback = proccess_toggleref;
196 }
197
198 #endif