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" */
#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
typedef struct
@ -116,7 +133,7 @@ typedef struct
/*< private >*/
guint ref_count; /* (atomic) */
#ifdef HAVE_OPTIONAL_FLAGS
#if HAVE_OPTIONAL_FLAGS_IN_GOBJECT
guint optional_flags; /* (atomic) */
#endif
GData *qdata;
@ -190,9 +207,6 @@ static GQuark quark_closure_array = 0;
static GQuark quark_weak_notifies = 0;
static GQuark quark_toggle_refs = 0;
static GQuark quark_notify_queue;
#ifndef HAVE_OPTIONAL_FLAGS
static GQuark quark_in_construction;
#endif
static GParamSpecPool *pspec_pool = NULL;
static gulong gobject_signals[LAST_SIGNAL] = { 0, };
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);
#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 --- */
static void
g_object_notify_queue_free (gpointer data)
@ -455,6 +487,11 @@ _g_object_type_init (void)
# endif /* G_HAS_CONSTRUCTORS */
}
#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
@ -529,9 +566,6 @@ g_object_do_class_init (GObjectClass *class)
quark_weak_locations = g_quark_from_static_string ("GObject-weak-locations");
quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references");
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 ();
@ -589,6 +623,10 @@ g_object_do_class_init (GObjectClass *class)
* implement an interface implement all properties for that interface
*/
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. */
@ -1183,12 +1221,7 @@ g_object_interface_list_properties (gpointer g_iface,
static inline guint
object_get_optional_flags (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
GObjectReal *real = (GObjectReal *)object;
return (guint)g_atomic_int_get (&real->optional_flags);
#else
return 0;
#endif
return g_atomic_int_get (object_get_optional_flags_p (object));
}
/* Variant of object_get_optional_flags for when
@ -1198,21 +1231,14 @@ object_get_optional_flags (GObject *object)
static inline guint
object_get_optional_flags_X (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
GObjectReal *real = (GObjectReal *)object;
return real->optional_flags;
#else
return 0;
#endif
return *object_get_optional_flags_p (object);
}
#ifdef HAVE_OPTIONAL_FLAGS
static inline void
object_set_optional_flags (GObject *object,
guint flags)
{
GObjectReal *real = (GObjectReal *)object;
g_atomic_int_or (&real->optional_flags, flags);
g_atomic_int_or (object_get_optional_flags_p (object), flags);
}
/* Variant for when we have exclusive access
@ -1222,8 +1248,7 @@ static inline void
object_set_optional_flags_X (GObject *object,
guint flags)
{
GObjectReal *real = (GObjectReal *)object;
real->optional_flags |= flags;
(*object_get_optional_flags_p (object)) |= flags;
}
/* Variant for when we have exclusive access
@ -1233,83 +1258,55 @@ static inline void
object_unset_optional_flags_X (GObject *object,
guint flags)
{
GObjectReal *real = (GObjectReal *)object;
real->optional_flags &= ~flags;
(*object_get_optional_flags_p (object)) &= ~flags;
}
#endif
gboolean
_g_object_has_signal_handler (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
return (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_SIGNAL_HANDLER) != 0;
#else
return TRUE;
#endif
}
static inline gboolean
_g_object_has_notify_handler (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
return CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)) ||
(object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0;
#else
return TRUE;
#endif
}
static inline gboolean
_g_object_has_notify_handler_X (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
return CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object)) ||
(object_get_optional_flags_X (object) & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0;
#else
return TRUE;
#endif
}
void
_g_object_set_has_signal_handler (GObject *object,
guint signal_id)
{
#ifdef HAVE_OPTIONAL_FLAGS
guint flags = OPTIONAL_FLAG_HAS_SIGNAL_HANDLER;
if (signal_id == gobject_signals[NOTIFY])
flags |= OPTIONAL_FLAG_HAS_NOTIFY_HANDLER;
object_set_optional_flags (object, flags);
#endif
}
static inline gboolean
object_in_construction (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
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
set_object_in_construction (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
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
unset_object_in_construction (GObject *object)
{
#ifdef HAVE_OPTIONAL_FLAGS
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
@ -1498,9 +1495,7 @@ static inline void
g_object_notify_by_spec_internal (GObject *object,
GParamSpec *pspec)
{
#ifdef HAVE_OPTIONAL_FLAGS
guint object_flags;
#endif
gboolean needs_notify;
gboolean in_init;
@ -1509,16 +1504,11 @@ g_object_notify_by_spec_internal (GObject *object,
param_spec_follow_override (&pspec);
#ifdef HAVE_OPTIONAL_FLAGS
/* get all flags we need with a single atomic read */
object_flags = object_get_optional_flags (object);
needs_notify = ((object_flags & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0) ||
CLASS_NEEDS_NOTIFY (G_OBJECT_GET_CLASS (object));
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)
{