1 /* garcbox.c: Atomically reference counted data
3 * Copyright 2018 Emmanuele Bassi
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 #include "gmessages.h"
24 #include "grcboxprivate.h"
25 #include "grefcount.h"
27 #ifdef ENABLE_VALGRIND
33 #define G_ARC_BOX(p) (GArcBox *) (((char *) (p)) - G_ARC_BOX_SIZE)
37 * @Title: Atomically reference counted data
38 * @Short_description: Allocated memory with atomic reference counting semantics
40 * An "atomically reference counted box", or "ArcBox", is an opaque wrapper
41 * data type that is guaranteed to be as big as the size of a given data type,
42 * and which augments the given data type with thread safe reference counting
43 * semantics for its memory management.
45 * ArcBox is useful if you have a plain old data type, like a structure
46 * typically placed on the stack, and you wish to provide additional API
47 * to use it on the heap, without necessarily implementing copy/free
48 * semantics, or your own reference counting.
52 * |[<!-- language="C" -->
58 * point_new (float x, float y)
60 * Point *res = g_arc_box_new (Point);
69 * Every time you wish to acquire a reference on the memory, you should
70 * call g_arc_box_acquire(); similarly, when you wish to release a reference
71 * you should call g_arc_box_release():
73 * |[<!-- language="C" -->
75 * point_ref (Point *p)
77 * return g_arc_box_acquire (p);
81 * point_unref (Point *p)
83 * g_arc_box_release (p);
87 * If you have additional memory allocated inside the structure, you can
88 * use g_arc_box_release_full(), which takes a function pointer, which
89 * will be called if the reference released was the last:
91 * |[<!-- language="C" -->
101 * person_clear (Person *p)
104 * g_free (p->address);
110 * person_unref (Person *p)
112 * g_arc_box_release_full (p, (GDestroyNotify) person_clear);
116 * If you wish to transfer the ownership of a reference counted data
117 * type without increasing the reference count, you can use g_steal_pointer():
119 * |[<!-- language="C" -->
120 * Person *p = g_arc_box_new (Person);
122 * fill_person_details (p);
124 * add_person_to_database (db, g_steal_pointer (&p));
127 * The reference counting operations on data allocated using g_arc_box_alloc(),
128 * g_arc_box_new(), and g_arc_box_dup() are guaranteed to be atomic, and thus
129 * can be safely be performed by different threads. It is important to note that
130 * only the reference acquisition and release are atomic; changes to the content
131 * of the data are your responsibility.
138 * @block_size: the size of the allocation
140 * Allocates @block_size bytes of memory, and adds atomic
141 * reference counting semantics to it.
143 * The data will be freed when its reference count drops to
146 * Returns: a pointer to the allocated memory
151 g_arc_box_alloc (gsize block_size
)
153 g_return_val_if_fail (block_size
> 0, NULL
);
155 return g_rc_box_alloc_full (block_size
, TRUE
, FALSE
);
160 * @block_size: the size of the allocation
162 * Allocates @block_size bytes of memory, and adds atomic
163 * referenc counting semantics to it.
165 * The contents of the returned data is set to 0's.
167 * The data will be freed when its reference count drops to
170 * Returns: a pointer to the allocated memory
175 g_arc_box_alloc0 (gsize block_size
)
177 g_return_val_if_fail (block_size
> 0, NULL
);
179 return g_rc_box_alloc_full (block_size
, TRUE
, TRUE
);
184 * @type: the type to allocate, typically a structure name
186 * A convenience macro to allocate atomically reference counted
187 * data with the size of the given @type.
189 * This macro calls g_arc_box_alloc() with `sizeof (@type)` and
190 * casts the returned pointer to a pointer of the given @type,
191 * avoiding a type cast in the source code.
193 * This macro cannot return %NULL, as the minimum allocation
194 * size from `sizeof (@type)` is 1 byte.
196 * Returns: (not nullable): a pointer to the allocated memory,
197 * cast to a pointer for the given @type
204 * @type: the type to allocate, typically a structure name
206 * A convenience macro to allocate atomically reference counted
207 * data with the size of the given @type, and set its contents
210 * This macro calls g_arc_box_alloc0() with `sizeof (@type)` and
211 * casts the returned pointer to a pointer of the given @type,
212 * avoiding a type cast in the source code.
214 * This macro cannot return %NULL, as the minimum allocation
215 * size from `sizeof (@type)` is 1 byte.
217 * Returns: (not nullable): a pointer to the allocated memory,
218 * cast to a pointer for the given @type
225 * @block_size: the number of bytes to copy
226 * @mem_block: (not nullable): the memory to copy
228 * Allocates a new block of data with atomit reference counting
229 * semantics, and copies @block_size bytes of @mem_block
232 * Returns: (not nullable): a pointer to the allocated memory
237 (g_arc_box_dup
) (gsize block_size
,
238 gconstpointer mem_block
)
242 g_return_val_if_fail (block_size
> 0, NULL
);
243 g_return_val_if_fail (mem_block
!= NULL
, NULL
);
245 res
= g_rc_box_alloc_full (block_size
, TRUE
, FALSE
);
246 memcpy (res
, mem_block
, block_size
);
253 * @mem_block: (not nullable): a pointer to reference counted data
255 * Atomically acquires a reference on the data pointed by @mem_block.
257 * Returns: (not nullabl): a pointer to the data, with its reference
263 (g_arc_box_acquire
) (gpointer mem_block
)
265 GArcBox
*real_box
= G_ARC_BOX (mem_block
);
267 g_return_val_if_fail (mem_block
!= NULL
, NULL
);
268 #ifndef G_DISABLE_ASSERT
269 g_return_val_if_fail (real_box
->magic
== G_BOX_MAGIC
, NULL
);
272 g_atomic_ref_count_inc (&real_box
->ref_count
);
279 * @mem_block: (not nullable): a pointer to reference counted data
281 * Atomically releases a reference on the data pointed by @mem_block.
283 * If the reference was the last one, it will free the
284 * resources allocated for @mem_block.
289 g_arc_box_release (gpointer mem_block
)
291 GArcBox
*real_box
= G_ARC_BOX (mem_block
);
293 g_return_if_fail (mem_block
!= NULL
);
294 #ifndef G_DISABLE_ASSERT
295 g_return_if_fail (real_box
->magic
== G_BOX_MAGIC
);
298 if (g_atomic_ref_count_dec (&real_box
->ref_count
))
303 * g_arc_box_release_full:
304 * @mem_block: (not nullable): a pointer to reference counted data
305 * @clear_func: (not nullable): a function to call when clearing the data
307 * Atomically releases a reference on the data pointed by @mem_block.
309 * If the reference was the last one, it will call @clear_func
310 * to clear the contents of @mem_block, and then will free the
311 * resources allocated for @mem_block.
316 g_arc_box_release_full (gpointer mem_block
,
317 GDestroyNotify clear_func
)
319 GArcBox
*real_box
= G_ARC_BOX (mem_block
);
321 g_return_if_fail (mem_block
!= NULL
);
322 g_return_if_fail (clear_func
!= NULL
);
323 #ifndef G_DISABLE_ASSERT
324 g_return_if_fail (real_box
->magic
== G_BOX_MAGIC
);
327 if (g_atomic_ref_count_dec (&real_box
->ref_count
))
329 clear_func (mem_block
);