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
This commit is contained in:
Colin Walters 2017-05-19 15:54:39 -04:00
parent ac0b0c84f7
commit 017f78d77f
3 changed files with 42 additions and 9 deletions

View File

@ -52,6 +52,9 @@
#include <sys/uio.h> #include <sys/uio.h>
#endif #endif
#define GOBJECT_COMPILATION
#include "gobject/gtype-private.h" /* For _PRELUDE type define */
#undef GOBJECT_COMPILATION
#include "gcancellable.h" #include "gcancellable.h"
#include "gdatagrambased.h" #include "gdatagrambased.h"
#include "gioenumtypes.h" #include "gioenumtypes.h"
@ -267,9 +270,16 @@ struct _GSocketPrivate
} recv_addr_cache[RECV_ADDR_CACHE_SIZE]; } recv_addr_cache[RECV_ADDR_CACHE_SIZE];
}; };
G_DEFINE_TYPE_WITH_CODE (GSocket, g_socket, G_TYPE_OBJECT, _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE (GSocket, g_socket, G_TYPE_OBJECT, 0,
G_ADD_PRIVATE (GSocket) /* 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 (); g_networking_init ();
, /* And now the regular type init code */
G_ADD_PRIVATE (GSocket)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_socket_initable_iface_init); g_socket_initable_iface_init);
G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED, G_IMPLEMENT_INTERFACE (G_TYPE_DATAGRAM_BASED,

View File

@ -90,6 +90,17 @@ void _g_closure_invoke_va (GClosure *closure,
int n_params, int n_params,
GType *param_types); 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 G_END_DECLS

View File

@ -1943,7 +1943,8 @@ static void type_name##_class_intern_init (gpointer klass) \
} }
#endif /* GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38 */ #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##_init (TypeName *self); \
static void type_name##_class_init (TypeName##Class *klass); \ static void type_name##_class_init (TypeName##Class *klass); \
@ -1962,7 +1963,11 @@ type_name##_get_instance_private (TypeName *self) \
GType \ GType \
type_name##_get_type (void) \ 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)) \ if (g_once_init_enter (&g_define_type_id__volatile)) \
{ \ { \
GType g_define_type_id = \ GType g_define_type_id = \
@ -1982,6 +1987,13 @@ type_name##_get_type (void) \
return g_define_type_id__volatile; \ return g_define_type_id__volatile; \
} /* closes type_name##_get_type() */ } /* 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) \ #define _G_DEFINE_INTERFACE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PREREQ) \
\ \
static void type_name##_default_init (TypeName##Interface *klass); \ static void type_name##_default_init (TypeName##Interface *klass); \