mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-25 03:32:12 +01:00
Merge branch 'refcount-types' into 'master'
Reference counting types See merge request GNOME/glib!54
This commit is contained in:
commit
815478a74e
@ -119,6 +119,7 @@
|
|||||||
<xi:include href="xml/gvariant.xml"/>
|
<xi:include href="xml/gvariant.xml"/>
|
||||||
<xi:include href="gvariant-varargs.xml"/>
|
<xi:include href="gvariant-varargs.xml"/>
|
||||||
<xi:include href="gvariant-text.xml"/>
|
<xi:include href="gvariant-text.xml"/>
|
||||||
|
<xi:include href="xml/refcount.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="deprecated">
|
<chapter id="deprecated">
|
||||||
|
@ -3449,3 +3449,18 @@ g_hostname_is_ip_address
|
|||||||
g_uuid_string_is_valid
|
g_uuid_string_is_valid
|
||||||
g_uuid_string_random
|
g_uuid_string_random
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>refcount</FILE>
|
||||||
|
grefcount
|
||||||
|
g_ref_count_init
|
||||||
|
g_ref_count_inc
|
||||||
|
g_ref_count_dec
|
||||||
|
g_ref_count_compare
|
||||||
|
<SUBSECTION>
|
||||||
|
gatomicrefcount
|
||||||
|
g_atomic_ref_count_init
|
||||||
|
g_atomic_ref_count_inc
|
||||||
|
g_atomic_ref_count_dec
|
||||||
|
g_atomic_ref_count_compare
|
||||||
|
</SECTION>
|
||||||
|
@ -149,6 +149,7 @@ libglib_2_0_la_SOURCES = \
|
|||||||
gquark.c \
|
gquark.c \
|
||||||
gqueue.c \
|
gqueue.c \
|
||||||
grand.c \
|
grand.c \
|
||||||
|
grefcount.c \
|
||||||
gregex.c \
|
gregex.c \
|
||||||
gscanner.c \
|
gscanner.c \
|
||||||
gscripttable.h \
|
gscripttable.h \
|
||||||
@ -284,6 +285,7 @@ glibsubinclude_HEADERS = \
|
|||||||
gquark.h \
|
gquark.h \
|
||||||
gqueue.h \
|
gqueue.h \
|
||||||
grand.h \
|
grand.h \
|
||||||
|
grefcount.h \
|
||||||
gregex.h \
|
gregex.h \
|
||||||
gscanner.h \
|
gscanner.h \
|
||||||
gsequence.h \
|
gsequence.h \
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include "gthread.h"
|
#include "gthread.h"
|
||||||
#include "gmessages.h"
|
#include "gmessages.h"
|
||||||
#include "gqsort.h"
|
#include "gqsort.h"
|
||||||
|
#include "grefcount.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:arrays
|
* SECTION:arrays
|
||||||
@ -106,7 +106,7 @@ struct _GRealArray
|
|||||||
guint elt_size;
|
guint elt_size;
|
||||||
guint zero_terminated : 1;
|
guint zero_terminated : 1;
|
||||||
guint clear : 1;
|
guint clear : 1;
|
||||||
gint ref_count;
|
gatomicrefcount ref_count;
|
||||||
GDestroyNotify clear_func;
|
GDestroyNotify clear_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -199,9 +199,10 @@ g_array_sized_new (gboolean zero_terminated,
|
|||||||
array->zero_terminated = (zero_terminated ? 1 : 0);
|
array->zero_terminated = (zero_terminated ? 1 : 0);
|
||||||
array->clear = (clear ? 1 : 0);
|
array->clear = (clear ? 1 : 0);
|
||||||
array->elt_size = elt_size;
|
array->elt_size = elt_size;
|
||||||
array->ref_count = 1;
|
|
||||||
array->clear_func = NULL;
|
array->clear_func = NULL;
|
||||||
|
|
||||||
|
g_atomic_ref_count_init (&array->ref_count);
|
||||||
|
|
||||||
if (array->zero_terminated || reserved_size != 0)
|
if (array->zero_terminated || reserved_size != 0)
|
||||||
{
|
{
|
||||||
g_array_maybe_expand (array, reserved_size);
|
g_array_maybe_expand (array, reserved_size);
|
||||||
@ -257,7 +258,7 @@ g_array_ref (GArray *array)
|
|||||||
GRealArray *rarray = (GRealArray*) array;
|
GRealArray *rarray = (GRealArray*) array;
|
||||||
g_return_val_if_fail (array, NULL);
|
g_return_val_if_fail (array, NULL);
|
||||||
|
|
||||||
g_atomic_int_inc (&rarray->ref_count);
|
g_atomic_ref_count_inc (&rarray->ref_count);
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
@ -287,7 +288,7 @@ g_array_unref (GArray *array)
|
|||||||
GRealArray *rarray = (GRealArray*) array;
|
GRealArray *rarray = (GRealArray*) array;
|
||||||
g_return_if_fail (array);
|
g_return_if_fail (array);
|
||||||
|
|
||||||
if (g_atomic_int_dec_and_test (&rarray->ref_count))
|
if (g_atomic_ref_count_dec (&rarray->ref_count))
|
||||||
array_free (rarray, FREE_SEGMENT);
|
array_free (rarray, FREE_SEGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +347,7 @@ g_array_free (GArray *farray,
|
|||||||
flags = (free_segment ? FREE_SEGMENT : 0);
|
flags = (free_segment ? FREE_SEGMENT : 0);
|
||||||
|
|
||||||
/* if others are holding a reference, preserve the wrapper but do free/return the data */
|
/* if others are holding a reference, preserve the wrapper but do free/return the data */
|
||||||
if (!g_atomic_int_dec_and_test (&array->ref_count))
|
if (!g_atomic_ref_count_dec (&array->ref_count))
|
||||||
flags |= PRESERVE_WRAPPER;
|
flags |= PRESERVE_WRAPPER;
|
||||||
|
|
||||||
return array_free (array, flags);
|
return array_free (array, flags);
|
||||||
@ -882,7 +883,7 @@ struct _GRealPtrArray
|
|||||||
gpointer *pdata;
|
gpointer *pdata;
|
||||||
guint len;
|
guint len;
|
||||||
guint alloc;
|
guint alloc;
|
||||||
gint ref_count;
|
gatomicrefcount ref_count;
|
||||||
GDestroyNotify element_free_func;
|
GDestroyNotify element_free_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -936,9 +937,10 @@ g_ptr_array_sized_new (guint reserved_size)
|
|||||||
array->pdata = NULL;
|
array->pdata = NULL;
|
||||||
array->len = 0;
|
array->len = 0;
|
||||||
array->alloc = 0;
|
array->alloc = 0;
|
||||||
array->ref_count = 1;
|
|
||||||
array->element_free_func = NULL;
|
array->element_free_func = NULL;
|
||||||
|
|
||||||
|
g_atomic_ref_count_init (&array->ref_count);
|
||||||
|
|
||||||
if (reserved_size != 0)
|
if (reserved_size != 0)
|
||||||
g_ptr_array_maybe_expand (array, reserved_size);
|
g_ptr_array_maybe_expand (array, reserved_size);
|
||||||
|
|
||||||
@ -1041,7 +1043,7 @@ g_ptr_array_ref (GPtrArray *array)
|
|||||||
|
|
||||||
g_return_val_if_fail (array, NULL);
|
g_return_val_if_fail (array, NULL);
|
||||||
|
|
||||||
g_atomic_int_inc (&rarray->ref_count);
|
g_atomic_ref_count_inc (&rarray->ref_count);
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
@ -1066,7 +1068,7 @@ g_ptr_array_unref (GPtrArray *array)
|
|||||||
|
|
||||||
g_return_if_fail (array);
|
g_return_if_fail (array);
|
||||||
|
|
||||||
if (g_atomic_int_dec_and_test (&rarray->ref_count))
|
if (g_atomic_ref_count_dec (&rarray->ref_count))
|
||||||
ptr_array_free (array, FREE_SEGMENT);
|
ptr_array_free (array, FREE_SEGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1107,7 +1109,7 @@ g_ptr_array_free (GPtrArray *array,
|
|||||||
/* if others are holding a reference, preserve the wrapper but
|
/* if others are holding a reference, preserve the wrapper but
|
||||||
* do free/return the data
|
* do free/return the data
|
||||||
*/
|
*/
|
||||||
if (!g_atomic_int_dec_and_test (&rarray->ref_count))
|
if (!g_atomic_ref_count_dec (&rarray->ref_count))
|
||||||
flags |= PRESERVE_WRAPPER;
|
flags |= PRESERVE_WRAPPER;
|
||||||
|
|
||||||
return ptr_array_free (array, flags);
|
return ptr_array_free (array, flags);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <glib/gtestutils.h>
|
#include <glib/gtestutils.h>
|
||||||
#include <glib/gmem.h>
|
#include <glib/gmem.h>
|
||||||
#include <glib/gmessages.h>
|
#include <glib/gmessages.h>
|
||||||
|
#include <glib/grefcount.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ struct _GBytes
|
|||||||
{
|
{
|
||||||
gconstpointer data; /* may be NULL iff (size == 0) */
|
gconstpointer data; /* may be NULL iff (size == 0) */
|
||||||
gsize size; /* may be 0 */
|
gsize size; /* may be 0 */
|
||||||
gint ref_count;
|
gatomicrefcount ref_count;
|
||||||
GDestroyNotify free_func;
|
GDestroyNotify free_func;
|
||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
};
|
};
|
||||||
@ -187,7 +188,7 @@ g_bytes_new_with_free_func (gconstpointer data,
|
|||||||
bytes->size = size;
|
bytes->size = size;
|
||||||
bytes->free_func = free_func;
|
bytes->free_func = free_func;
|
||||||
bytes->user_data = user_data;
|
bytes->user_data = user_data;
|
||||||
bytes->ref_count = 1;
|
g_atomic_ref_count_init (&bytes->ref_count);
|
||||||
|
|
||||||
return (GBytes *)bytes;
|
return (GBytes *)bytes;
|
||||||
}
|
}
|
||||||
@ -310,7 +311,7 @@ g_bytes_ref (GBytes *bytes)
|
|||||||
{
|
{
|
||||||
g_return_val_if_fail (bytes != NULL, NULL);
|
g_return_val_if_fail (bytes != NULL, NULL);
|
||||||
|
|
||||||
g_atomic_int_inc (&bytes->ref_count);
|
g_atomic_ref_count_inc (&bytes->ref_count);
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
@ -330,7 +331,7 @@ g_bytes_unref (GBytes *bytes)
|
|||||||
if (bytes == NULL)
|
if (bytes == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_atomic_int_dec_and_test (&bytes->ref_count))
|
if (g_atomic_ref_count_dec (&bytes->ref_count))
|
||||||
{
|
{
|
||||||
if (bytes->free_func != NULL)
|
if (bytes->free_func != NULL)
|
||||||
bytes->free_func (bytes->user_data);
|
bytes->free_func (bytes->user_data);
|
||||||
@ -438,7 +439,7 @@ try_steal_and_unref (GBytes *bytes,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Are we the only reference? */
|
/* Are we the only reference? */
|
||||||
if (g_atomic_int_get (&bytes->ref_count) == 1)
|
if (g_atomic_ref_count_compare (&bytes->ref_count, 1))
|
||||||
{
|
{
|
||||||
*size = bytes->size;
|
*size = bytes->size;
|
||||||
result = (gpointer)bytes->data;
|
result = (gpointer)bytes->data;
|
||||||
|
12
glib/ghash.c
12
glib/ghash.c
@ -37,7 +37,7 @@
|
|||||||
#include "gatomic.h"
|
#include "gatomic.h"
|
||||||
#include "gtestutils.h"
|
#include "gtestutils.h"
|
||||||
#include "gslice.h"
|
#include "gslice.h"
|
||||||
|
#include "grefcount.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:hash_tables
|
* SECTION:hash_tables
|
||||||
@ -227,7 +227,7 @@ struct _GHashTable
|
|||||||
|
|
||||||
GHashFunc hash_func;
|
GHashFunc hash_func;
|
||||||
GEqualFunc key_equal_func;
|
GEqualFunc key_equal_func;
|
||||||
gint ref_count;
|
gatomicrefcount ref_count;
|
||||||
#ifndef G_DISABLE_ASSERT
|
#ifndef G_DISABLE_ASSERT
|
||||||
/*
|
/*
|
||||||
* Tracks the structure of the hash table, not its contents: is only
|
* Tracks the structure of the hash table, not its contents: is only
|
||||||
@ -374,7 +374,7 @@ g_hash_table_lookup_node (GHashTable *hash_table,
|
|||||||
* (as keys, etc. will be NULL).
|
* (as keys, etc. will be NULL).
|
||||||
* Applications need to either use g_hash_table_destroy, or ensure the hash
|
* Applications need to either use g_hash_table_destroy, or ensure the hash
|
||||||
* table is empty prior to removing the last reference using g_hash_table_unref(). */
|
* table is empty prior to removing the last reference using g_hash_table_unref(). */
|
||||||
g_assert (hash_table->ref_count > 0);
|
g_assert (!g_atomic_ref_count_compare (&hash_table->ref_count, 0));
|
||||||
|
|
||||||
hash_value = hash_table->hash_func (key);
|
hash_value = hash_table->hash_func (key);
|
||||||
if (G_UNLIKELY (!HASH_IS_REAL (hash_value)))
|
if (G_UNLIKELY (!HASH_IS_REAL (hash_value)))
|
||||||
@ -716,11 +716,11 @@ g_hash_table_new_full (GHashFunc hash_func,
|
|||||||
|
|
||||||
hash_table = g_slice_new (GHashTable);
|
hash_table = g_slice_new (GHashTable);
|
||||||
g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
|
g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
|
||||||
|
g_atomic_ref_count_init (&hash_table->ref_count);
|
||||||
hash_table->nnodes = 0;
|
hash_table->nnodes = 0;
|
||||||
hash_table->noccupied = 0;
|
hash_table->noccupied = 0;
|
||||||
hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
|
hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
|
||||||
hash_table->key_equal_func = key_equal_func;
|
hash_table->key_equal_func = key_equal_func;
|
||||||
hash_table->ref_count = 1;
|
|
||||||
#ifndef G_DISABLE_ASSERT
|
#ifndef G_DISABLE_ASSERT
|
||||||
hash_table->version = 0;
|
hash_table->version = 0;
|
||||||
#endif
|
#endif
|
||||||
@ -1077,7 +1077,7 @@ g_hash_table_ref (GHashTable *hash_table)
|
|||||||
{
|
{
|
||||||
g_return_val_if_fail (hash_table != NULL, NULL);
|
g_return_val_if_fail (hash_table != NULL, NULL);
|
||||||
|
|
||||||
g_atomic_int_inc (&hash_table->ref_count);
|
g_atomic_ref_count_inc (&hash_table->ref_count);
|
||||||
|
|
||||||
return hash_table;
|
return hash_table;
|
||||||
}
|
}
|
||||||
@ -1098,7 +1098,7 @@ g_hash_table_unref (GHashTable *hash_table)
|
|||||||
{
|
{
|
||||||
g_return_if_fail (hash_table != NULL);
|
g_return_if_fail (hash_table != NULL);
|
||||||
|
|
||||||
if (g_atomic_int_dec_and_test (&hash_table->ref_count))
|
if (g_atomic_ref_count_dec (&hash_table->ref_count))
|
||||||
{
|
{
|
||||||
g_hash_table_remove_all_nodes (hash_table, TRUE, TRUE);
|
g_hash_table_remove_all_nodes (hash_table, TRUE, TRUE);
|
||||||
if (hash_table->keys != hash_table->values)
|
if (hash_table->keys != hash_table->values)
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
#include <glib/gquark.h>
|
#include <glib/gquark.h>
|
||||||
#include <glib/gqueue.h>
|
#include <glib/gqueue.h>
|
||||||
#include <glib/grand.h>
|
#include <glib/grand.h>
|
||||||
|
#include <glib/grefcount.h>
|
||||||
#include <glib/gregex.h>
|
#include <glib/gregex.h>
|
||||||
#include <glib/gscanner.h>
|
#include <glib/gscanner.h>
|
||||||
#include <glib/gsequence.h>
|
#include <glib/gsequence.h>
|
||||||
|
285
glib/grefcount.c
Normal file
285
glib/grefcount.c
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
/* grefcount.c: Reference counting
|
||||||
|
*
|
||||||
|
* Copyright 2018 Emmanuele Bassi
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:refcount
|
||||||
|
* @Title: Reference counting
|
||||||
|
* @Short_description: Reference counting types and functions
|
||||||
|
*
|
||||||
|
* Reference counting is a garbage collection mechanism that is based on
|
||||||
|
* assigning a counter to a data type, or any memory area; the counter is
|
||||||
|
* increased whenever a new reference to that data type is acquired, and
|
||||||
|
* decreased whenever the reference is released. Once the last reference
|
||||||
|
* is released, the resources associated to that data type are freed.
|
||||||
|
*
|
||||||
|
* GLib uses reference counting in many of its data types, and provides
|
||||||
|
* the #grefcount and #gatomicrefcount types to implement safe and atomic
|
||||||
|
* reference counting semantics in new data types.
|
||||||
|
*
|
||||||
|
* It is important to note that #grefcount and #gatomicrefcount should be
|
||||||
|
* considered completely opaque types; you should always use the provided
|
||||||
|
* API to increase and decrease the counters, and you should never check
|
||||||
|
* their content directly, or compare their content with other values.
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "grefcount.h"
|
||||||
|
|
||||||
|
#include "gatomic.h"
|
||||||
|
#include "gmessages.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* grefcount:
|
||||||
|
*
|
||||||
|
* A type for implementing non-atomic reference count semantics.
|
||||||
|
*
|
||||||
|
* Use g_ref_count_init() to initialize it; g_ref_count_inc() to
|
||||||
|
* increase the counter, and g_ref_count_dec() to decrease it.
|
||||||
|
*
|
||||||
|
* It is safe to use #grefcount only if you're expecting to operate
|
||||||
|
* on the reference counter from a single thread. It is entirely up
|
||||||
|
* to you to ensure that all reference count changes happen in the
|
||||||
|
* same thread.
|
||||||
|
*
|
||||||
|
* See also: #gatomicrefcount
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gatomicrefcount:
|
||||||
|
*
|
||||||
|
* A type for implementing atomic reference count semantics.
|
||||||
|
*
|
||||||
|
* Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
|
||||||
|
* to increase the counter, and g_atomic_ref_count_dec() to decrease it.
|
||||||
|
*
|
||||||
|
* It is safe to use #gatomicrefcount if you're expecting to operate on the
|
||||||
|
* reference counter from multiple threads.
|
||||||
|
*
|
||||||
|
* See also: #grefcount
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_ref_count_init:
|
||||||
|
* @rc: the address of a reference count variable
|
||||||
|
*
|
||||||
|
* Initializes a reference count variable.
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
(g_ref_count_init) (grefcount *rc)
|
||||||
|
{
|
||||||
|
g_return_if_fail (rc != NULL);
|
||||||
|
|
||||||
|
/* Non-atomic refcounting is implemented using the negative range
|
||||||
|
* of signed integers:
|
||||||
|
*
|
||||||
|
* G_MININT Z¯< 0 > Z⁺ G_MAXINT
|
||||||
|
* |----------------------------|----------------------------|
|
||||||
|
*
|
||||||
|
* Acquiring a reference moves us towards MININT, and releasing a
|
||||||
|
* reference moves us towards 0.
|
||||||
|
*/
|
||||||
|
*rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_ref_count_inc:
|
||||||
|
* @rc: the address of a reference count variable
|
||||||
|
*
|
||||||
|
* Increases the reference count.
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
(g_ref_count_inc) (grefcount *rc)
|
||||||
|
{
|
||||||
|
grefcount rrc;
|
||||||
|
|
||||||
|
g_return_if_fail (rc != NULL);
|
||||||
|
|
||||||
|
rrc = *rc;
|
||||||
|
|
||||||
|
g_return_if_fail (rrc < 0);
|
||||||
|
|
||||||
|
/* Check for saturation */
|
||||||
|
if (rrc == G_MININT)
|
||||||
|
{
|
||||||
|
g_critical ("Reference count %p has reached saturation", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rrc -= 1;
|
||||||
|
|
||||||
|
*rc = rrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_ref_count_dec:
|
||||||
|
* @rc: the address of a reference count variable
|
||||||
|
*
|
||||||
|
* Decreases the reference count.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
(g_ref_count_dec) (grefcount *rc)
|
||||||
|
{
|
||||||
|
grefcount rrc;
|
||||||
|
|
||||||
|
g_return_val_if_fail (rc != NULL, FALSE);
|
||||||
|
|
||||||
|
rrc = *rc;
|
||||||
|
|
||||||
|
g_return_val_if_fail (rrc < 0, FALSE);
|
||||||
|
|
||||||
|
rrc += 1;
|
||||||
|
if (rrc == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
*rc = rrc;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_ref_count_compare:
|
||||||
|
* @rc: the address of a reference count variable
|
||||||
|
* @val: the value to compare
|
||||||
|
*
|
||||||
|
* Compares the current value of @rc with @val.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the reference count is the same
|
||||||
|
* as the given value
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
(g_ref_count_compare) (grefcount *rc,
|
||||||
|
gint val)
|
||||||
|
{
|
||||||
|
grefcount rrc;
|
||||||
|
|
||||||
|
g_return_val_if_fail (rc != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (val >= 0, FALSE);
|
||||||
|
|
||||||
|
rrc = *rc;
|
||||||
|
|
||||||
|
if (val == G_MAXINT)
|
||||||
|
return rrc == G_MININT;
|
||||||
|
|
||||||
|
return rrc == -val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_atomic_ref_count_init:
|
||||||
|
* @arc: the address of an atomic reference count variable
|
||||||
|
*
|
||||||
|
* Atomically initializes a reference count variable.
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
(g_atomic_ref_count_init) (gatomicrefcount *arc)
|
||||||
|
{
|
||||||
|
g_return_if_fail (arc != NULL);
|
||||||
|
|
||||||
|
/* Atomic refcounting is implemented using the positive range
|
||||||
|
* of signed integers:
|
||||||
|
*
|
||||||
|
* G_MININT Z¯< 0 > Z⁺ G_MAXINT
|
||||||
|
* |----------------------------|----------------------------|
|
||||||
|
*
|
||||||
|
* Acquiring a reference moves us towards MAXINT, and releasing a
|
||||||
|
* reference moves us towards 0.
|
||||||
|
*/
|
||||||
|
g_atomic_int_set (arc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_atomic_ref_count_inc:
|
||||||
|
* @arc: the address of an atomic reference count variable
|
||||||
|
*
|
||||||
|
* Atomically increases the reference count.
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
(g_atomic_ref_count_inc) (gatomicrefcount *arc)
|
||||||
|
{
|
||||||
|
g_return_if_fail (arc != NULL);
|
||||||
|
g_return_if_fail (g_atomic_int_get (arc) > 0);
|
||||||
|
|
||||||
|
if (g_atomic_int_get (arc) == G_MAXINT)
|
||||||
|
{
|
||||||
|
g_critical ("Reference count has reached saturation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_atomic_int_inc (arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_atomic_ref_count_dec:
|
||||||
|
* @arc: the address of an atomic reference count variable
|
||||||
|
*
|
||||||
|
* Atomically decreases the reference count.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
(g_atomic_ref_count_dec) (gatomicrefcount *arc)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (arc != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
|
||||||
|
|
||||||
|
return g_atomic_int_dec_and_test (arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_atomic_ref_count_compare:
|
||||||
|
* @arc: the address of an atomic reference count variable
|
||||||
|
* @val: the value to compare
|
||||||
|
*
|
||||||
|
* Atomically compares the current value of @arc with @val.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the reference count is the same
|
||||||
|
* as the given value
|
||||||
|
*
|
||||||
|
* Since: 2.58
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
(g_atomic_ref_count_compare) (gatomicrefcount *arc,
|
||||||
|
gint val)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (arc != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (val >= 0, FALSE);
|
||||||
|
|
||||||
|
return g_atomic_int_get (arc) == val;
|
||||||
|
}
|
122
glib/grefcount.h
Normal file
122
glib/grefcount.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/* grefcount.h: Reference counting
|
||||||
|
*
|
||||||
|
* Copyright 2018 Emmanuele Bassi
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GREFCOUNT_H__
|
||||||
|
#define __GREFCOUNT_H__
|
||||||
|
|
||||||
|
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
|
||||||
|
#error "Only <glib.h> can be included directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
void g_ref_count_init (grefcount *rc);
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
void g_ref_count_inc (grefcount *rc);
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
gboolean g_ref_count_dec (grefcount *rc);
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
gboolean g_ref_count_compare (grefcount *rc,
|
||||||
|
gint val);
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
void g_atomic_ref_count_init (gatomicrefcount *arc);
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
void g_atomic_ref_count_inc (gatomicrefcount *arc);
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
gboolean g_atomic_ref_count_dec (gatomicrefcount *arc);
|
||||||
|
GLIB_AVAILABLE_IN_2_58
|
||||||
|
gboolean g_atomic_ref_count_compare (gatomicrefcount *arc,
|
||||||
|
gint val);
|
||||||
|
|
||||||
|
/* On GCC we can use __extension__ to inline the API without using
|
||||||
|
* ancillary functions; we only do this when disabling checks, as
|
||||||
|
* it disables warnings when saturating the reference counters
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) && defined(G_DISABLE_CHECKS)
|
||||||
|
|
||||||
|
# define g_ref_count_init(rc) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ *(rc) : 1); \
|
||||||
|
*(rc) = -1; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_ref_count_inc(rc) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ *(rc) : 1); \
|
||||||
|
if (*(rc) == G_MININT) ; else { \
|
||||||
|
*(rc) -= 1; \
|
||||||
|
} \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_ref_count_dec(rc) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
|
||||||
|
grefcount __rc = *(rc); \
|
||||||
|
__rc += 1; \
|
||||||
|
if (__rc == 0) ; else { \
|
||||||
|
*(rc) = __rc; \
|
||||||
|
} \
|
||||||
|
(gboolean) (__rc == 0); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_ref_count_compare(rc,val) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ (val) : 1); \
|
||||||
|
(gboolean) (*(rc) == -(val)); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_atomic_ref_count_init(rc) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ *(rc) : 1); \
|
||||||
|
g_atomic_int_set ((rc), 1); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_atomic_ref_count_inc(rc) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ *(rc) : 1); \
|
||||||
|
(void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_atomic_ref_count_dec(rc) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ *(rc) : 1); \
|
||||||
|
g_atomic_int_dec_and_test ((rc)); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
# define g_atomic_ref_count_compare(rc,val) \
|
||||||
|
(G_GNUC_EXTENSION ({ \
|
||||||
|
G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
|
||||||
|
(void) (0 ? *(rc) ^ (val) : 1); \
|
||||||
|
(gboolean) (g_atomic_int_get (rc) == (val)); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#endif /* __GNUC__ && G_DISABLE_CHECKS */
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GREFCOUNT_H__ */
|
@ -510,6 +510,9 @@ struct _GTimeVal
|
|||||||
glong tv_usec;
|
glong tv_usec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef gint grefcount;
|
||||||
|
typedef volatile gint gatomicrefcount;
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
/* We prefix variable declarations so they can
|
/* We prefix variable declarations so they can
|
||||||
|
@ -76,6 +76,7 @@ glib_sub_headers = files(
|
|||||||
'gquark.h',
|
'gquark.h',
|
||||||
'gqueue.h',
|
'gqueue.h',
|
||||||
'grand.h',
|
'grand.h',
|
||||||
|
'grefcount.h',
|
||||||
'gregex.h',
|
'gregex.h',
|
||||||
'gscanner.h',
|
'gscanner.h',
|
||||||
'gsequence.h',
|
'gsequence.h',
|
||||||
@ -159,6 +160,7 @@ glib_sources = files(
|
|||||||
'gquark.c',
|
'gquark.c',
|
||||||
'gqueue.c',
|
'gqueue.c',
|
||||||
'grand.c',
|
'grand.c',
|
||||||
|
'grefcount.c',
|
||||||
'gregex.c',
|
'gregex.c',
|
||||||
'gscanner.c',
|
'gscanner.c',
|
||||||
'gsequence.c',
|
'gsequence.c',
|
||||||
|
@ -47,6 +47,8 @@ glib_tests = [
|
|||||||
'queue',
|
'queue',
|
||||||
'rand',
|
'rand',
|
||||||
'rec-mutex',
|
'rec-mutex',
|
||||||
|
'refcount',
|
||||||
|
'refcount-macro',
|
||||||
'regex',
|
'regex',
|
||||||
'rwlock',
|
'rwlock',
|
||||||
'scannerapi',
|
'scannerapi',
|
||||||
@ -108,14 +110,23 @@ slow_tests = [
|
|||||||
|
|
||||||
foreach test_name : glib_tests
|
foreach test_name : glib_tests
|
||||||
deps = [libm, thread_dep, libglib_dep]
|
deps = [libm, thread_dep, libglib_dep]
|
||||||
|
source = test_name + '.c'
|
||||||
|
c_args = test_cargs + ['-DPCRE_STATIC']
|
||||||
if test_name == 'regex'
|
if test_name == 'regex'
|
||||||
deps += [pcre]
|
deps += [pcre]
|
||||||
endif
|
endif
|
||||||
if test_name == 'gdatetime'
|
if test_name == 'gdatetime'
|
||||||
deps += [libintl]
|
deps += [libintl]
|
||||||
endif
|
endif
|
||||||
exe = executable(test_name, '@0@.c'.format(test_name),
|
# We build the refcount test twice: one to test the function-based API,
|
||||||
c_args : ['-DPCRE_STATIC'] + test_cargs,
|
# and the other to test the macro-based API that is used when disabling
|
||||||
|
# checks
|
||||||
|
if test_name == 'refcount-macro'
|
||||||
|
source = 'refcount.c'
|
||||||
|
c_args += ['-DG_DISABLE_CHECKS']
|
||||||
|
endif
|
||||||
|
exe = executable(test_name, source,
|
||||||
|
c_args : c_args,
|
||||||
dependencies : deps,
|
dependencies : deps,
|
||||||
install : false,
|
install : false,
|
||||||
)
|
)
|
||||||
|
221
glib/tests/refcount.c
Normal file
221
glib/tests/refcount.c
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/* refcount.c: Tests for reference counting types
|
||||||
|
*
|
||||||
|
* Copyright 2018 Emmanuele Bassi
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/* test_grefcount: test the behavior of the grefcount API */
|
||||||
|
static void
|
||||||
|
test_grefcount (void)
|
||||||
|
{
|
||||||
|
grefcount a, b;
|
||||||
|
|
||||||
|
/* init(a): 1 */
|
||||||
|
g_ref_count_init (&a);
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("init(a) := %d\n", (int) a);
|
||||||
|
g_assert_true (g_ref_count_compare (&a, 1));
|
||||||
|
|
||||||
|
/* inc(a): 2 */
|
||||||
|
g_ref_count_inc (&a);
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("inc(a) := %d\n", (int) a);
|
||||||
|
g_assert_false (g_ref_count_compare (&a, 1));
|
||||||
|
g_assert_false (g_ref_count_compare (&a, G_MAXINT));
|
||||||
|
|
||||||
|
/* b = a = 2 */
|
||||||
|
b = a;
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("a := %d, b := %d\n", (int) a, (int) b);
|
||||||
|
|
||||||
|
/* inc(a): 3 */
|
||||||
|
g_ref_count_inc (&a);
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("inc(a) := %d\n", (int) a);
|
||||||
|
|
||||||
|
/* dec(b) = 1 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(b) := %d + 1\n", (int) b);
|
||||||
|
g_assert_false (g_ref_count_dec (&b));
|
||||||
|
|
||||||
|
/* dec(a) = 2 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(a) := %d + 1\n", (int) a);
|
||||||
|
g_assert_false (g_ref_count_dec (&a));
|
||||||
|
|
||||||
|
/* dec(b) = 0 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(b) := %d + 1\n", (int) b);
|
||||||
|
g_assert_true (g_ref_count_dec (&b));
|
||||||
|
|
||||||
|
/* dec(a) = 1 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(a) := %d + 1\n", (int) a);
|
||||||
|
g_assert_false (g_ref_count_dec (&a));
|
||||||
|
|
||||||
|
/* dec(a) = 0 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(a) := %d + 1\n", (int) a);
|
||||||
|
g_assert_true (g_ref_count_dec (&a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test_grefcount_saturation: Saturating a grefcount counter
|
||||||
|
* does not cause an overflow; additionally, if we're building
|
||||||
|
* with checks enabled, it'll cause a warning
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_grefcount_saturation (void)
|
||||||
|
{
|
||||||
|
if (g_test_subprocess ())
|
||||||
|
{
|
||||||
|
grefcount a;
|
||||||
|
|
||||||
|
/* We're breaking abstraction here for convenience */
|
||||||
|
a = G_MININT + 1;
|
||||||
|
|
||||||
|
g_ref_count_inc (&a);
|
||||||
|
g_assert_true (a == G_MININT);
|
||||||
|
|
||||||
|
g_ref_count_inc (&a);
|
||||||
|
g_assert_true (a == G_MININT);
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_test_trap_subprocess (NULL, 0, 0);
|
||||||
|
|
||||||
|
#ifndef G_DISABLE_CHECKS
|
||||||
|
/* Ensure that we got a warning when building with checks; the
|
||||||
|
* test will fail because of the critical warning being caught
|
||||||
|
* by GTest
|
||||||
|
*/
|
||||||
|
g_test_trap_assert_failed ();
|
||||||
|
g_test_trap_assert_stderr ("*saturation*");
|
||||||
|
#else
|
||||||
|
/* With checks disabled we don't get any warning */
|
||||||
|
g_test_trap_assert_passed ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test_gatomicrefcount: test the behavior of the gatomicrefcount API */
|
||||||
|
static void
|
||||||
|
test_gatomicrefcount (void)
|
||||||
|
{
|
||||||
|
gatomicrefcount a, b;
|
||||||
|
|
||||||
|
/* init(a): 1 */
|
||||||
|
g_atomic_ref_count_init (&a);
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("init(a) := %d\n", (int) a);
|
||||||
|
g_assert_true (g_atomic_ref_count_compare (&a, 1));
|
||||||
|
|
||||||
|
/* inc(a): 2 */
|
||||||
|
g_atomic_ref_count_inc (&a);
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("inc(a) := %d\n", (int) a);
|
||||||
|
g_assert_false (g_atomic_ref_count_compare (&a, 1));
|
||||||
|
g_assert_false (g_atomic_ref_count_compare (&a, G_MAXINT));
|
||||||
|
|
||||||
|
/* b = a = 2 */
|
||||||
|
b = a;
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("a := %d, b := %d\n", (int) a, (int) b);
|
||||||
|
|
||||||
|
/* inc(a): 3 */
|
||||||
|
g_atomic_ref_count_inc (&a);
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("inc(a) := %d\n", (int) a);
|
||||||
|
|
||||||
|
/* dec(b) = 1 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(b) := %d + 1\n", (int) b);
|
||||||
|
g_assert_false (g_atomic_ref_count_dec (&b));
|
||||||
|
|
||||||
|
/* dec(a) = 2 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(a) := %d + 1\n", (int) a);
|
||||||
|
g_assert_false (g_atomic_ref_count_dec (&a));
|
||||||
|
|
||||||
|
/* dec(b) = 0 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(b) := %d + 1\n", (int) b);
|
||||||
|
g_assert_true (g_atomic_ref_count_dec (&b));
|
||||||
|
|
||||||
|
/* dec(a) = 1 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(a) := %d + 1\n", (int) a);
|
||||||
|
g_assert_false (g_atomic_ref_count_dec (&a));
|
||||||
|
|
||||||
|
/* dec(a) = 0 */
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_test_message ("dec(a) := %d + 1\n", (int) a);
|
||||||
|
g_assert_true (g_atomic_ref_count_dec (&a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test_grefcount_saturation: Saturating a gatomicrefcount counter
|
||||||
|
* does not cause an overflow; additionally, if we're building
|
||||||
|
* with checks enabled, it'll cause a warning
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_gatomicrefcount_saturation (void)
|
||||||
|
{
|
||||||
|
if (g_test_subprocess ())
|
||||||
|
{
|
||||||
|
gatomicrefcount a;
|
||||||
|
|
||||||
|
/* We're breaking abstraction here for convenience */
|
||||||
|
a = G_MAXINT - 1;
|
||||||
|
|
||||||
|
g_atomic_ref_count_inc (&a);
|
||||||
|
g_assert_true (a == G_MAXINT);
|
||||||
|
|
||||||
|
g_atomic_ref_count_inc (&a);
|
||||||
|
g_assert_true (a == G_MAXINT);
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_test_trap_subprocess (NULL, 0, 0);
|
||||||
|
|
||||||
|
#ifndef G_DISABLE_CHECKS
|
||||||
|
/* Ensure that we got a warning when building with checks; the
|
||||||
|
* test will fail because of the critical warning being caught
|
||||||
|
* by GTest
|
||||||
|
*/
|
||||||
|
g_test_trap_assert_failed ();
|
||||||
|
g_test_trap_assert_stderr ("*saturation*");
|
||||||
|
#else
|
||||||
|
/* With checks disabled we don't get any warning */
|
||||||
|
g_test_trap_assert_passed ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func ("/refcount/grefcount", test_grefcount);
|
||||||
|
g_test_add_func ("/refcount/grefcount/saturation", test_grefcount_saturation);
|
||||||
|
|
||||||
|
g_test_add_func ("/refcount/gatomicrefcount", test_gatomicrefcount);
|
||||||
|
g_test_add_func ("/refcount/gatomicrefcount/saturation", test_gatomicrefcount_saturation);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user