[dtrace] GC heap allocation probes for SGen.
[mono.git] / mono / metadata / sgen-protocol.c
1 /*
2  * Copyright 2001-2003 Ximian, Inc
3  * Copyright 2003-2010 Novell, Inc.
4  * 
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  * 
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  * 
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include "config.h"
26 #include "sgen-protocol.h"
27
28 #ifdef SGEN_BINARY_PROTOCOL
29
30 /* If not null, dump binary protocol to this file */
31 static FILE *binary_protocol_file = NULL;
32
33 static int binary_protocol_use_count = 0;
34
35 #define BINARY_PROTOCOL_BUFFER_SIZE     (65536 - 2 * 8)
36
37 typedef struct _BinaryProtocolBuffer BinaryProtocolBuffer;
38 struct _BinaryProtocolBuffer {
39         BinaryProtocolBuffer *next;
40         int index;
41         unsigned char buffer [BINARY_PROTOCOL_BUFFER_SIZE];
42 };
43
44 static BinaryProtocolBuffer *binary_protocol_buffers = NULL;
45
46 void
47 binary_protocol_init (const char *filename)
48 {
49         binary_protocol_file = fopen (filename, "w");
50 }
51
52 gboolean
53 binary_protocol_is_enabled (void)
54 {
55         return binary_protocol_file != NULL;
56 }
57
58 static void
59 binary_protocol_flush_buffers_rec (BinaryProtocolBuffer *buffer)
60 {
61         if (!buffer)
62                 return;
63
64         binary_protocol_flush_buffers_rec (buffer->next);
65
66         g_assert (buffer->index > 0);
67         fwrite (buffer->buffer, 1, buffer->index, binary_protocol_file);
68
69         sgen_free_os_memory (buffer, sizeof (BinaryProtocolBuffer), FALSE);
70 }
71
72 void
73 binary_protocol_flush_buffers (gboolean force)
74 {
75         if (!binary_protocol_file)
76                 return;
77
78         if (!force && binary_protocol_use_count != 0)
79                 return;
80
81         binary_protocol_flush_buffers_rec (binary_protocol_buffers);
82         binary_protocol_buffers = NULL;
83
84         fflush (binary_protocol_file);
85 }
86
87 static BinaryProtocolBuffer*
88 binary_protocol_get_buffer (int length)
89 {
90         BinaryProtocolBuffer *buffer, *new_buffer;
91
92  retry:
93         buffer = binary_protocol_buffers;
94         if (buffer && buffer->index + length <= BINARY_PROTOCOL_BUFFER_SIZE)
95                 return buffer;
96
97         new_buffer = sgen_alloc_os_memory (sizeof (BinaryProtocolBuffer), TRUE, FALSE, "debugging memory");
98         new_buffer->next = buffer;
99         new_buffer->index = 0;
100
101         if (InterlockedCompareExchangePointer ((void**)&binary_protocol_buffers, new_buffer, buffer) != buffer) {
102                 sgen_free_os_memory (new_buffer, sizeof (BinaryProtocolBuffer), FALSE);
103                 goto retry;
104         }
105
106         return new_buffer;
107 }
108
109
110 static void
111 protocol_entry (unsigned char type, gpointer data, int size)
112 {
113         int index;
114         BinaryProtocolBuffer *buffer;
115         int old_count;
116
117         if (!binary_protocol_file)
118                 return;
119
120         do {
121                 old_count = binary_protocol_use_count;
122                 g_assert (old_count >= 0);
123         } while (InterlockedCompareExchange (&binary_protocol_use_count, old_count + 1, old_count) != old_count);
124
125  retry:
126         buffer = binary_protocol_get_buffer (size + 1);
127  retry_same_buffer:
128         index = buffer->index;
129         if (index + 1 + size > BINARY_PROTOCOL_BUFFER_SIZE)
130                 goto retry;
131
132         if (InterlockedCompareExchange (&buffer->index, index + 1 + size, index) != index)
133                 goto retry_same_buffer;
134
135         /* FIXME: if we're interrupted at this point, we have a buffer
136            entry that contains random data. */
137
138         buffer->buffer [index++] = type;
139         memcpy (buffer->buffer + index, data, size);
140         index += size;
141
142         g_assert (index <= BINARY_PROTOCOL_BUFFER_SIZE);
143
144         do {
145                 old_count = binary_protocol_use_count;
146                 g_assert (old_count > 0);
147         } while (InterlockedCompareExchange (&binary_protocol_use_count, old_count - 1, old_count) != old_count);
148 }
149
150 void
151 binary_protocol_collection (int generation)
152 {
153         SGenProtocolCollection entry = { generation };
154         binary_protocol_flush_buffers (FALSE);
155         protocol_entry (SGEN_PROTOCOL_COLLECTION, &entry, sizeof (SGenProtocolCollection));
156 }
157
158 void
159 binary_protocol_alloc (gpointer obj, gpointer vtable, int size)
160 {
161         SGenProtocolAlloc entry = { obj, vtable, size };
162         protocol_entry (SGEN_PROTOCOL_ALLOC, &entry, sizeof (SGenProtocolAlloc));
163 }
164
165 void
166 binary_protocol_alloc_pinned (gpointer obj, gpointer vtable, int size)
167 {
168         SGenProtocolAlloc entry = { obj, vtable, size };
169         protocol_entry (SGEN_PROTOCOL_ALLOC_PINNED, &entry, sizeof (SGenProtocolAlloc));
170 }
171
172 void
173 binary_protocol_alloc_degraded (gpointer obj, gpointer vtable, int size)
174 {
175         SGenProtocolAlloc entry = { obj, vtable, size };
176         protocol_entry (SGEN_PROTOCOL_ALLOC_DEGRADED, &entry, sizeof (SGenProtocolAlloc));
177 }
178
179 void
180 binary_protocol_copy (gpointer from, gpointer to, gpointer vtable, int size)
181 {
182         SGenProtocolCopy entry = { from, to, vtable, size };
183         protocol_entry (SGEN_PROTOCOL_COPY, &entry, sizeof (SGenProtocolCopy));
184 }
185
186 void
187 binary_protocol_pin (gpointer obj, gpointer vtable, int size)
188 {
189         SGenProtocolPin entry = { obj, vtable, size };
190         protocol_entry (SGEN_PROTOCOL_PIN, &entry, sizeof (SGenProtocolPin));
191 }
192
193 void
194 binary_protocol_mark (gpointer obj, gpointer vtable, int size)
195 {
196         SGenProtocolMark entry = { obj, vtable, size };
197         protocol_entry (SGEN_PROTOCOL_MARK, &entry, sizeof (SGenProtocolMark));
198 }
199
200 void
201 binary_protocol_wbarrier (gpointer ptr, gpointer value, gpointer value_vtable)
202 {
203         SGenProtocolWBarrier entry = { ptr, value, value_vtable };
204         protocol_entry (SGEN_PROTOCOL_WBARRIER, &entry, sizeof (SGenProtocolWBarrier));
205 }
206
207 void
208 binary_protocol_global_remset (gpointer ptr, gpointer value, gpointer value_vtable)
209 {
210         SGenProtocolGlobalRemset entry = { ptr, value, value_vtable };
211         protocol_entry (SGEN_PROTOCOL_GLOBAL_REMSET, &entry, sizeof (SGenProtocolGlobalRemset));
212 }
213
214 void
215 binary_protocol_ptr_update (gpointer ptr, gpointer old_value, gpointer new_value, gpointer vtable, int size)
216 {
217         SGenProtocolPtrUpdate entry = { ptr, old_value, new_value, vtable, size };
218         protocol_entry (SGEN_PROTOCOL_PTR_UPDATE, &entry, sizeof (SGenProtocolPtrUpdate));
219 }
220
221 void
222 binary_protocol_cleanup (gpointer ptr, gpointer vtable, int size)
223 {
224         SGenProtocolCleanup entry = { ptr, vtable, size };
225         protocol_entry (SGEN_PROTOCOL_CLEANUP, &entry, sizeof (SGenProtocolCleanup));
226 }
227
228 void
229 binary_protocol_empty (gpointer start, int size)
230 {
231         SGenProtocolEmpty entry = { start, size };
232         protocol_entry (SGEN_PROTOCOL_EMPTY, &entry, sizeof (SGenProtocolEmpty));
233 }
234
235 void
236 binary_protocol_thread_restart (gpointer thread)
237 {
238         SGenProtocolThreadRestart entry = { thread };
239         protocol_entry (SGEN_PROTOCOL_THREAD_RESTART, &entry, sizeof (SGenProtocolThreadRestart));
240
241 }
242
243 void
244 binary_protocol_thread_register (gpointer thread)
245 {
246         SGenProtocolThreadRegister entry = { thread };
247         protocol_entry (SGEN_PROTOCOL_THREAD_REGISTER, &entry, sizeof (SGenProtocolThreadRegister));
248
249 }
250
251 void
252 binary_protocol_thread_unregister (gpointer thread)
253 {
254         SGenProtocolThreadUnregister entry = { thread };
255         protocol_entry (SGEN_PROTOCOL_THREAD_UNREGISTER, &entry, sizeof (SGenProtocolThreadUnregister));
256
257 }
258
259 void
260 binary_protocol_missing_remset (gpointer obj, gpointer obj_vtable, int offset, gpointer value, gpointer value_vtable, int value_pinned)
261 {
262         SGenProtocolMissingRemset entry = { obj, obj_vtable, offset, value, value_vtable, value_pinned };
263         protocol_entry (SGEN_PROTOCOL_MISSING_REMSET, &entry, sizeof (SGenProtocolMissingRemset));
264
265 }
266
267 #endif