Branch data Line data Source code
1 : : /* grefcount.c: Reference counting
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 "grefcount.h"
24 : :
25 : : #include "gatomic.h"
26 : : #include "gmessages.h"
27 : :
28 : : /**
29 : : * grefcount:
30 : : *
31 : : * A type for implementing non-atomic reference count semantics.
32 : : *
33 : : * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
34 : : * increase the counter, and g_ref_count_dec() to decrease it.
35 : : *
36 : : * It is safe to use #grefcount only if you're expecting to operate
37 : : * on the reference counter from a single thread. It is entirely up
38 : : * to you to ensure that all reference count changes happen in the
39 : : * same thread.
40 : : *
41 : : * See also: #gatomicrefcount
42 : : *
43 : : * Since: 2.58
44 : : */
45 : :
46 : : /**
47 : : * gatomicrefcount:
48 : : *
49 : : * A type for implementing atomic reference count semantics.
50 : : *
51 : : * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
52 : : * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
53 : : *
54 : : * It is safe to use #gatomicrefcount if you're expecting to operate on the
55 : : * reference counter from multiple threads.
56 : : *
57 : : * See also: #grefcount
58 : : *
59 : : * Since: 2.58
60 : : */
61 : :
62 : : /**
63 : : * g_ref_count_init:
64 : : * @rc: the address of a reference count variable
65 : : *
66 : : * Initializes a reference count variable to 1.
67 : : *
68 : : * Since: 2.58
69 : : */
70 : : void
71 : 87 : (g_ref_count_init) (grefcount *rc)
72 : : {
73 : 87 : g_return_if_fail (rc != NULL);
74 : :
75 : : /* Non-atomic refcounting is implemented using the negative range
76 : : * of signed integers:
77 : : *
78 : : * G_MININT Z¯< 0 > Z⁺ G_MAXINT
79 : : * |----------------------------|----------------------------|
80 : : *
81 : : * Acquiring a reference moves us towards MININT, and releasing a
82 : : * reference moves us towards 0.
83 : : */
84 : 87 : *rc = -1;
85 : : }
86 : :
87 : : /**
88 : : * g_ref_count_inc:
89 : : * @rc: the address of a reference count variable
90 : : *
91 : : * Increases the reference count.
92 : : *
93 : : * Since: 2.58
94 : : */
95 : : void
96 : 65 : (g_ref_count_inc) (grefcount *rc)
97 : : {
98 : : grefcount rrc;
99 : :
100 : 65 : g_return_if_fail (rc != NULL);
101 : :
102 : 65 : rrc = *rc;
103 : :
104 : 65 : g_return_if_fail (rrc < 0);
105 : :
106 : : /* Check for saturation */
107 : 65 : if (rrc == G_MININT)
108 : : {
109 : 0 : g_critical ("Reference count %p has reached saturation", rc);
110 : 0 : return;
111 : : }
112 : :
113 : 65 : rrc -= 1;
114 : :
115 : 65 : *rc = rrc;
116 : : }
117 : :
118 : : /**
119 : : * g_ref_count_dec:
120 : : * @rc: the address of a reference count variable
121 : : *
122 : : * Decreases the reference count.
123 : : *
124 : : * If %TRUE is returned, the reference count reached 0. After this point, @rc
125 : : * is an undefined state and must be reinitialized with
126 : : * g_ref_count_init() to be used again.
127 : : *
128 : : * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
129 : : *
130 : : * Since: 2.58
131 : : */
132 : : gboolean
133 : 154 : (g_ref_count_dec) (grefcount *rc)
134 : : {
135 : : grefcount rrc;
136 : :
137 : 154 : g_return_val_if_fail (rc != NULL, FALSE);
138 : :
139 : 154 : rrc = *rc;
140 : :
141 : 154 : g_return_val_if_fail (rrc < 0, FALSE);
142 : :
143 : 154 : rrc += 1;
144 : 154 : if (rrc == 0)
145 : 88 : return TRUE;
146 : :
147 : 66 : *rc = rrc;
148 : :
149 : 66 : return FALSE;
150 : : }
151 : :
152 : : /**
153 : : * g_ref_count_compare:
154 : : * @rc: the address of a reference count variable
155 : : * @val: the value to compare
156 : : *
157 : : * Compares the current value of @rc with @val.
158 : : *
159 : : * Returns: %TRUE if the reference count is the same
160 : : * as the given value
161 : : *
162 : : * Since: 2.58
163 : : */
164 : : gboolean
165 : 3 : (g_ref_count_compare) (grefcount *rc,
166 : : gint val)
167 : : {
168 : : grefcount rrc;
169 : :
170 : 3 : g_return_val_if_fail (rc != NULL, FALSE);
171 : 3 : g_return_val_if_fail (val >= 0, FALSE);
172 : :
173 : 3 : rrc = *rc;
174 : :
175 : 3 : if (val == G_MAXINT)
176 : 1 : return rrc == G_MININT;
177 : :
178 : 2 : return rrc == -val;
179 : : }
180 : :
181 : : /**
182 : : * g_atomic_ref_count_init:
183 : : * @arc: the address of an atomic reference count variable
184 : : *
185 : : * Initializes a reference count variable to 1.
186 : : *
187 : : * Since: 2.58
188 : : */
189 : : void
190 : 9854851 : (g_atomic_ref_count_init) (gatomicrefcount *arc)
191 : : {
192 : 9854851 : g_return_if_fail (arc != NULL);
193 : :
194 : : /* Atomic refcounting is implemented using the positive range
195 : : * of signed integers:
196 : : *
197 : : * G_MININT Z¯< 0 > Z⁺ G_MAXINT
198 : : * |----------------------------|----------------------------|
199 : : *
200 : : * Acquiring a reference moves us towards MAXINT, and releasing a
201 : : * reference moves us towards 0.
202 : : */
203 : 9854851 : *arc = 1;
204 : : }
205 : :
206 : : /**
207 : : * g_atomic_ref_count_inc:
208 : : * @arc: the address of an atomic reference count variable
209 : : *
210 : : * Atomically increases the reference count.
211 : : *
212 : : * Since: 2.58
213 : : */
214 : : void
215 : 16763852 : (g_atomic_ref_count_inc) (gatomicrefcount *arc)
216 : : {
217 : : gint old_value;
218 : :
219 : 16763852 : g_return_if_fail (arc != NULL);
220 : 16763852 : old_value = g_atomic_int_add (arc, 1);
221 : 16763852 : g_return_if_fail (old_value > 0);
222 : :
223 : 16763852 : if (old_value == G_MAXINT)
224 : 0 : g_critical ("Reference count has reached saturation");
225 : : }
226 : :
227 : : /**
228 : : * g_atomic_ref_count_dec:
229 : : * @arc: the address of an atomic reference count variable
230 : : *
231 : : * Atomically decreases the reference count.
232 : : *
233 : : * If %TRUE is returned, the reference count reached 0. After this point, @arc
234 : : * is an undefined state and must be reinitialized with
235 : : * g_atomic_ref_count_init() to be used again.
236 : : *
237 : : * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
238 : : *
239 : : * Since: 2.58
240 : : */
241 : : gboolean
242 : 26537103 : (g_atomic_ref_count_dec) (gatomicrefcount *arc)
243 : : {
244 : : gint old_value;
245 : :
246 : 26537103 : g_return_val_if_fail (arc != NULL, FALSE);
247 : 26537103 : old_value = g_atomic_int_add (arc, -1);
248 : 26537103 : g_return_val_if_fail (old_value > 0, FALSE);
249 : :
250 : 26537103 : return old_value == 1;
251 : : }
252 : :
253 : : /**
254 : : * g_atomic_ref_count_compare:
255 : : * @arc: the address of an atomic reference count variable
256 : : * @val: the value to compare
257 : : *
258 : : * Atomically compares the current value of @arc with @val.
259 : : *
260 : : * Returns: %TRUE if the reference count is the same
261 : : * as the given value
262 : : *
263 : : * Since: 2.58
264 : : */
265 : : gboolean
266 : 57822725 : (g_atomic_ref_count_compare) (gatomicrefcount *arc,
267 : : gint val)
268 : : {
269 : 57822725 : g_return_val_if_fail (arc != NULL, FALSE);
270 : 57822725 : g_return_val_if_fail (val >= 0, FALSE);
271 : :
272 : 57822725 : return g_atomic_int_get (arc) == val;
273 : : }
|