gobject: add private data for GObject and use it for optional flags

Add a GObjectPrivate struct and let GObject have private data.

On architectures where we have an alignment gap in GObject struct (64
bit), we use the gap for "optional_flags". Use the private data for
those optional flags, on architectures where we don't have them.

For now, private data is only added for those optional flags (and not on
architectures, where the flags fit inside GObject). In the future, we
may add additional fields there, and add the private struct always.

The main purpose will be to replace all the global locks with per-object
locks, and make "optional_flags" also available on 32bit.
This commit is contained in:
Thomas Haller 2023-12-20 09:00:32 +01:00
parent a12f0731dd
commit 777606d9c4

View File

@ -107,7 +107,24 @@ enum {
#define OPTIONAL_FLAG_HAS_NOTIFY_HANDLER (1 << 2) /* Same, specifically for "notify" */ #define OPTIONAL_FLAG_HAS_NOTIFY_HANDLER (1 << 2) /* Same, specifically for "notify" */
#if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8
#define HAVE_OPTIONAL_FLAGS #define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 1
#else
#define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 0
#endif
/* For now we only create a private struct if we don't have optional flags in
* GObject. Currently we don't need it otherwise. In the future we might
* always add a private struct. */
#define HAVE_PRIVATE (!HAVE_OPTIONAL_FLAGS_IN_GOBJECT)
#if HAVE_PRIVATE
typedef struct {
#if !HAVE_OPTIONAL_FLAGS_IN_GOBJECT
guint optional_flags; /* (atomic) */
#endif
} GObjectPrivate;
static int GObject_private_offset;
#endif #endif
typedef struct typedef struct
@ -116,7 +133,7 @@ typedef struct
/*< private >*/ /*< private >*/
guint ref_count; /* (atomic) */ guint ref_count; /* (atomic) */
#ifdef HAVE_OPTIONAL_FLAGS #if HAVE_OPTIONAL_FLAGS_IN_GOBJECT
guint optional_flags; /* (atomic) */ guint optional_flags; /* (atomic) */
#endif #endif
GData *qdata; GData *qdata;
@ -190,9 +207,6 @@ static GQuark quark_closure_array = 0;
static GQuark quark_weak_notifies = 0; static GQuark quark_weak_notifies = 0;
static GQuark quark_toggle_refs = 0; static GQuark quark_toggle_refs = 0;
static GQuark quark_notify_queue; static GQuark quark_notify_queue;
#ifndef HAVE_OPTIONAL_FLAGS
static GQuark quark_in_construction;
#endif
static GParamSpecPool *pspec_pool = NULL; static GParamSpecPool *pspec_pool = NULL;
static gulong gobject_signals[LAST_SIGNAL] = { 0, }; static gulong gobject_signals[LAST_SIGNAL] = { 0, };
static guint (*floating_flag_handler) (GObject*, gint) = object_floating_flag_handler; static guint (*floating_flag_handler) (GObject*, gint) = object_floating_flag_handler;
@ -202,6 +216,24 @@ static GRWLock weak_locations_lock;
G_LOCK_DEFINE_STATIC(notify_lock); G_LOCK_DEFINE_STATIC(notify_lock);
#if HAVE_PRIVATE
G_ALWAYS_INLINE static inline GObjectPrivate *
g_object_get_instance_private (GObject *object)
{
return G_STRUCT_MEMBER_P (object, GObject_private_offset);
}
#endif
G_ALWAYS_INLINE static inline guint *
object_get_optional_flags_p (GObject *object)
{
#if HAVE_OPTIONAL_FLAGS_IN_GOBJECT
return &(((GObjectReal *) object)->optional_flags);
#else
return &g_object_get_instance_private (object)->optional_flags;
#endif
}
/* --- functions --- */ /* --- functions --- */
static void static void
g_object_notify_queue_free (gpointer data) g_object_notify_queue_free (gpointer data)
@ -455,6 +487,11 @@ _g_object_type_init (void)
# endif /* G_HAS_CONSTRUCTORS */ # endif /* G_HAS_CONSTRUCTORS */
} }
#endif /* G_ENABLE_DEBUG */ #endif /* G_ENABLE_DEBUG */
#if HAVE_PRIVATE
GObject_private_offset =
g_type_add_instance_private (G_TYPE_OBJECT, sizeof (GObjectPrivate));
#endif
} }
/* Initialize the global GParamSpecPool; this function needs to be /* Initialize the global GParamSpecPool; this function needs to be
@ -529,9 +566,6 @@ g_object_do_class_init (GObjectClass *class)
quark_weak_locations = g_quark_from_static_string ("GObject-weak-locations"); quark_weak_locations = g_quark_from_static_string ("GObject-weak-locations");
quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references"); quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references");
quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue");
#ifndef HAVE_OPTIONAL_FLAGS
quark_in_construction = g_quark_from_static_string ("GObject-in-construction");
#endif
g_object_init_pspec_pool (); g_object_init_pspec_pool ();
@ -589,6 +623,10 @@ g_object_do_class_init (GObjectClass *class)
* implement an interface implement all properties for that interface * implement an interface implement all properties for that interface
*/ */
g_type_add_interface_check (NULL, object_interface_check_properties); g_type_add_interface_check (NULL, object_interface_check_properties);
#if HAVE_PRIVATE
g_type_class_adjust_private_offset (class, &GObject_private_offset);
#endif
} }
/* Sinks @pspec if its a floating ref. */ /* Sinks @pspec if its a floating ref. */
@ -1183,12 +1221,7 @@ g_object_interface_list_properties (gpointer g_iface,
static inline guint static inline guint
object_get_optional_flags (GObject *object) object_get_optional_flags (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS return g_atomic_int_get (object_get_optional_flags_p (object));
GObjectReal *real = (GObjectReal *)object;
return (guint)g_atomic_int_get (&real->optional_flags);
#else
return 0;
#endif
} }
/* Variant of object_get_optional_flags for when /* Variant of object_get_optional_flags for when
@ -1198,21 +1231,14 @@ object_get_optional_flags (GObject *object)
static inline guint static inline guint
object_get_optional_flags_X (GObject *object) object_get_optional_flags_X (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS return *object_get_optional_flags_p (object);
GObjectReal *real = (GObjectReal *)object;
return real->optional_flags;
#else
return 0;
#endif
} }
#ifdef HAVE_OPTIONAL_FLAGS
static inline void static inline void
object_set_optional_flags (GObject *object, object_set_optional_flags (GObject *object,
guint flags) guint flags)
{ {
GObjectReal *real = (GObjectReal *)object; g_atomic_int_or (object_get_optional_flags_p (object), flags);
g_atomic_int_or (&real->optional_flags, flags);
} }
/* Variant for when we have exclusive access /* Variant for when we have exclusive access
@ -1222,8 +1248,7 @@ static inline void
object_set_optional_flags_X (GObject *object, object_set_optional_flags_X (GObject *object,
guint flags) guint flags)
{ {
GObjectReal *real = (GObjectReal *)object; (*object_get_optional_flags_p (object)) |= flags;
real->optional_flags |= flags;
} }
/* Variant for when we have exclusive access /* Variant for when we have exclusive access
@ -1233,83 +1258,55 @@ static inline void
object_unset_optional_flags_X (GObject *object, object_unset_optional_flags_X (GObject *object,
guint flags) guint flags)
{ {
GObjectReal *real = (GObjectReal *)object; (*object_get_optional_flags_p (object)) &= ~flags;
real->optional_flags &= ~flags;
} }
#endif
gboolean gboolean
_g_object_has_signal_handler (GObject *object) _g_object_has_signal_handler (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
return (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_SIGNAL_HANDLER) != 0; return (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_SIGNAL_HANDLER) != 0;
#else
return TRUE;
#endif
} }
static inline gboolean static inline gboolean
_g_object_has_notify_handler (GObject *object) _g_object_has_notify_handler (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
return CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)) || return CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)) ||
(object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0; (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0;
#else
return TRUE;
#endif
} }
static inline gboolean static inline gboolean
_g_object_has_notify_handler_X (GObject *object) _g_object_has_notify_handler_X (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
return CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)) || return CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)) ||
(object_get_optional_flags_X (object) & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0; (object_get_optional_flags_X (object) & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0;
#else
return TRUE;
#endif
} }
void void
_g_object_set_has_signal_handler (GObject *object, _g_object_set_has_signal_handler (GObject *object,
guint signal_id) guint signal_id)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
guint flags = OPTIONAL_FLAG_HAS_SIGNAL_HANDLER; guint flags = OPTIONAL_FLAG_HAS_SIGNAL_HANDLER;
if (signal_id == gobject_signals[NOTIFY]) if (signal_id == gobject_signals[NOTIFY])
flags |= OPTIONAL_FLAG_HAS_NOTIFY_HANDLER; flags |= OPTIONAL_FLAG_HAS_NOTIFY_HANDLER;
object_set_optional_flags (object, flags); object_set_optional_flags (object, flags);
#endif
} }
static inline gboolean static inline gboolean
object_in_construction (GObject *object) object_in_construction (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
return (object_get_optional_flags (object) & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0; return (object_get_optional_flags (object) & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0;
#else
return g_datalist_id_get_data (&object->qdata, quark_in_construction) != NULL;
#endif
} }
static inline void static inline void
set_object_in_construction (GObject *object) set_object_in_construction (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
object_set_optional_flags_X (object, OPTIONAL_FLAG_IN_CONSTRUCTION); object_set_optional_flags_X (object, OPTIONAL_FLAG_IN_CONSTRUCTION);
#else
g_datalist_id_set_data (&object->qdata, quark_in_construction, object);
#endif
} }
static inline void static inline void
unset_object_in_construction (GObject *object) unset_object_in_construction (GObject *object)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
object_unset_optional_flags_X (object, OPTIONAL_FLAG_IN_CONSTRUCTION); object_unset_optional_flags_X (object, OPTIONAL_FLAG_IN_CONSTRUCTION);
#else
g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL);
#endif
} }
static void static void
@ -1498,9 +1495,7 @@ static inline void
g_object_notify_by_spec_internal (GObject *object, g_object_notify_by_spec_internal (GObject *object,
GParamSpec *pspec) GParamSpec *pspec)
{ {
#ifdef HAVE_OPTIONAL_FLAGS
guint object_flags; guint object_flags;
#endif
gboolean needs_notify; gboolean needs_notify;
gboolean in_init; gboolean in_init;
@ -1509,16 +1504,11 @@ g_object_notify_by_spec_internal (GObject *object,
param_spec_follow_override (&pspec); param_spec_follow_override (&pspec);
#ifdef HAVE_OPTIONAL_FLAGS
/* get all flags we need with a single atomic read */ /* get all flags we need with a single atomic read */
object_flags = object_get_optional_flags (object); object_flags = object_get_optional_flags (object);
needs_notify = ((object_flags & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0) || needs_notify = ((object_flags & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0) ||
CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)); CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object));
in_init = (object_flags & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0; in_init = (object_flags & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0;
#else
needs_notify = TRUE;
in_init = object_in_construction (object);
#endif
if (pspec != NULL && needs_notify) if (pspec != NULL && needs_notify)
{ {