diff mbox series

[RFC,02/40] qom: Introduce class_late_init

Message ID 20230103181646.55711-3-richard.henderson@linaro.org
State New
Headers show
Series Toward class init of cpu features | expand

Commit Message

Richard Henderson Jan. 3, 2023, 6:16 p.m. UTC
Create a new class initialization hook, to be called immediately
before creation of the first instance.  Most class initialization
happens quite early, which makes interaction between classes
difficult.  E.g. cpu objects often depend on the accellerator,
or the global properties coming from the command-line.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qom/object.h |  4 ++++
 qom/object.c         | 55 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 51 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/include/qom/object.h b/include/qom/object.h
index ef7258a5e1..86958abe15 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -402,6 +402,9 @@  struct Object
  *   parent class initialization has occurred, but before the class itself
  *   is initialized.  This is the function to use to undo the effects of
  *   memcpy from the parent class to the descendants.
+ * @class_late_init: This function is called for all base classes just
+ *   before the first object is created.  This is the function to use to
+ *   apply properties (which are interpreted quite late).
  * @class_data: Data to pass to the @class_init,
  *   @class_base_init. This can be useful when building dynamic
  *   classes.
@@ -425,6 +428,7 @@  struct TypeInfo
 
     void (*class_init)(ObjectClass *klass, void *data);
     void (*class_base_init)(ObjectClass *klass, void *data);
+    bool (*class_late_init)(ObjectClass *klass, Error **errp);
     void *class_data;
 
     InterfaceInfo *interfaces;
diff --git a/qom/object.c b/qom/object.c
index e25f1e96db..82a5c7d36e 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -56,6 +56,7 @@  struct TypeImpl
 
     void (*class_init)(ObjectClass *klass, void *data);
     void (*class_base_init)(ObjectClass *klass, void *data);
+    bool (*class_late_init)(ObjectClass *klass, Error **errp);
 
     void *class_data;
 
@@ -64,6 +65,7 @@  struct TypeImpl
     void (*instance_finalize)(Object *obj);
 
     bool abstract;
+    bool object_created;
 
     const char *parent;
     TypeImpl *parent_type;
@@ -121,6 +123,7 @@  static TypeImpl *type_new(const TypeInfo *info)
 
     ti->class_init = info->class_init;
     ti->class_base_init = info->class_base_init;
+    ti->class_late_init = info->class_late_init;
     ti->class_data = info->class_data;
 
     ti->instance_init = info->instance_init;
@@ -367,6 +370,26 @@  static void type_initialize(TypeImpl *ti)
     }
 }
 
+static bool type_late_initialize(TypeImpl *ti, ObjectClass *cls, Error **errp)
+{
+    TypeImpl *pi = type_get_parent(ti);
+    if (pi && !type_late_initialize(pi, cls, errp)) {
+        return false;
+    }
+
+    for (GSList *e = ti->class->interfaces; e ; e = e->next) {
+        InterfaceClass *ic = e->data;
+        if (!type_late_initialize(ic->interface_type, cls, errp)) {
+            return false;
+        }
+    }
+
+    if (ti->class_late_init) {
+        return ti->class_late_init(cls, errp);
+    }
+    return true;
+}
+
 static void object_init_with_type(Object *obj, TypeImpl *ti)
 {
     if (type_has_parent(ti)) {
@@ -502,7 +525,8 @@  static void object_class_property_init_all(Object *obj)
     }
 }
 
-static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type)
+static bool object_initialize_with_type(Object *obj, size_t size,
+                                        TypeImpl *type, Error **errp)
 {
     type_initialize(type);
 
@@ -510,6 +534,13 @@  static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type
     g_assert(type->abstract == false);
     g_assert(size >= type->instance_size);
 
+    if (!type->object_created) {
+        type->object_created = true;
+        if (!type_late_initialize(type, type->class, errp)) {
+            return false;
+        }
+    }
+
     memset(obj, 0, type->instance_size);
     obj->class = type->class;
     object_ref(obj);
@@ -518,6 +549,7 @@  static void object_initialize_with_type(Object *obj, size_t size, TypeImpl *type
                                             NULL, object_property_free);
     object_init_with_type(obj, type);
     object_post_init_with_type(obj, type);
+    return true;
 }
 
 void object_initialize(void *data, size_t size, const char *typename)
@@ -540,7 +572,7 @@  void object_initialize(void *data, size_t size, const char *typename)
         abort();
     }
 
-    object_initialize_with_type(data, size, type);
+    object_initialize_with_type(data, size, type, &error_fatal);
 }
 
 bool object_initialize_child_with_props(Object *parentobj,
@@ -712,7 +744,7 @@  typedef union {
 } qemu_max_align_t;
 #endif
 
-static Object *object_new_with_type(Type type)
+static Object *object_new_with_type(Type type, Error **errp)
 {
     Object *obj;
     size_t size, align;
@@ -736,22 +768,25 @@  static Object *object_new_with_type(Type type)
         obj_free = qemu_vfree;
     }
 
-    object_initialize_with_type(obj, size, type);
-    obj->free = obj_free;
+    if (!object_initialize_with_type(obj, size, type, errp)) {
+        obj_free(obj);
+        return NULL;
+    }
 
+    obj->free = obj_free;
     return obj;
 }
 
 Object *object_new_with_class(ObjectClass *klass)
 {
-    return object_new_with_type(klass->type);
+    return object_new_with_type(klass->type, &error_fatal);
 }
 
 Object *object_new(const char *typename)
 {
     TypeImpl *ti = type_get_by_name(typename);
 
-    return object_new_with_type(ti);
+    return object_new_with_type(ti, &error_fatal);
 }
 
 
@@ -792,7 +827,11 @@  Object *object_new_with_propv(const char *typename,
         error_setg(errp, "object type '%s' is abstract", typename);
         return NULL;
     }
-    obj = object_new_with_type(klass->type);
+
+    obj = object_new_with_type(klass->type, errp);
+    if (!obj) {
+        return NULL;
+    }
 
     if (!object_set_propv(obj, errp, vargs)) {
         goto error;