|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v3 019/114] qom: inherit is_available and filter after MODULE_INIT_QOM
Parents are not all registered at type_register time, so a type
cannot inherit is_available then.
After MODULE_INIT_QOM, and after a late DSO, inherit the callback
from the parent, drop types that fail target_info(), and report a
missing parent. Skip that filter for MODULE_INIT_PHASE_DSO_BEFORE.
The inherit walk colors each type once, so it is O(N) in the number
of types. TYPE_INTERFACE and TYPE_OBJECT use target_is_any().
type_register_static aborts if it runs outside the QOM before/after
hooks.
Signed-off-by: Yonggang Luo <luoyonggang@xxxxxxxxx>
---
include/qemu/target-info.h | 9 +++
qom/object.c | 134 +++++++++++++++++++++++++++++++++++--
target-info.c | 6 ++
3 files changed, 145 insertions(+), 4 deletions(-)
diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h
index 440da63e6cf..790fc74e9d3 100644
--- a/include/qemu/target-info.h
+++ b/include/qemu/target-info.h
@@ -53,6 +53,15 @@ const char *target_cpu_type(void);
*/
bool target_big_endian(void);
+/**
+ * target_is_any:
+ * @ti: TargetInfo to inspect
+ *
+ * Returns true for every TargetInfo. Usable as TypeInfo.is_available
+ * for types that are not target-scoped (TYPE_OBJECT).
+ */
+bool target_is_any(const TargetInfo *ti);
+
/**
* target_is_base_arm:
* @ti: TargetInfo to inspect
diff --git a/qom/object.c b/qom/object.c
index a3e75927e82..d0f9242ac99 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -14,6 +14,7 @@
#include "qapi/error.h"
#include "qom/compat-properties.h"
#include "qom/object.h"
+#include "qemu/module.h"
#include "qom/object_interfaces.h"
#include "qemu/target-info-qapi.h"
#include "qemu/cutils.h"
@@ -40,6 +41,7 @@
#include "qobject/qnum.h"
#include "qobject/qstring.h"
#include "qemu/error-report.h"
+#include "qemu/queue.h"
#define MAX_INTERFACES 32
@@ -81,11 +83,16 @@ struct TypeImpl
int num_interfaces;
InterfaceImpl interfaces[MAX_INTERFACES];
+
+ QTAILQ_ENTRY(TypeImpl) register_node;
};
static Type type_interface;
static GHashTable *type_table;
+static QTAILQ_HEAD(, TypeImpl) type_register_list =
+ QTAILQ_HEAD_INITIALIZER(type_register_list);
+static bool type_qom_registering;
static bool enumerating_types;
@@ -95,6 +102,21 @@ static void type_table_add(TypeImpl *ti)
g_hash_table_insert(type_table, (void *)ti->name, ti);
}
+static void type_table_remove(TypeImpl *ti)
+{
+ int i;
+
+ assert(!enumerating_types);
+ g_hash_table_remove(type_table, (void *)ti->name);
+ QTAILQ_REMOVE(&type_register_list, ti, register_node);
+ g_free((char *)ti->name);
+ g_free((char *)ti->parent);
+ for (i = 0; i < ti->num_interfaces; i++) {
+ g_free((char *)ti->interfaces[i].typename);
+ }
+ g_free(ti);
+}
+
static TypeImpl *type_table_lookup(const char *name)
{
return g_hash_table_lookup(type_table, name);
@@ -171,18 +193,20 @@ static TypeImpl *type_register_internal(const TypeInfo
*info)
abort();
}
- if (info->is_available && !info->is_available(target_info())) {
- return NULL;
- }
-
ti = type_new(info);
type_table_add(ti);
+ QTAILQ_INSERT_TAIL(&type_register_list, ti, register_node);
return ti;
}
TypeImpl *type_register_static(const TypeInfo *info)
{
+ if (!type_qom_registering) {
+ fprintf(stderr, "Registering '%s' outside QOM before/after\n",
+ info->name);
+ abort();
+ }
assert(info->parent);
return type_register_internal(info);
}
@@ -316,6 +340,8 @@ static void type_initialize_interface(TypeImpl *ti,
TypeImpl *interface_type,
iface_impl = type_new(&info);
iface_impl->parent_type = parent_type;
+ g_assert(interface_type->is_available);
+ iface_impl->is_available = interface_type->is_available;
type_initialize(iface_impl);
g_free((char *)info.name);
@@ -1159,6 +1185,7 @@ bool object_class_is_secure(ObjectClass *klass)
TypeIsAvailable *object_class_get_is_available(ObjectClass *klass)
{
+ g_assert(klass->type->is_available);
return klass->type->is_available;
}
@@ -3297,12 +3324,109 @@ static void object_class_init(ObjectClass *klass,
const void *data)
NULL);
}
+static bool type_qom_before(ModuleInitPhase phase, Error **errp)
+{
+ (void)errp;
+ (void)phase;
+
+ type_qom_registering = true;
+ return true;
+}
+
+enum TypeVisitColor {
+ TYPE_VISIT_GRAY = 1,
+ TYPE_VISIT_BLACK,
+};
+
+static bool type_update_is_available(TypeImpl *type, GHashTable *visit,
+ Error **errp)
+{
+ TypeImpl *parent;
+ gpointer color;
+
+ color = g_hash_table_lookup(visit, type);
+ if (color == GINT_TO_POINTER(TYPE_VISIT_BLACK)) {
+ return true;
+ }
+ if (color == GINT_TO_POINTER(TYPE_VISIT_GRAY)) {
+ error_setg(errp, "Type '%s' has a cyclic parent chain",
+ type->name);
+ return false;
+ }
+
+ g_hash_table_insert(visit, type, GINT_TO_POINTER(TYPE_VISIT_GRAY));
+
+ parent = type_get_parent(type);
+ if (!parent) {
+ if (strcmp(type->name, TYPE_OBJECT) != 0 &&
+ strcmp(type->name, TYPE_INTERFACE) != 0) {
+ error_setg(errp,
+ "Type '%s' does not inherit from %s or %s",
+ type->name, TYPE_OBJECT, TYPE_INTERFACE);
+ return false;
+ }
+ } else {
+ if (!type_update_is_available(parent, visit, errp)) {
+ return false;
+ }
+ if (!type->is_available) {
+ type->is_available = parent->is_available;
+ }
+ }
+
+ g_hash_table_insert(visit, type, GINT_TO_POINTER(TYPE_VISIT_BLACK));
+ return true;
+}
+
+static bool type_qom_after(ModuleInitPhase phase, Error **errp)
+{
+ TypeImpl *type, *next;
+ GHashTable *visit;
+ Error *local_err = NULL;
+
+ type_qom_registering = false;
+ if (phase == MODULE_INIT_PHASE_DSO_BEFORE) {
+ return true;
+ }
+
+ visit = g_hash_table_new(NULL, NULL);
+ QTAILQ_FOREACH(type, &type_register_list, register_node) {
+ if (!type_update_is_available(type, visit, &local_err)) {
+ break;
+ }
+ }
+ g_hash_table_destroy(visit);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return false;
+ }
+
+ QTAILQ_FOREACH_SAFE(type, &type_register_list, register_node, next) {
+ g_assert(type->is_available);
+ if (!type->is_available(target_info())) {
+ type_table_remove(type);
+ }
+ }
+
+ QTAILQ_FOREACH(type, &type_register_list, register_node) {
+ if (type->parent && !type_table_lookup(type->parent)) {
+ error_setg(errp, "Type '%s' is missing its parent '%s'",
+ type->name, type->parent);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static void __attribute__((constructor)) register_types(void)
{
static const TypeInfo interface_info = {
.name = TYPE_INTERFACE,
.class_size = sizeof(InterfaceClass),
.abstract = true,
+ .is_available = target_is_any,
};
static const TypeInfo object_info = {
@@ -3310,9 +3434,11 @@ static void __attribute__((constructor))
register_types(void)
.instance_size = sizeof(Object),
.class_init = object_class_init,
.abstract = true,
+ .is_available = target_is_any,
};
type_table = g_hash_table_new(g_str_hash, g_str_equal);
type_interface = type_register_internal(&interface_info);
type_register_internal(&object_info);
+ register_module_hooks(MODULE_INIT_QOM, type_qom_before, type_qom_after);
}
diff --git a/target-info.c b/target-info.c
index 36f75ece36f..a9ab4b465d3 100644
--- a/target-info.c
+++ b/target-info.c
@@ -96,6 +96,12 @@ bool target_big_endian(void)
return target_endian_mode() == ENDIAN_MODE_BIG;
}
+bool target_is_any(const TargetInfo *ti)
+{
+ (void)ti;
+ return true;
+}
+
bool target_is_base_arm(const TargetInfo *ti)
{
switch (ti->target_arch) {
--
2.52.0.windows.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |