12eede
From 9e5a53d576765819d1c7c233515b9f6e5d77eb61 Mon Sep 17 00:00:00 2001
12eede
From: Emmanuele Bassi <ebassi@gnome.org>
12eede
Date: Wed, 17 Jan 2018 16:38:45 +0000
12eede
Subject: [PATCH] Add reference counting types
12eede
12eede
We have a common pattern for reference counting in GLib, but we always
12eede
implement it with ad hoc code. This is a good chance at trying to
12eede
standardise the implementation and make it public, so that other code
12eede
using GLib can take advantage of shared behaviour and semantics.
12eede
12eede
Instead of simply taking an integer variable, we should create type
12eede
aliases, to immediately distinguish the reference counting semantics of
12eede
the code; we can handle mixing atomic reference counting with a
12eede
non-atomic type (and vice versa) by using differently signed values for
12eede
the atomic and non-atomic cases.
12eede
12eede
The gatomicrefcount type is modelled on the Linux kernel refcount_t
12eede
type; the grefcount type is added to let single-threaded code bases to
12eede
avoid paying the price of atomic memory barriers on reference counting
12eede
operations.
12eede
---
12eede
 docs/reference/glib/glib-docs.xml     |   1 +
12eede
 docs/reference/glib/glib-sections.txt |  15 ++
12eede
 glib/Makefile.am                      |   2 +
12eede
 glib/glib.h                           |   1 +
12eede
 glib/grefcount.c                      | 285 ++++++++++++++++++++++++++
12eede
 glib/grefcount.h                      |  52 +++++
12eede
 glib/gtypes.h                         |   3 +
12eede
 glib/meson.build                      |   2 +
12eede
 8 files changed, 361 insertions(+)
12eede
 create mode 100644 glib/grefcount.c
12eede
 create mode 100644 glib/grefcount.h
12eede
12eede
diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml
12eede
index a0716c1727..26cdafb67b 100644
12eede
--- a/docs/reference/glib/glib-docs.xml
12eede
+++ b/docs/reference/glib/glib-docs.xml
12eede
@@ -119,6 +119,7 @@
12eede
     <xi:include href="xml/gvariant.xml"/>
12eede
     <xi:include href="gvariant-varargs.xml"/>
12eede
     <xi:include href="gvariant-text.xml"/>
12eede
+    <xi:include href="xml/refcount.xml"/>
12eede
   </chapter>
12eede
 
12eede
   <chapter id="deprecated">
12eede
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
12eede
index 0183b0898a..331d92c75f 100644
12eede
--- a/docs/reference/glib/glib-sections.txt
12eede
+++ b/docs/reference/glib/glib-sections.txt
12eede
@@ -3449,3 +3449,18 @@ g_hostname_is_ip_address
12eede
 g_uuid_string_is_valid
12eede
 g_uuid_string_random
12eede
 </SECTION>
12eede
+
12eede
+<SECTION>
12eede
+<FILE>refcount</FILE>
12eede
+grefcount
12eede
+g_ref_count_init
12eede
+g_ref_count_inc
12eede
+g_ref_count_dec
12eede
+g_ref_count_compare
12eede
+<SUBSECTION>
12eede
+gatomicrefcount
12eede
+g_atomic_ref_count_init
12eede
+g_atomic_ref_count_inc
12eede
+g_atomic_ref_count_dec
12eede
+g_atomic_ref_count_compare
12eede
+</SECTION>
12eede
diff --git a/glib/Makefile.am b/glib/Makefile.am
12eede
index 0497061265..4d04e09daa 100644
12eede
--- a/glib/Makefile.am
12eede
+++ b/glib/Makefile.am
12eede
@@ -149,6 +149,7 @@ libglib_2_0_la_SOURCES = 	\
12eede
 	gquark.c		\
12eede
 	gqueue.c		\
12eede
 	grand.c			\
12eede
+	grefcount.c		\
12eede
 	gregex.c		\
12eede
 	gscanner.c		\
12eede
 	gscripttable.h		\
12eede
@@ -284,6 +285,7 @@ glibsubinclude_HEADERS = \
12eede
 	gquark.h	\
12eede
 	gqueue.h	\
12eede
 	grand.h		\
12eede
+	grefcount.h	\
12eede
 	gregex.h	\
12eede
 	gscanner.h	\
12eede
 	gsequence.h	\
12eede
diff --git a/glib/glib.h b/glib/glib.h
12eede
index 4f5a7f702f..84299c4f90 100644
12eede
--- a/glib/glib.h
12eede
+++ b/glib/glib.h
12eede
@@ -69,6 +69,7 @@
12eede
 #include <glib/gquark.h>
12eede
 #include <glib/gqueue.h>
12eede
 #include <glib/grand.h>
12eede
+#include <glib/grefcount.h>
12eede
 #include <glib/gregex.h>
12eede
 #include <glib/gscanner.h>
12eede
 #include <glib/gsequence.h>
12eede
diff --git a/glib/grefcount.c b/glib/grefcount.c
12eede
new file mode 100644
12eede
index 0000000000..10e35a217d
12eede
--- /dev/null
12eede
+++ b/glib/grefcount.c
12eede
@@ -0,0 +1,285 @@
12eede
+/* grefcount.c: Reference counting
12eede
+ *
12eede
+ * Copyright 2018  Emmanuele Bassi
12eede
+ *
12eede
+ * This library is free software; you can redistribute it and/or
12eede
+ * modify it under the terms of the GNU Lesser General Public
12eede
+ * License as published by the Free Software Foundation; either
12eede
+ * version 2.1 of the License, or (at your option) any later version.
12eede
+ *
12eede
+ * This library is distributed in the hope that it will be useful,
12eede
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12eede
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12eede
+ * Lesser General Public License for more details.
12eede
+ *
12eede
+ * You should have received a copy of the GNU Lesser General Public
12eede
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
12eede
+ */
12eede
+
12eede
+/**
12eede
+ * SECTION:refcount
12eede
+ * @Title: Reference counting
12eede
+ * @Short_description: Reference counting types and functions
12eede
+ *
12eede
+ * Reference counting is a garbage collection mechanism that is based on
12eede
+ * assigning a counter to a data type, or any memory area; the counter is
12eede
+ * increased whenever a new reference to that data type is acquired, and
12eede
+ * decreased whenever the reference is released. Once the last reference
12eede
+ * is released, the resources associated to that data type are freed.
12eede
+ *
12eede
+ * GLib uses reference counting in many of its data types, and provides
12eede
+ * the #grefcount and #gatomicrefcount types to implement safe and atomic
12eede
+ * reference counting semantics in new data types.
12eede
+ *
12eede
+ * It is important to note that #grefcount and #gatomicrefcount should be
12eede
+ * considered completely opaque types; you should always use the provided
12eede
+ * API to increase and decrease the counters, and you should never check
12eede
+ * their content directly, or compare their content with other values.
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+
12eede
+#include "config.h"
12eede
+
12eede
+#include "grefcount.h"
12eede
+
12eede
+#include "gatomic.h"
12eede
+#include "gmessages.h"
12eede
+
12eede
+/**
12eede
+ * grefcount:
12eede
+ *
12eede
+ * A type for implementing non-atomic reference count semantics.
12eede
+ *
12eede
+ * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
12eede
+ * increase the counter, and g_ref_count_dec() to decrease it.
12eede
+ *
12eede
+ * It is safe to use #grefcount only if you're expecting to operate
12eede
+ * on the reference counter from a single thread. It is entirely up
12eede
+ * to you to ensure that all reference count changes happen in the
12eede
+ * same thread.
12eede
+ *
12eede
+ * See also: #gatomicrefcount
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+
12eede
+/**
12eede
+ * gatomicrefcount:
12eede
+ *
12eede
+ * A type for implementing atomic reference count semantics.
12eede
+ *
12eede
+ * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
12eede
+ * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
12eede
+ *
12eede
+ * It is safe to use #gatomicrefcount if you're expecting to operate on the
12eede
+ * reference counter from multiple threads.
12eede
+ *
12eede
+ * See also: #grefcount
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+
12eede
+/**
12eede
+ * g_ref_count_init:
12eede
+ * @rc: the address of a reference count variable
12eede
+ *
12eede
+ * Initializes a reference count variable.
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+void
12eede
+g_ref_count_init (grefcount *rc)
12eede
+{
12eede
+  g_return_if_fail (rc != NULL);
12eede
+
12eede
+  /* Non-atomic refcounting is implemented using the negative range
12eede
+   * of signed integers:
12eede
+   *
12eede
+   * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
12eede
+   * |----------------------------|----------------------------|
12eede
+   *
12eede
+   * Acquiring a reference moves us towards MININT, and releasing a
12eede
+   * reference moves us towards 0.
12eede
+   */
12eede
+  *rc = -1;
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_ref_count_inc:
12eede
+ * @rc: the address of a reference count variable
12eede
+ *
12eede
+ * Increases the reference count.
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+void
12eede
+g_ref_count_inc (grefcount *rc)
12eede
+{
12eede
+  grefcount rrc;
12eede
+
12eede
+  g_return_if_fail (rc != NULL);
12eede
+
12eede
+  rrc = *rc;
12eede
+
12eede
+  g_return_if_fail (rrc < 0);
12eede
+
12eede
+  /* Check for saturation */
12eede
+  if (rrc == G_MININT)
12eede
+    {
12eede
+      g_critical ("Reference count %p has reached saturation", rc);
12eede
+      return;
12eede
+    }
12eede
+
12eede
+  rrc -= 1;
12eede
+
12eede
+  *rc = rrc;
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_ref_count_dec:
12eede
+ * @rc: the address of a reference count variable
12eede
+ *
12eede
+ * Decreases the reference count.
12eede
+ *
12eede
+ * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+gboolean
12eede
+g_ref_count_dec (grefcount *rc)
12eede
+{
12eede
+  grefcount rrc;
12eede
+
12eede
+  g_return_val_if_fail (rc != NULL, FALSE);
12eede
+
12eede
+  rrc = *rc;
12eede
+
12eede
+  g_return_val_if_fail (rrc < 0, FALSE);
12eede
+
12eede
+  rrc += 1;
12eede
+  if (rrc == 0)
12eede
+    return TRUE;
12eede
+
12eede
+  *rc = rrc;
12eede
+
12eede
+  return FALSE;
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_ref_count_compare:
12eede
+ * @rc: the address of a reference count variable
12eede
+ * @val: the value to compare
12eede
+ *
12eede
+ * Compares the current value of @rc with @val.
12eede
+ *
12eede
+ * Returns: %TRUE if the reference count is the same
12eede
+ *   as the given value
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+gboolean
12eede
+g_ref_count_compare (grefcount *rc,
12eede
+                     gint       val)
12eede
+{
12eede
+  grefcount rrc;
12eede
+
12eede
+  g_return_val_if_fail (rc != NULL, FALSE);
12eede
+  g_return_val_if_fail (val >= 0, FALSE);
12eede
+
12eede
+  rrc = *rc;
12eede
+
12eede
+  if (val == G_MAXINT)
12eede
+    return rrc == G_MININT;
12eede
+
12eede
+  return rrc == -val;
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_atomic_ref_count_init:
12eede
+ * @arc: the address of an atomic reference count variable
12eede
+ *
12eede
+ * Atomically initializes a reference count variable.
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+void
12eede
+g_atomic_ref_count_init (gatomicrefcount *arc)
12eede
+{
12eede
+  g_return_if_fail (arc != NULL);
12eede
+
12eede
+  /* Atomic refcounting is implemented using the positive range
12eede
+   * of signed integers:
12eede
+   *
12eede
+   * G_MININT                 Z¯< 0 > Z⁺                G_MAXINT
12eede
+   * |----------------------------|----------------------------|
12eede
+   *
12eede
+   * Acquiring a reference moves us towards MAXINT, and releasing a
12eede
+   * reference moves us towards 0.
12eede
+   */
12eede
+  g_atomic_int_set (arc, 1);
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_atomic_ref_count_inc:
12eede
+ * @arc: the address of an atomic reference count variable
12eede
+ *
12eede
+ * Atomically increases the reference count.
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+void
12eede
+g_atomic_ref_count_inc (gatomicrefcount *arc)
12eede
+{
12eede
+  g_return_if_fail (arc != NULL);
12eede
+  g_return_if_fail (g_atomic_int_get (arc) > 0);
12eede
+
12eede
+  if (g_atomic_int_get (arc) == G_MAXINT)
12eede
+    {
12eede
+      g_critical ("Reference count has reached saturation");
12eede
+      return;
12eede
+    }
12eede
+
12eede
+  g_atomic_int_inc (arc);
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_atomic_ref_count_dec:
12eede
+ * @arc: the address of an atomic reference count variable
12eede
+ *
12eede
+ * Atomically decreases the reference count.
12eede
+ *
12eede
+ * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+gboolean
12eede
+g_atomic_ref_count_dec (gatomicrefcount *arc)
12eede
+{
12eede
+  g_return_val_if_fail (arc != NULL, FALSE);
12eede
+  g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
12eede
+
12eede
+  return g_atomic_int_dec_and_test (arc);
12eede
+}
12eede
+
12eede
+/**
12eede
+ * g_atomic_ref_count_compare:
12eede
+ * @arc: the address of an atomic reference count variable
12eede
+ * @val: the value to compare
12eede
+ *
12eede
+ * Atomically compares the current value of @arc with @val.
12eede
+ *
12eede
+ * Returns: %TRUE if the reference count is the same
12eede
+ *   as the given value
12eede
+ *
12eede
+ * Since: 2.58
12eede
+ */
12eede
+gboolean
12eede
+g_atomic_ref_count_compare (gatomicrefcount *arc,
12eede
+                            gint             val)
12eede
+{
12eede
+  g_return_val_if_fail (arc != NULL, FALSE);
12eede
+  g_return_val_if_fail (val >= 0, FALSE);
12eede
+
12eede
+  return g_atomic_int_get (arc) == val;
12eede
+}
12eede
diff --git a/glib/grefcount.h b/glib/grefcount.h
12eede
new file mode 100644
12eede
index 0000000000..b24c71e8cb
12eede
--- /dev/null
12eede
+++ b/glib/grefcount.h
12eede
@@ -0,0 +1,52 @@
12eede
+/* grefcount.h: Reference counting
12eede
+ *
12eede
+ * Copyright 2018  Emmanuele Bassi
12eede
+ *
12eede
+ * This library is free software; you can redistribute it and/or
12eede
+ * modify it under the terms of the GNU Lesser General Public
12eede
+ * License as published by the Free Software Foundation; either
12eede
+ * version 2.1 of the License, or (at your option) any later version.
12eede
+ *
12eede
+ * This library is distributed in the hope that it will be useful,
12eede
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12eede
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12eede
+ * Lesser General Public License for more details.
12eede
+ *
12eede
+ * You should have received a copy of the GNU Lesser General Public
12eede
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
12eede
+ */
12eede
+
12eede
+#ifndef __GREFCOUNT_H__
12eede
+#define __GREFCOUNT_H__
12eede
+
12eede
+#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
12eede
+#error "Only <glib.h> can be included directly."
12eede
+#endif
12eede
+
12eede
+#include <glib/gtypes.h>
12eede
+
12eede
+G_BEGIN_DECLS
12eede
+
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+void            g_ref_count_init                (grefcount       *rc);
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+void            g_ref_count_inc                 (grefcount       *rc);
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+gboolean        g_ref_count_dec                 (grefcount       *rc);
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+gboolean        g_ref_count_compare             (grefcount       *rc,
12eede
+                                                 gint             val);
12eede
+
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+void            g_atomic_ref_count_init         (gatomicrefcount *arc);
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+void            g_atomic_ref_count_inc          (gatomicrefcount *arc);
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+gboolean        g_atomic_ref_count_dec          (gatomicrefcount *arc);
12eede
+GLIB_AVAILABLE_IN_2_56
12eede
+gboolean        g_atomic_ref_count_compare      (gatomicrefcount *arc,
12eede
+                                                 gint             val);
12eede
+
12eede
+G_END_DECLS
12eede
+
12eede
+#endif /* __GREFCOUNT_H__ */
12eede
diff --git a/glib/gtypes.h b/glib/gtypes.h
12eede
index 09d9bd1456..67adb7f1f8 100644
12eede
--- a/glib/gtypes.h
12eede
+++ b/glib/gtypes.h
12eede
@@ -510,6 +510,9 @@ struct _GTimeVal
12eede
   glong tv_usec;
12eede
 };
12eede
 
12eede
+typedef gint            grefcount;
12eede
+typedef volatile gint   gatomicrefcount;
12eede
+
12eede
 G_END_DECLS
12eede
 
12eede
 /* We prefix variable declarations so they can
12eede
diff --git a/glib/meson.build b/glib/meson.build
12eede
index 036d1f4d60..76d354c2a7 100644
12eede
--- a/glib/meson.build
12eede
+++ b/glib/meson.build
12eede
@@ -76,6 +76,7 @@ glib_sub_headers = files(
12eede
   'gquark.h',
12eede
   'gqueue.h',
12eede
   'grand.h',
12eede
+  'grefcount.h',
12eede
   'gregex.h',
12eede
   'gscanner.h',
12eede
   'gsequence.h',
12eede
@@ -159,6 +160,7 @@ glib_sources = files(
12eede
   'gquark.c',
12eede
   'gqueue.c',
12eede
   'grand.c',
12eede
+  'grefcount.c',
12eede
   'gregex.c',
12eede
   'gscanner.c',
12eede
   'gsequence.c',
12eede
-- 
12eede
GitLab
12eede
12eede
From 827c208cbf9cc0ef17b8c4531a40aafe1edc3f01 Mon Sep 17 00:00:00 2001
12eede
From: Emmanuele Bassi <ebassi@gnome.org>
12eede
Date: Mon, 4 Jun 2018 11:38:40 +0100
12eede
Subject: [PATCH] Use macros for refcount types API
12eede
12eede
If we're using GCC we can use __extension__ to inline the grefcount and
12eede
gatomicrefcount API, and avoid the function call.
12eede
12eede
These macros are only enabled if G_DISABLE_CHECKS is defined, as they
12eede
remove critical warnings when the reference counters achieve saturation.
12eede
---
12eede
 glib/grefcount.c | 20 +++++++-------
12eede
 glib/grefcount.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
12eede
 2 files changed, 80 insertions(+), 10 deletions(-)
12eede
12eede
diff --git a/glib/grefcount.c b/glib/grefcount.c
12eede
index 10e35a217d..37085316b9 100644
12eede
--- a/glib/grefcount.c
12eede
+++ b/glib/grefcount.c
12eede
@@ -89,7 +89,7 @@
12eede
  * Since: 2.58
12eede
  */
12eede
 void
12eede
-g_ref_count_init (grefcount *rc)
12eede
+(g_ref_count_init) (grefcount *rc)
12eede
 {
12eede
   g_return_if_fail (rc != NULL);
12eede
 
12eede
@@ -114,7 +114,7 @@ g_ref_count_init (grefcount *rc)
12eede
  * Since: 2.58
12eede
  */
12eede
 void
12eede
-g_ref_count_inc (grefcount *rc)
12eede
+(g_ref_count_inc) (grefcount *rc)
12eede
 {
12eede
   grefcount rrc;
12eede
 
12eede
@@ -147,7 +147,7 @@ g_ref_count_inc (grefcount *rc)
12eede
  * Since: 2.58
12eede
  */
12eede
 gboolean
12eede
-g_ref_count_dec (grefcount *rc)
12eede
+(g_ref_count_dec) (grefcount *rc)
12eede
 {
12eede
   grefcount rrc;
12eede
 
12eede
@@ -179,8 +179,8 @@ g_ref_count_dec (grefcount *rc)
12eede
  * Since: 2.58
12eede
  */
12eede
 gboolean
12eede
-g_ref_count_compare (grefcount *rc,
12eede
-                     gint       val)
12eede
+(g_ref_count_compare) (grefcount *rc,
12eede
+                       gint       val)
12eede
 {
12eede
   grefcount rrc;
12eede
 
12eede
@@ -204,7 +204,7 @@ g_ref_count_compare (grefcount *rc,
12eede
  * Since: 2.58
12eede
  */
12eede
 void
12eede
-g_atomic_ref_count_init (gatomicrefcount *arc)
12eede
+(g_atomic_ref_count_init) (gatomicrefcount *arc)
12eede
 {
12eede
   g_return_if_fail (arc != NULL);
12eede
 
12eede
@@ -229,7 +229,7 @@ g_atomic_ref_count_init (gatomicrefcount *arc)
12eede
  * Since: 2.58
12eede
  */
12eede
 void
12eede
-g_atomic_ref_count_inc (gatomicrefcount *arc)
12eede
+(g_atomic_ref_count_inc) (gatomicrefcount *arc)
12eede
 {
12eede
   g_return_if_fail (arc != NULL);
12eede
   g_return_if_fail (g_atomic_int_get (arc) > 0);
12eede
@@ -254,7 +254,7 @@ g_atomic_ref_count_inc (gatomicrefcount *arc)
12eede
  * Since: 2.58
12eede
  */
12eede
 gboolean
12eede
-g_atomic_ref_count_dec (gatomicrefcount *arc)
12eede
+(g_atomic_ref_count_dec) (gatomicrefcount *arc)
12eede
 {
12eede
   g_return_val_if_fail (arc != NULL, FALSE);
12eede
   g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
12eede
@@ -275,8 +275,8 @@ g_atomic_ref_count_dec (gatomicrefcount *arc)
12eede
  * Since: 2.58
12eede
  */
12eede
 gboolean
12eede
-g_atomic_ref_count_compare (gatomicrefcount *arc,
12eede
-                            gint             val)
12eede
+(g_atomic_ref_count_compare) (gatomicrefcount *arc,
12eede
+                              gint             val)
12eede
 {
12eede
   g_return_val_if_fail (arc != NULL, FALSE);
12eede
   g_return_val_if_fail (val >= 0, FALSE);
12eede
diff --git a/glib/grefcount.h b/glib/grefcount.h
12eede
index b24c71e8cb..dec9a5ffb8 100644
12eede
--- a/glib/grefcount.h
12eede
+++ b/glib/grefcount.h
12eede
@@ -47,6 +47,76 @@ GLIB_AVAILABLE_IN_2_58
12eede
 gboolean        g_atomic_ref_count_compare      (gatomicrefcount *arc,
12eede
                                                  gint             val);
12eede
 
12eede
+/* On GCC we can use __extension__ to inline the API without using
12eede
+ * ancillary functions; we only do this when disabling checks, as
12eede
+ * it disables warnings when saturating the reference counters
12eede
+ */
12eede
+#if defined(__GNUC__) && defined(G_DISABLE_CHECKS)
12eede
+
12eede
+# define g_ref_count_init(rc) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
12eede
+    (void) (0 ? *(rc) ^ *(rc) : 1); \
12eede
+    *(rc) = -1; \
12eede
+  }))
12eede
+
12eede
+# define g_ref_count_inc(rc) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
12eede
+    (void) (0 ? *(rc) ^ *(rc) : 1); \
12eede
+    if (*(rc) == G_MININT) ; else { \
12eede
+      *(rc) -= 1; \
12eede
+    } \
12eede
+  }))
12eede
+
12eede
+# define g_ref_count_dec(rc) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
12eede
+    grefcount __rc = *(rc); \
12eede
+    __rc += 1; \
12eede
+    if (__rc == 0) ; else { \
12eede
+      *(rc) = __rc; \
12eede
+    } \
12eede
+    (gboolean) (__rc == 0); \
12eede
+  }))
12eede
+
12eede
+# define g_ref_count_compare(rc,val) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
12eede
+    (void) (0 ? *(rc) ^ (val) : 1); \
12eede
+    (gboolean) (*(rc) == -(val)); \
12eede
+  }))
12eede
+
12eede
+# define g_atomic_ref_count_init(rc) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
12eede
+    (void) (0 ? *(rc) ^ *(rc) : 1); \
12eede
+    g_atomic_int_set ((rc), 1); \
12eede
+  }))
12eede
+
12eede
+# define g_atomic_ref_count_inc(rc) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
12eede
+    (void) (0 ? *(rc) ^ *(rc) : 1); \
12eede
+    (void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
12eede
+  }))
12eede
+
12eede
+# define g_atomic_ref_count_dec(rc) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
12eede
+    (void) (0 ? *(rc) ^ *(rc) : 1); \
12eede
+    g_atomic_int_dec_and_test ((rc)); \
12eede
+  }))
12eede
+
12eede
+# define g_atomic_ref_count_compare(rc,val) \
12eede
+  (G_GNUC_EXTENSION ({ \
12eede
+    G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
12eede
+    (void) (0 ? *(rc) ^ (val) : 1); \
12eede
+    (gboolean) (g_atomic_int_get (rc) == (val)); \
12eede
+  }))
12eede
+
12eede
+#endif /* __GNUC__ && G_DISABLE_CHECKS */
12eede
+
12eede
 G_END_DECLS
12eede
 
12eede
 #endif /* __GREFCOUNT_H__ */
12eede
-- 
12eede
GitLab
12eede
12eede
From 09c149453ac969dedb1cb2d15d489d1dd81412bf Mon Sep 17 00:00:00 2001
12eede
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
12eede
Date: Sat, 13 Oct 2018 23:10:33 +0200
12eede
Subject: [PATCH] grefcount: add missing gatomic.h
12eede
MIME-Version: 1.0
12eede
Content-Type: text/plain; charset=UTF-8
12eede
Content-Transfer-Encoding: 8bit
12eede
12eede
Without gatomic.h, build fails on:
12eede
In file included from garcbox.c:24:0:
12eede
garcbox.c: In function ‘g_atomic_rc_box_acquire’:
12eede
grefcount.h:101:13: error: implicit declaration of function ‘g_atomic_int_get’; did you mean ‘__atomic_store’? [-Werror=implicit-function-declaration]
12eede
     (void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
12eede
             ^
12eede
garcbox.c:292:3: note: in expansion of macro ‘g_atomic_ref_count_inc’
12eede
   g_atomic_ref_count_inc (&real_box->ref_count);
12eede
12eede
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
12eede
---
12eede
 glib/grefcount.h | 1 +
12eede
 1 file changed, 1 insertion(+)
12eede
12eede
diff --git a/glib/grefcount.h b/glib/grefcount.h
12eede
index dec9a5ffb8..b6eced1b7d 100644
12eede
--- a/glib/grefcount.h
12eede
+++ b/glib/grefcount.h
12eede
@@ -23,6 +23,7 @@
12eede
 #error "Only <glib.h> can be included directly."
12eede
 #endif
12eede
 
12eede
+#include <glib/gatomic.h>
12eede
 #include <glib/gtypes.h>
12eede
 
12eede
 G_BEGIN_DECLS
12eede
-- 
12eede
GitLab
12eede