Coverage Report

Created: 2025-10-13 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/glib/grefcount.c
Line
Count
Source
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
0
{
94
0
  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
0
  *rc = -1;
106
0
}
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
0
{
119
0
  grefcount rrc;
120
121
0
  g_return_if_fail (rc != NULL);
122
123
0
  rrc = *rc;
124
125
0
  g_return_if_fail (rrc < 0);
126
127
  /* Check for saturation */
128
0
  if (rrc == G_MININT)
129
0
    {
130
0
      g_critical ("Reference count %p has reached saturation", rc);
131
0
      return;
132
0
    }
133
134
0
  rrc -= 1;
135
136
0
  *rc = rrc;
137
0
}
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
 */
149
gboolean
150
(g_ref_count_dec) (grefcount *rc)
151
0
{
152
0
  grefcount rrc;
153
154
0
  g_return_val_if_fail (rc != NULL, FALSE);
155
156
0
  rrc = *rc;
157
158
0
  g_return_val_if_fail (rrc < 0, FALSE);
159
160
0
  rrc += 1;
161
0
  if (rrc == 0)
162
0
    return TRUE;
163
164
0
  *rc = rrc;
165
166
0
  return FALSE;
167
0
}
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
 */
181
gboolean
182
(g_ref_count_compare) (grefcount *rc,
183
                       gint       val)
184
0
{
185
0
  grefcount rrc;
186
187
0
  g_return_val_if_fail (rc != NULL, FALSE);
188
0
  g_return_val_if_fail (val >= 0, FALSE);
189
190
0
  rrc = *rc;
191
192
0
  if (val == G_MAXINT)
193
0
    return rrc == G_MININT;
194
195
0
  return rrc == -val;
196
0
}
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
101M
{
209
101M
  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
101M
  *arc = 1;
221
101M
}
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
2.37M
{
234
2.37M
  g_return_if_fail (arc != NULL);
235
2.37M
  g_return_if_fail (g_atomic_int_get (arc) > 0);
236
237
2.37M
  if (g_atomic_int_get (arc) == G_MAXINT)
238
0
    {
239
0
      g_critical ("Reference count has reached saturation");
240
0
      return;
241
0
    }
242
243
2.37M
  g_atomic_int_inc (arc);
244
2.37M
}
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
 */
256
gboolean
257
(g_atomic_ref_count_dec) (gatomicrefcount *arc)
258
103M
{
259
103M
  g_return_val_if_fail (arc != NULL, FALSE);
260
103M
  g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
261
262
103M
  return g_atomic_int_dec_and_test (arc);
263
103M
}
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
 */
277
gboolean
278
(g_atomic_ref_count_compare) (gatomicrefcount *arc,
279
                              gint             val)
280
0
{
281
0
  g_return_val_if_fail (arc != NULL, FALSE);
282
0
  g_return_val_if_fail (val >= 0, FALSE);
283
284
0
  return g_atomic_int_get (arc) == val;
285
0
}