[glib] gtype: Add private DEFINE_TYPE with prelude to workaround gtype deadlocks



commit 017f78d77f0bf2bed749e21199ea89d75e56ab69
Author: Colin Walters <walters verbum org>
Date:   Fri May 19 15:54:39 2017 -0400

    gtype: Add private DEFINE_TYPE with prelude to workaround gtype deadlocks
    
    And use it in GSocket, as it had a real-world case reported.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=674885

 gio/gsocket.c           |   24 +++++++++++++++++-------
 gobject/gtype-private.h |   11 +++++++++++
 gobject/gtype.h         |   16 ++++++++++++++--
 3 files changed, 42 insertions(+), 9 deletions(-)
---
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 2f04055..248074a 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -52,6 +52,9 @@
 #include <sys/uio.h>
 #endif
 
+#define GOBJECT_COMPILATION
+#include "gobject/gtype-private.h" /* For _PRELUDE type define */
+#undef GOBJECT_COMPILATION
 #include "gcancellable.h"
 #include "gdatagrambased.h"
 #include "gioenumtypes.h"
@@ -267,13 +270,20 @@ struct _GSocketPrivate
   } recv_addr_cache[RECV_ADDR_CACHE_SIZE];
 };
 
-G_DEFINE_TYPE_WITH_CODE (GSocket, g_socket, G_TYPE_OBJECT,
-                         G_ADD_PRIVATE (GSocket)
-                        g_networking_init ();
-                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
-                                               g_socket_initable_iface_init);
-                         G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED,
-                                                g_socket_datagram_based_iface_init));
+_G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE (GSocket, g_socket, G_TYPE_OBJECT, 0,
+                                      /* Need a prelude for 
https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
+                                      g_type_ensure (G_TYPE_SOCKET_FAMILY);
+                                      g_type_ensure (G_TYPE_SOCKET_TYPE);
+                                      g_type_ensure (G_TYPE_SOCKET_PROTOCOL);
+                                      g_type_ensure (G_TYPE_SOCKET_ADDRESS);
+                                      /* And networking init is appropriate for the prelude */
+                                      g_networking_init ();
+                                      , /* And now the regular type init code */
+                                      G_ADD_PRIVATE (GSocket)
+                                      G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                             g_socket_initable_iface_init);
+                                      G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED,
+                                                             g_socket_datagram_based_iface_init));
 
 static int
 get_socket_errno (void)
diff --git a/gobject/gtype-private.h b/gobject/gtype-private.h
index 1d05755..5f2f13b 100644
--- a/gobject/gtype-private.h
+++ b/gobject/gtype-private.h
@@ -90,6 +90,17 @@ void        _g_closure_invoke_va (GClosure       *closure,
                                  int             n_params,
                                  GType          *param_types);
 
+/**
+ * _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE:
+ *
+ * See also G_DEFINE_TYPE_EXTENDED().  This macro is generally only
+ * necessary as a workaround for classes which have properties of
+ * object types that may be initialized in distinct threads.  See:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=674885
+ *
+ * Currently private.
+ */
+#define _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE(TN, t_n, T_P, _f_, _P_, _C_)          
_G_DEFINE_TYPE_EXTENDED_BEGIN_PRE (TN, t_n, T_P) {_P_;} _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER (TN, t_n, T_P, 
_f_){_C_;} _G_DEFINE_TYPE_EXTENDED_END()
 
 G_END_DECLS
 
diff --git a/gobject/gtype.h b/gobject/gtype.h
index ab8f97c..89c1bec 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -1943,7 +1943,8 @@ static void     type_name##_class_intern_init (gpointer klass) \
 }
 #endif /* GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38 */
 
-#define _G_DEFINE_TYPE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PARENT, flags) \
+/* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */
+#define _G_DEFINE_TYPE_EXTENDED_BEGIN_PRE(TypeName, type_name, TYPE_PARENT) \
 \
 static void     type_name##_init              (TypeName        *self); \
 static void     type_name##_class_init        (TypeName##Class *klass); \
@@ -1962,7 +1963,11 @@ type_name##_get_instance_private (TypeName *self) \
 GType \
 type_name##_get_type (void) \
 { \
-  static volatile gsize g_define_type_id__volatile = 0; \
+  static volatile gsize g_define_type_id__volatile = 0;
+  /* Prelude goes here */
+
+/* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */
+#define _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \
   if (g_once_init_enter (&g_define_type_id__volatile))  \
     { \
       GType g_define_type_id = \
@@ -1982,6 +1987,13 @@ type_name##_get_type (void) \
   return g_define_type_id__volatile;   \
 } /* closes type_name##_get_type() */
 
+/* This was defined before we had G_DEFINE_TYPE_WITH_CODE_AND_PRELUDE, it's simplest
+ * to keep it.
+ */
+#define _G_DEFINE_TYPE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PARENT, flags) \
+  _G_DEFINE_TYPE_EXTENDED_BEGIN_PRE(TypeName, type_name, TYPE_PARENT) \
+  _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \
+
 #define _G_DEFINE_INTERFACE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PREREQ) \
 \
 static void     type_name##_default_init        (TypeName##Interface *klass); \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]