1 /* grefcount.c: Reference counting
3 * Copyright 2018 Emmanuele Bassi
5 * SPDX-License-Identifier: LGPL-2.1-or-later
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.
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.
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/>.
23 * @Title: Reference counting
24 * @Short_description: Reference counting types and functions
26 * Reference counting is a garbage collection mechanism that is based on
27 * assigning a counter to a data type, or any memory area; the counter is
28 * increased whenever a new reference to that data type is acquired, and
29 * decreased whenever the reference is released. Once the last reference
30 * is released, the resources associated to that data type are freed.
32 * GLib uses reference counting in many of its data types, and provides
33 * the #grefcount and #gatomicrefcount types to implement safe and atomic
34 * reference counting semantics in new data types.
36 * It is important to note that #grefcount and #gatomicrefcount should be
37 * considered completely opaque types; you should always use the provided
38 * API to increase and decrease the counters, and you should never check
39 * their content directly, or compare their content with other values.
46 #include "grefcount.h"
49 #include "gmessages.h"
54 * A type for implementing non-atomic reference count semantics.
56 * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
57 * increase the counter, and g_ref_count_dec() to decrease it.
59 * It is safe to use #grefcount only if you're expecting to operate
60 * on the reference counter from a single thread. It is entirely up
61 * to you to ensure that all reference count changes happen in the
64 * See also: #gatomicrefcount
72 * A type for implementing atomic reference count semantics.
74 * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
75 * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
77 * It is safe to use #gatomicrefcount if you're expecting to operate on the
78 * reference counter from multiple threads.
80 * See also: #grefcount
87 * @rc: the address of a reference count variable
89 * Initializes a reference count variable to 1.
94 (g_ref_count_init) (grefcount *rc)
96 g_return_if_fail (rc != NULL);
98 /* Non-atomic refcounting is implemented using the negative range
101 * G_MININT Z¯< 0 > Z⁺ G_MAXINT
102 * |----------------------------|----------------------------|
104 * Acquiring a reference moves us towards MININT, and releasing a
105 * reference moves us towards 0.
112 * @rc: the address of a reference count variable
114 * Increases the reference count.
119 (g_ref_count_inc) (grefcount *rc)
123 g_return_if_fail (rc != NULL);
127 g_return_if_fail (rrc < 0);
129 /* Check for saturation */
132 g_critical ("Reference count %p has reached saturation", rc);
143 * @rc: the address of a reference count variable
145 * Decreases the reference count.
147 * If %TRUE is returned, the reference count reached 0. After this point, @rc
148 * is an undefined state and must be reinitialized with
149 * g_ref_count_init() to be used again.
151 * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
156 (g_ref_count_dec) (grefcount *rc)
160 g_return_val_if_fail (rc != NULL, FALSE);
164 g_return_val_if_fail (rrc < 0, FALSE);
176 * g_ref_count_compare:
177 * @rc: the address of a reference count variable
178 * @val: the value to compare
180 * Compares the current value of @rc with @val.
182 * Returns: %TRUE if the reference count is the same
188 (g_ref_count_compare) (grefcount *rc,
193 g_return_val_if_fail (rc != NULL, FALSE);
194 g_return_val_if_fail (val >= 0, FALSE);
199 return rrc == G_MININT;
205 * g_atomic_ref_count_init:
206 * @arc: the address of an atomic reference count variable
208 * Initializes a reference count variable to 1.
213 (g_atomic_ref_count_init) (gatomicrefcount *arc)
215 g_return_if_fail (arc != NULL);
217 /* Atomic refcounting is implemented using the positive range
218 * of signed integers:
220 * G_MININT Z¯< 0 > Z⁺ G_MAXINT
221 * |----------------------------|----------------------------|
223 * Acquiring a reference moves us towards MAXINT, and releasing a
224 * reference moves us towards 0.
230 * g_atomic_ref_count_inc:
231 * @arc: the address of an atomic reference count variable
233 * Atomically increases the reference count.
238 (g_atomic_ref_count_inc) (gatomicrefcount *arc)
242 g_return_if_fail (arc != NULL);
243 old_value = g_atomic_int_add (arc, 1);
244 g_return_if_fail (old_value > 0);
246 if (old_value == G_MAXINT)
247 g_critical ("Reference count has reached saturation");
251 * g_atomic_ref_count_dec:
252 * @arc: the address of an atomic reference count variable
254 * Atomically decreases the reference count.
256 * If %TRUE is returned, the reference count reached 0. After this point, @arc
257 * is an undefined state and must be reinitialized with
258 * g_atomic_ref_count_init() to be used again.
260 * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
265 (g_atomic_ref_count_dec) (gatomicrefcount *arc)
269 g_return_val_if_fail (arc != NULL, FALSE);
270 old_value = g_atomic_int_add (arc, -1);
271 g_return_val_if_fail (old_value > 0, FALSE);
273 return old_value == 1;
277 * g_atomic_ref_count_compare:
278 * @arc: the address of an atomic reference count variable
279 * @val: the value to compare
281 * Atomically compares the current value of @arc with @val.
283 * Returns: %TRUE if the reference count is the same
289 (g_atomic_ref_count_compare) (gatomicrefcount *arc,
292 g_return_val_if_fail (arc != NULL, FALSE);
293 g_return_val_if_fail (val >= 0, FALSE);
295 return g_atomic_int_get (arc) == val;