Branch data Line data Source code
1 : : /* grcbox.c: Reference counted data
2 : : *
3 : : * Copyright 2018 Emmanuele Bassi
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General Public
18 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include "config.h"
22 : :
23 : : #include "grcboxprivate.h"
24 : :
25 : : #include "gmessages.h"
26 : : #include "grefcount.h"
27 : : #include "gtestutils.h"
28 : :
29 : : #ifdef ENABLE_VALGRIND
30 : : #include "valgrind.h"
31 : : #endif
32 : :
33 : : #include "glib_trace.h"
34 : :
35 : : #include <string.h>
36 : :
37 : : /* We use the same alignment as GTypeInstance and GNU libc's malloc */
38 : : #define ALIGN_STRUCT(offset) ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)
39 : :
40 : : #define G_RC_BOX(p) (GRcBox *) (((char *) (p)) - G_RC_BOX_SIZE)
41 : :
42 : : gpointer
43 : 788 : g_rc_box_alloc_full (gsize block_size,
44 : : gsize alignment,
45 : : gboolean atomic,
46 : : gboolean clear)
47 : : {
48 : : /* We don't do an (atomic ? G_ARC_BOX_SIZE : G_RC_BOX_SIZE) check, here
49 : : * because we have a static assertion that sizeof(GArcBox) == sizeof(GRcBox)
50 : : * inside grcboxprivate.h, and we don't want the compiler to unnecessarily
51 : : * warn about both branches of the conditional yielding identical results
52 : : */
53 : 788 : gsize private_size = G_ARC_BOX_SIZE;
54 : 788 : gsize private_offset = 0;
55 : : gsize real_size;
56 : : char *allocated;
57 : :
58 : 788 : g_assert (alignment != 0);
59 : :
60 : : /* We need to ensure that the private data is aligned */
61 : 788 : if (private_size % alignment != 0)
62 : : {
63 : 0 : private_offset = private_size % alignment;
64 : 0 : private_size += (alignment - private_offset);
65 : : }
66 : :
67 : 788 : g_assert (block_size < (G_MAXSIZE - private_size));
68 : 788 : real_size = private_size + block_size;
69 : :
70 : : /* The real allocated size must be a multiple of @alignment, to
71 : : * maintain the alignment of block_size
72 : : */
73 : 788 : if (real_size % alignment != 0)
74 : : {
75 : 302 : gsize offset = real_size % alignment;
76 : 302 : g_assert (real_size < (G_MAXSIZE - (alignment - offset)));
77 : 302 : real_size += (alignment - offset);
78 : : }
79 : :
80 : : #ifdef ENABLE_VALGRIND
81 : : if (RUNNING_ON_VALGRIND)
82 : : {
83 : : /* When running under Valgrind we massage the memory allocation
84 : : * to include a pointer at the tail end of the block; the pointer
85 : : * is then set to the start of the block. This trick allows
86 : : * Valgrind to keep track of the over-allocation and not be
87 : : * confused when passing the pointer around
88 : : */
89 : : g_assert (private_size < (G_MAXSIZE - ALIGN_STRUCT (1)));
90 : : private_size += ALIGN_STRUCT (1);
91 : :
92 : : if (clear)
93 : : allocated = g_malloc0 (real_size + sizeof (gpointer));
94 : : else
95 : : allocated = g_malloc (real_size + sizeof (gpointer));
96 : :
97 : : *(gpointer *) (allocated + private_size + block_size) = allocated + ALIGN_STRUCT (1);
98 : :
99 : : VALGRIND_MALLOCLIKE_BLOCK (allocated + private_size, block_size + sizeof (gpointer), 0, TRUE);
100 : : VALGRIND_MALLOCLIKE_BLOCK (allocated + ALIGN_STRUCT (1), private_size - ALIGN_STRUCT (1), 0, TRUE);
101 : : }
102 : : else
103 : : #endif /* ENABLE_VALGRIND */
104 : : {
105 : 788 : if (clear)
106 : 780 : allocated = g_malloc0 (real_size);
107 : : else
108 : 8 : allocated = g_malloc (real_size);
109 : : }
110 : :
111 : 788 : if (atomic)
112 : : {
113 : : /* We leave the alignment padding at the top of the allocation,
114 : : * so we have an in memory layout of:
115 : : *
116 : : * |[ offset ][ sizeof(GArcBox) ]||[ block_size ]|
117 : : */
118 : 771 : GArcBox *real_box = (GArcBox *) (allocated + private_offset);
119 : : /* Store the real size */
120 : 771 : real_box->mem_size = block_size;
121 : : /* Store the alignment offset, to be used when freeing the
122 : : * allocated block
123 : : */
124 : 771 : real_box->private_offset = private_offset;
125 : : #ifndef G_DISABLE_ASSERT
126 : 771 : real_box->magic = G_BOX_MAGIC;
127 : : #endif
128 : 771 : g_atomic_ref_count_init (&real_box->ref_count);
129 : : }
130 : : else
131 : : {
132 : : /* We leave the alignment padding at the top of the allocation,
133 : : * so we have an in memory layout of:
134 : : *
135 : : * |[ offset ][ sizeof(GRcBox) ]||[ block_size ]|
136 : : */
137 : 17 : GRcBox *real_box = (GRcBox *) (allocated + private_offset);
138 : : /* Store the real size */
139 : 17 : real_box->mem_size = block_size;
140 : : /* Store the alignment offset, to be used when freeing the
141 : : * allocated block
142 : : */
143 : 17 : real_box->private_offset = private_offset;
144 : : #ifndef G_DISABLE_ASSERT
145 : 17 : real_box->magic = G_BOX_MAGIC;
146 : : #endif
147 : 17 : g_ref_count_init (&real_box->ref_count);
148 : : }
149 : :
150 : 788 : TRACE (GLIB_RCBOX_ALLOC (allocated, block_size, atomic, clear));
151 : :
152 : 788 : return allocated + private_size;
153 : : }
154 : :
155 : : /**
156 : : * g_rc_box_alloc:
157 : : * @block_size: the size of the allocation, must be greater than 0
158 : : *
159 : : * Allocates @block_size bytes of memory, and adds reference
160 : : * counting semantics to it.
161 : : *
162 : : * The data will be freed when its reference count drops to
163 : : * zero.
164 : : *
165 : : * The allocated data is guaranteed to be suitably aligned for any
166 : : * built-in type.
167 : : *
168 : : * Returns: (transfer full) (not nullable): a pointer to the allocated memory
169 : : *
170 : : * Since: 2.58
171 : : */
172 : : gpointer
173 : 3 : g_rc_box_alloc (gsize block_size)
174 : : {
175 : 3 : g_return_val_if_fail (block_size > 0, NULL);
176 : :
177 : 3 : return g_rc_box_alloc_full (block_size, STRUCT_ALIGNMENT, FALSE, FALSE);
178 : : }
179 : :
180 : : /**
181 : : * g_rc_box_alloc0:
182 : : * @block_size: the size of the allocation, must be greater than 0
183 : : *
184 : : * Allocates @block_size bytes of memory, and adds reference
185 : : * counting semantics to it.
186 : : *
187 : : * The contents of the returned data is set to zero.
188 : : *
189 : : * The data will be freed when its reference count drops to
190 : : * zero.
191 : : *
192 : : * The allocated data is guaranteed to be suitably aligned for any
193 : : * built-in type.
194 : : *
195 : : * Returns: (transfer full) (not nullable): a pointer to the allocated memory
196 : : *
197 : : * Since: 2.58
198 : : */
199 : : gpointer
200 : 13 : g_rc_box_alloc0 (gsize block_size)
201 : : {
202 : 13 : g_return_val_if_fail (block_size > 0, NULL);
203 : :
204 : 13 : return g_rc_box_alloc_full (block_size, STRUCT_ALIGNMENT, FALSE, TRUE);
205 : : }
206 : :
207 : : /**
208 : : * g_rc_box_new:
209 : : * @type: the type to allocate, typically a structure name
210 : : *
211 : : * A convenience macro to allocate reference counted data with
212 : : * the size of the given @type.
213 : : *
214 : : * This macro calls g_rc_box_alloc() with `sizeof (@type)` and
215 : : * casts the returned pointer to a pointer of the given @type,
216 : : * avoiding a type cast in the source code.
217 : : *
218 : : * Returns: (transfer full) (not nullable): a pointer to the
219 : : * allocated memory, cast to a pointer for the given @type
220 : : *
221 : : * Since: 2.58
222 : : */
223 : :
224 : : /**
225 : : * g_rc_box_new0:
226 : : * @type: the type to allocate, typically a structure name
227 : : *
228 : : * A convenience macro to allocate reference counted data with
229 : : * the size of the given @type, and set its contents to zero.
230 : : *
231 : : * This macro calls g_rc_box_alloc0() with `sizeof (@type)` and
232 : : * casts the returned pointer to a pointer of the given @type,
233 : : * avoiding a type cast in the source code.
234 : : *
235 : : * Returns: (transfer full) (not nullable): a pointer to the
236 : : * allocated memory, cast to a pointer for the given @type
237 : : *
238 : : * Since: 2.58
239 : : */
240 : :
241 : : /**
242 : : * g_rc_box_dup:
243 : : * @block_size: the number of bytes to copy, must be greater than 0
244 : : * @mem_block: (not nullable): the memory to copy
245 : : *
246 : : * Allocates a new block of data with reference counting
247 : : * semantics, and copies @block_size bytes of @mem_block
248 : : * into it.
249 : : *
250 : : * Returns: (transfer full) (not nullable): a pointer to the allocated
251 : : * memory
252 : : *
253 : : * Since: 2.58
254 : : */
255 : : gpointer
256 : 1 : (g_rc_box_dup) (gsize block_size,
257 : : gconstpointer mem_block)
258 : : {
259 : : gpointer res;
260 : :
261 : 1 : g_return_val_if_fail (block_size > 0, NULL);
262 : 1 : g_return_val_if_fail (mem_block != NULL, NULL);
263 : :
264 : 1 : res = g_rc_box_alloc_full (block_size, STRUCT_ALIGNMENT, FALSE, FALSE);
265 : 1 : memcpy (res, mem_block, block_size);
266 : :
267 : 1 : return res;
268 : : }
269 : :
270 : : /**
271 : : * g_rc_box_acquire:
272 : : * @mem_block: (not nullable): a pointer to reference counted data
273 : : *
274 : : * Acquires a reference on the data pointed by @mem_block.
275 : : *
276 : : * Returns: (transfer full) (not nullable): a pointer to the data,
277 : : * with its reference count increased
278 : : *
279 : : * Since: 2.58
280 : : */
281 : : gpointer
282 : 9 : (g_rc_box_acquire) (gpointer mem_block)
283 : : {
284 : 9 : GRcBox *real_box = G_RC_BOX (mem_block);
285 : :
286 : 9 : g_return_val_if_fail (mem_block != NULL, NULL);
287 : : #ifndef G_DISABLE_ASSERT
288 : 9 : g_return_val_if_fail (real_box->magic == G_BOX_MAGIC, NULL);
289 : : #endif
290 : :
291 : 9 : g_ref_count_inc (&real_box->ref_count);
292 : :
293 : 9 : TRACE (GLIB_RCBOX_ACQUIRE (mem_block, 0));
294 : :
295 : 9 : return mem_block;
296 : : }
297 : :
298 : : /**
299 : : * g_rc_box_release:
300 : : * @mem_block: (transfer full) (not nullable): a pointer to reference counted data
301 : : *
302 : : * Releases a reference on the data pointed by @mem_block.
303 : : *
304 : : * If the reference was the last one, it will free the
305 : : * resources allocated for @mem_block.
306 : : *
307 : : * Since: 2.58
308 : : */
309 : : void
310 : 22 : g_rc_box_release (gpointer mem_block)
311 : : {
312 : 22 : g_rc_box_release_full (mem_block, NULL);
313 : 22 : }
314 : :
315 : : /**
316 : : * g_rc_box_release_full:
317 : : * @mem_block: (transfer full) (not nullable): a pointer to reference counted data
318 : : * @clear_func: (not nullable): a function to call when clearing the data
319 : : *
320 : : * Releases a reference on the data pointed by @mem_block.
321 : : *
322 : : * If the reference was the last one, it will call @clear_func
323 : : * to clear the contents of @mem_block, and then will free the
324 : : * resources allocated for @mem_block.
325 : : *
326 : : * Since: 2.58
327 : : */
328 : : void
329 : 26 : g_rc_box_release_full (gpointer mem_block,
330 : : GDestroyNotify clear_func)
331 : : {
332 : 26 : GRcBox *real_box = G_RC_BOX (mem_block);
333 : :
334 : 26 : g_return_if_fail (mem_block != NULL);
335 : : #ifndef G_DISABLE_ASSERT
336 : 26 : g_return_if_fail (real_box->magic == G_BOX_MAGIC);
337 : : #endif
338 : :
339 : 26 : if (g_ref_count_dec (&real_box->ref_count))
340 : : {
341 : 17 : char *real_mem = (char *) real_box - real_box->private_offset;
342 : :
343 : 17 : TRACE (GLIB_RCBOX_RELEASE (mem_block, 0));
344 : :
345 : 17 : if (clear_func != NULL)
346 : 3 : clear_func (mem_block);
347 : :
348 : 17 : TRACE (GLIB_RCBOX_FREE (mem_block));
349 : 17 : g_free (real_mem);
350 : : }
351 : : }
352 : :
353 : : /**
354 : : * g_rc_box_get_size:
355 : : * @mem_block: (not nullable): a pointer to reference counted data
356 : : *
357 : : * Retrieves the size of the reference counted data pointed by @mem_block.
358 : : *
359 : : * Returns: the size of the data, in bytes
360 : : *
361 : : * Since: 2.58
362 : : */
363 : : gsize
364 : 1 : g_rc_box_get_size (gpointer mem_block)
365 : : {
366 : 1 : GRcBox *real_box = G_RC_BOX (mem_block);
367 : :
368 : 1 : g_return_val_if_fail (mem_block != NULL, 0);
369 : : #ifndef G_DISABLE_ASSERT
370 : 1 : g_return_val_if_fail (real_box->magic == G_BOX_MAGIC, 0);
371 : : #endif
372 : :
373 : 1 : return real_box->mem_size;
374 : : }
|