• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* grefcount.c: Reference counting
2  *
3  * Copyright 2018  Emmanuele Bassi
4  *
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.
9  *
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.
14  *
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/>.
17  */
18 
19 /**
20  * SECTION:refcount
21  * @Title: Reference counting
22  * @Short_description: Reference counting types and functions
23  *
24  * Reference counting is a garbage collection mechanism that is based on
25  * assigning a counter to a data type, or any memory area; the counter is
26  * increased whenever a new reference to that data type is acquired, and
27  * decreased whenever the reference is released. Once the last reference
28  * is released, the resources associated to that data type are freed.
29  *
30  * GLib uses reference counting in many of its data types, and provides
31  * the #grefcount and #gatomicrefcount types to implement safe and atomic
32  * reference counting semantics in new data types.
33  *
34  * It is important to note that #grefcount and #gatomicrefcount should be
35  * considered completely opaque types; you should always use the provided
36  * API to increase and decrease the counters, and you should never check
37  * their content directly, or compare their content with other values.
38  *
39  * Since: 2.58
40  */
41 
42 #include "config.h"
43 
44 #include "grefcount.h"
45 
46 #include "gatomic.h"
47 #include "gmessages.h"
48 
49 /**
50  * grefcount:
51  *
52  * A type for implementing non-atomic reference count semantics.
53  *
54  * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
55  * increase the counter, and g_ref_count_dec() to decrease it.
56  *
57  * It is safe to use #grefcount only if you're expecting to operate
58  * on the reference counter from a single thread. It is entirely up
59  * to you to ensure that all reference count changes happen in the
60  * same thread.
61  *
62  * See also: #gatomicrefcount
63  *
64  * Since: 2.58
65  */
66 
67 /**
68  * gatomicrefcount:
69  *
70  * A type for implementing atomic reference count semantics.
71  *
72  * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
73  * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
74  *
75  * It is safe to use #gatomicrefcount if you're expecting to operate on the
76  * reference counter from multiple threads.
77  *
78  * See also: #grefcount
79  *
80  * Since: 2.58
81  */
82 
83 /**
84  * g_ref_count_init:
85  * @rc: the address of a reference count variable
86  *
87  * Initializes a reference count variable.
88  *
89  * Since: 2.58
90  */
91 void
92 (g_ref_count_init) (grefcount *rc)
93 {
94   g_return_if_fail (rc != NULL);
95 
96   /* Non-atomic refcounting is implemented using the negative range
97    * of signed integers:
98    *
99    * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
100    * |----------------------------|----------------------------|
101    *
102    * Acquiring a reference moves us towards MININT, and releasing a
103    * reference moves us towards 0.
104    */
105   *rc = -1;
106 }
107 
108 /**
109  * g_ref_count_inc:
110  * @rc: the address of a reference count variable
111  *
112  * Increases the reference count.
113  *
114  * Since: 2.58
115  */
116 void
117 (g_ref_count_inc) (grefcount *rc)
118 {
119   grefcount rrc;
120 
121   g_return_if_fail (rc != NULL);
122 
123   rrc = *rc;
124 
125   g_return_if_fail (rrc < 0);
126 
127   /* Check for saturation */
128   if (rrc == G_MININT)
129     {
130       g_critical ("Reference count %p has reached saturation", rc);
131       return;
132     }
133 
134   rrc -= 1;
135 
136   *rc = rrc;
137 }
138 
139 /**
140  * g_ref_count_dec:
141  * @rc: the address of a reference count variable
142  *
143  * Decreases the reference count.
144  *
145  * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
146  *
147  * Since: 2.58
148  */
gboolean(g_ref_count_dec)149 gboolean
150 (g_ref_count_dec) (grefcount *rc)
151 {
152   grefcount rrc;
153 
154   g_return_val_if_fail (rc != NULL, FALSE);
155 
156   rrc = *rc;
157 
158   g_return_val_if_fail (rrc < 0, FALSE);
159 
160   rrc += 1;
161   if (rrc == 0)
162     return TRUE;
163 
164   *rc = rrc;
165 
166   return FALSE;
167 }
168 
169 /**
170  * g_ref_count_compare:
171  * @rc: the address of a reference count variable
172  * @val: the value to compare
173  *
174  * Compares the current value of @rc with @val.
175  *
176  * Returns: %TRUE if the reference count is the same
177  *   as the given value
178  *
179  * Since: 2.58
180  */
gboolean(g_ref_count_compare)181 gboolean
182 (g_ref_count_compare) (grefcount *rc,
183                        gint       val)
184 {
185   grefcount rrc;
186 
187   g_return_val_if_fail (rc != NULL, FALSE);
188   g_return_val_if_fail (val >= 0, FALSE);
189 
190   rrc = *rc;
191 
192   if (val == G_MAXINT)
193     return rrc == G_MININT;
194 
195   return rrc == -val;
196 }
197 
198 /**
199  * g_atomic_ref_count_init:
200  * @arc: the address of an atomic reference count variable
201  *
202  * Initializes a reference count variable.
203  *
204  * Since: 2.58
205  */
206 void
207 (g_atomic_ref_count_init) (gatomicrefcount *arc)
208 {
209   g_return_if_fail (arc != NULL);
210 
211   /* Atomic refcounting is implemented using the positive range
212    * of signed integers:
213    *
214    * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
215    * |----------------------------|----------------------------|
216    *
217    * Acquiring a reference moves us towards MAXINT, and releasing a
218    * reference moves us towards 0.
219    */
220   *arc = 1;
221 }
222 
223 /**
224  * g_atomic_ref_count_inc:
225  * @arc: the address of an atomic reference count variable
226  *
227  * Atomically increases the reference count.
228  *
229  * Since: 2.58
230  */
231 void
232 (g_atomic_ref_count_inc) (gatomicrefcount *arc)
233 {
234   g_return_if_fail (arc != NULL);
235   g_return_if_fail (g_atomic_int_get (arc) > 0);
236 
237   if (g_atomic_int_get (arc) == G_MAXINT)
238     {
239       g_critical ("Reference count has reached saturation");
240       return;
241     }
242 
243   g_atomic_int_inc (arc);
244 }
245 
246 /**
247  * g_atomic_ref_count_dec:
248  * @arc: the address of an atomic reference count variable
249  *
250  * Atomically decreases the reference count.
251  *
252  * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
253  *
254  * Since: 2.58
255  */
gboolean(g_atomic_ref_count_dec)256 gboolean
257 (g_atomic_ref_count_dec) (gatomicrefcount *arc)
258 {
259   g_return_val_if_fail (arc != NULL, FALSE);
260   g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
261 
262   return g_atomic_int_dec_and_test (arc);
263 }
264 
265 /**
266  * g_atomic_ref_count_compare:
267  * @arc: the address of an atomic reference count variable
268  * @val: the value to compare
269  *
270  * Atomically compares the current value of @arc with @val.
271  *
272  * Returns: %TRUE if the reference count is the same
273  *   as the given value
274  *
275  * Since: 2.58
276  */
gboolean(g_atomic_ref_count_compare)277 gboolean
278 (g_atomic_ref_count_compare) (gatomicrefcount *arc,
279                               gint             val)
280 {
281   g_return_val_if_fail (arc != NULL, FALSE);
282   g_return_val_if_fail (val >= 0, FALSE);
283 
284   return g_atomic_int_get (arc) == val;
285 }
286