Coverage Report

Created: 2025-07-01 06:23

/src/irssi/subprojects/glib-2.74.3/glib/grefcount.c
Line
Count
Source (jump to first uncovered line)
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
/**
22
 * SECTION:refcount
23
 * @Title: Reference counting
24
 * @Short_description: Reference counting types and functions
25
 *
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.
31
 *
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.
35
 *
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.
40
 *
41
 * Since: 2.58
42
 */
43
44
#include "config.h"
45
46
#include "grefcount.h"
47
48
#include "gatomic.h"
49
#include "gmessages.h"
50
51
/**
52
 * grefcount:
53
 *
54
 * A type for implementing non-atomic reference count semantics.
55
 *
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.
58
 *
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
62
 * same thread.
63
 *
64
 * See also: #gatomicrefcount
65
 *
66
 * Since: 2.58
67
 */
68
69
/**
70
 * gatomicrefcount:
71
 *
72
 * A type for implementing atomic reference count semantics.
73
 *
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.
76
 *
77
 * It is safe to use #gatomicrefcount if you're expecting to operate on the
78
 * reference counter from multiple threads.
79
 *
80
 * See also: #grefcount
81
 *
82
 * Since: 2.58
83
 */
84
85
/**
86
 * g_ref_count_init:
87
 * @rc: the address of a reference count variable
88
 *
89
 * Initializes a reference count variable to 1.
90
 *
91
 * Since: 2.58
92
 */
93
void
94
(g_ref_count_init) (grefcount *rc)
95
0
{
96
0
  g_return_if_fail (rc != NULL);
97
98
  /* Non-atomic refcounting is implemented using the negative range
99
   * of signed integers:
100
   *
101
   * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
102
   * |----------------------------|----------------------------|
103
   *
104
   * Acquiring a reference moves us towards MININT, and releasing a
105
   * reference moves us towards 0.
106
   */
107
0
  *rc = -1;
108
0
}
109
110
/**
111
 * g_ref_count_inc:
112
 * @rc: the address of a reference count variable
113
 *
114
 * Increases the reference count.
115
 *
116
 * Since: 2.58
117
 */
118
void
119
(g_ref_count_inc) (grefcount *rc)
120
0
{
121
0
  grefcount rrc;
122
123
0
  g_return_if_fail (rc != NULL);
124
125
0
  rrc = *rc;
126
127
0
  g_return_if_fail (rrc < 0);
128
129
  /* Check for saturation */
130
0
  if (rrc == G_MININT)
131
0
    {
132
0
      g_critical ("Reference count %p has reached saturation", rc);
133
0
      return;
134
0
    }
135
136
0
  rrc -= 1;
137
138
0
  *rc = rrc;
139
0
}
140
141
/**
142
 * g_ref_count_dec:
143
 * @rc: the address of a reference count variable
144
 *
145
 * Decreases the reference count.
146
 *
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.
150
 *
151
 * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
152
 *
153
 * Since: 2.58
154
 */
155
gboolean
156
(g_ref_count_dec) (grefcount *rc)
157
0
{
158
0
  grefcount rrc;
159
160
0
  g_return_val_if_fail (rc != NULL, FALSE);
161
162
0
  rrc = *rc;
163
164
0
  g_return_val_if_fail (rrc < 0, FALSE);
165
166
0
  rrc += 1;
167
0
  if (rrc == 0)
168
0
    return TRUE;
169
170
0
  *rc = rrc;
171
172
0
  return FALSE;
173
0
}
174
175
/**
176
 * g_ref_count_compare:
177
 * @rc: the address of a reference count variable
178
 * @val: the value to compare
179
 *
180
 * Compares the current value of @rc with @val.
181
 *
182
 * Returns: %TRUE if the reference count is the same
183
 *   as the given value
184
 *
185
 * Since: 2.58
186
 */
187
gboolean
188
(g_ref_count_compare) (grefcount *rc,
189
                       gint       val)
190
0
{
191
0
  grefcount rrc;
192
193
0
  g_return_val_if_fail (rc != NULL, FALSE);
194
0
  g_return_val_if_fail (val >= 0, FALSE);
195
196
0
  rrc = *rc;
197
198
0
  if (val == G_MAXINT)
199
0
    return rrc == G_MININT;
200
201
0
  return rrc == -val;
202
0
}
203
204
/**
205
 * g_atomic_ref_count_init:
206
 * @arc: the address of an atomic reference count variable
207
 *
208
 * Initializes a reference count variable to 1.
209
 *
210
 * Since: 2.58
211
 */
212
void
213
(g_atomic_ref_count_init) (gatomicrefcount *arc)
214
3.56M
{
215
3.56M
  g_return_if_fail (arc != NULL);
216
217
  /* Atomic refcounting is implemented using the positive range
218
   * of signed integers:
219
   *
220
   * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
221
   * |----------------------------|----------------------------|
222
   *
223
   * Acquiring a reference moves us towards MAXINT, and releasing a
224
   * reference moves us towards 0.
225
   */
226
3.56M
  *arc = 1;
227
3.56M
}
228
229
/**
230
 * g_atomic_ref_count_inc:
231
 * @arc: the address of an atomic reference count variable
232
 *
233
 * Atomically increases the reference count.
234
 *
235
 * Since: 2.58
236
 */
237
void
238
(g_atomic_ref_count_inc) (gatomicrefcount *arc)
239
0
{
240
0
  gint old_value;
241
242
0
  g_return_if_fail (arc != NULL);
243
0
  old_value = g_atomic_int_add (arc, 1);
244
0
  g_return_if_fail (old_value > 0);
245
246
0
  if (old_value == G_MAXINT)
247
0
    g_critical ("Reference count has reached saturation");
248
0
}
249
250
/**
251
 * g_atomic_ref_count_dec:
252
 * @arc: the address of an atomic reference count variable
253
 *
254
 * Atomically decreases the reference count.
255
 *
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.
259
 *
260
 * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
261
 *
262
 * Since: 2.58
263
 */
264
gboolean
265
(g_atomic_ref_count_dec) (gatomicrefcount *arc)
266
3.56M
{
267
3.56M
  gint old_value;
268
269
3.56M
  g_return_val_if_fail (arc != NULL, FALSE);
270
3.56M
  old_value = g_atomic_int_add (arc, -1);
271
3.56M
  g_return_val_if_fail (old_value > 0, FALSE);
272
273
3.56M
  return old_value == 1;
274
3.56M
}
275
276
/**
277
 * g_atomic_ref_count_compare:
278
 * @arc: the address of an atomic reference count variable
279
 * @val: the value to compare
280
 *
281
 * Atomically compares the current value of @arc with @val.
282
 *
283
 * Returns: %TRUE if the reference count is the same
284
 *   as the given value
285
 *
286
 * Since: 2.58
287
 */
288
gboolean
289
(g_atomic_ref_count_compare) (gatomicrefcount *arc,
290
                              gint             val)
291
0
{
292
0
  g_return_val_if_fail (arc != NULL, FALSE);
293
0
  g_return_val_if_fail (val >= 0, FALSE);
294
295
0
  return g_atomic_int_get (arc) == val;
296
0
}