diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml index a0716c172..26cdafb67 100644 --- a/docs/reference/glib/glib-docs.xml +++ b/docs/reference/glib/glib-docs.xml @@ -119,6 +119,7 @@ + diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 0183b0898..331d92c75 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -3449,3 +3449,18 @@ g_hostname_is_ip_address g_uuid_string_is_valid g_uuid_string_random + +
+refcount +grefcount +g_ref_count_init +g_ref_count_inc +g_ref_count_dec +g_ref_count_compare + +gatomicrefcount +g_atomic_ref_count_init +g_atomic_ref_count_inc +g_atomic_ref_count_dec +g_atomic_ref_count_compare +
diff --git a/glib/Makefile.am b/glib/Makefile.am index 049706126..4d04e09da 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -149,6 +149,7 @@ libglib_2_0_la_SOURCES = \ gquark.c \ gqueue.c \ grand.c \ + grefcount.c \ gregex.c \ gscanner.c \ gscripttable.h \ @@ -284,6 +285,7 @@ glibsubinclude_HEADERS = \ gquark.h \ gqueue.h \ grand.h \ + grefcount.h \ gregex.h \ gscanner.h \ gsequence.h \ diff --git a/glib/glib.h b/glib/glib.h index 4f5a7f702..84299c4f9 100644 --- a/glib/glib.h +++ b/glib/glib.h @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include diff --git a/glib/grefcount.c b/glib/grefcount.c new file mode 100644 index 000000000..10e35a217 --- /dev/null +++ b/glib/grefcount.c @@ -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 . + */ + +/** + * 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; +} diff --git a/glib/grefcount.h b/glib/grefcount.h new file mode 100644 index 000000000..b24c71e8c --- /dev/null +++ b/glib/grefcount.h @@ -0,0 +1,52 @@ +/* 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 . + */ + +#ifndef __GREFCOUNT_H__ +#define __GREFCOUNT_H__ + +#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +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); + +G_END_DECLS + +#endif /* __GREFCOUNT_H__ */ diff --git a/glib/gtypes.h b/glib/gtypes.h index 09d9bd145..67adb7f1f 100644 --- a/glib/gtypes.h +++ b/glib/gtypes.h @@ -510,6 +510,9 @@ struct _GTimeVal glong tv_usec; }; +typedef gint grefcount; +typedef volatile gint gatomicrefcount; + G_END_DECLS /* We prefix variable declarations so they can diff --git a/glib/meson.build b/glib/meson.build index 036d1f4d6..76d354c2a 100644 --- a/glib/meson.build +++ b/glib/meson.build @@ -76,6 +76,7 @@ glib_sub_headers = files( 'gquark.h', 'gqueue.h', 'grand.h', + 'grefcount.h', 'gregex.h', 'gscanner.h', 'gsequence.h', @@ -159,6 +160,7 @@ glib_sources = files( 'gquark.c', 'gqueue.c', 'grand.c', + 'grefcount.c', 'gregex.c', 'gscanner.c', 'gsequence.c',