提交 a6421530 编写于 作者: A Anthony Liguori

Merge remote-tracking branch 'bonzini/qdev-props-for-anthony' into staging

* bonzini/qdev-props-for-anthony: (25 commits)
  qdev: remove unused fields from PropertyInfo
  qdev: initialize properties via QOM
  qdev: inline qdev_prop_set into qdev_prop_set_ptr
  qdev: access properties via QOM
  qdev: fix off-by-one
  qdev: let QOM free properties
  qdev: remove parse/print methods for pointer properties
  qdev: make the non-legacy pci address property accept an integer
  qdev: remove parse/print methods for mac properties
  qdev: remove print/parse methods from LostTickPolicy properties
  qdev: remove parse method for string properties
  qdev: allow reusing get/set for legacy property
  qdev: remove direct calls to print/parse
  qom: add property get/set wrappers for links
  qom: fix canonical paths vs. interfaces
  qom: use object_resolve_path_type for links
  qom: add object_resolve_path_type
  qom: fix off-by-one
  qom: add property get/set wrappers for C types
  qom: add QObject-based property get/set wrappers
  ...
...@@ -61,8 +61,6 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, ...@@ -61,8 +61,6 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_taddr = { PropertyInfo qdev_prop_taddr = {
.name = "taddr", .name = "taddr",
.type = PROP_TYPE_TADDR,
.size = sizeof(target_phys_addr_t),
.parse = parse_taddr, .parse = parse_taddr,
.print = print_taddr, .print = print_taddr,
.get = get_taddr, .get = get_taddr,
...@@ -71,5 +69,8 @@ PropertyInfo qdev_prop_taddr = { ...@@ -71,5 +69,8 @@ PropertyInfo qdev_prop_taddr = {
void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value) void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value)
{ {
qdev_prop_set(dev, name, &value, PROP_TYPE_TADDR); Error *errp = NULL;
object_property_set_int(OBJECT(dev), value, name, &errp);
assert(!errp);
} }
...@@ -485,22 +485,26 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent); ...@@ -485,22 +485,26 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent);
static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
const char *prefix, int indent) const char *prefix, int indent)
{ {
char buf[64];
if (!props) if (!props)
return; return;
while (props->name) { for (; props->name; props++) {
/* Error *err = NULL;
* TODO Properties without a print method are just for dirty char *value;
* hacks. qdev_prop_ptr is the only such PropertyInfo. It's char *legacy_name = g_strdup_printf("legacy-%s", props->name);
* marked for removal. The test props->info->print should be if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
* removed along with it. value = object_property_get_str(OBJECT(dev), legacy_name, &err);
*/ } else {
if (props->info->print) { value = object_property_get_str(OBJECT(dev), props->name, &err);
props->info->print(dev, props, buf, sizeof(buf)); }
qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); g_free(legacy_name);
if (err) {
error_free(err);
continue;
} }
props++; qdev_printf("%s-prop: %s = %s\n", prefix, props->name,
value && *value ? value : "<null>");
g_free(value);
} }
} }
......
此差异已折叠。
...@@ -86,11 +86,11 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus) ...@@ -86,11 +86,11 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
dev->parent_bus = bus; dev->parent_bus = bus;
QTAILQ_INSERT_HEAD(&bus->children, dev, sibling); QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) { for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
qdev_property_add_legacy(dev, prop, NULL); qdev_property_add_legacy(dev, prop, NULL);
qdev_property_add_static(dev, prop, NULL); qdev_property_add_static(dev, prop, NULL);
} }
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
} }
/* Create a new device. This only initializes the device state structure /* Create a new device. This only initializes the device state structure
...@@ -550,21 +550,24 @@ static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque, ...@@ -550,21 +550,24 @@ static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
* Do not use this is new code! Properties added through this interface will * Do not use this is new code! Properties added through this interface will
* be given names and types in the "legacy" namespace. * be given names and types in the "legacy" namespace.
* *
* Legacy properties are always processed as strings. The format of the string * Legacy properties are string versions of other OOM properties. The format
* depends on the property type. * of the string depends on the property type.
*/ */
void qdev_property_add_legacy(DeviceState *dev, Property *prop, void qdev_property_add_legacy(DeviceState *dev, Property *prop,
Error **errp) Error **errp)
{ {
gchar *name, *type; gchar *name, *type;
if (!prop->info->print && !prop->info->parse) {
return;
}
name = g_strdup_printf("legacy-%s", prop->name); name = g_strdup_printf("legacy-%s", prop->name);
type = g_strdup_printf("legacy<%s>", type = g_strdup_printf("legacy<%s>",
prop->info->legacy_name ?: prop->info->name); prop->info->legacy_name ?: prop->info->name);
object_property_add(OBJECT(dev), name, type, object_property_add(OBJECT(dev), name, type,
prop->info->print ? qdev_get_legacy_property : NULL, prop->info->print ? qdev_get_legacy_property : prop->info->get,
prop->info->parse ? qdev_set_legacy_property : NULL, prop->info->parse ? qdev_set_legacy_property : prop->info->set,
NULL, NULL,
prop, errp); prop, errp);
...@@ -581,9 +584,18 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop, ...@@ -581,9 +584,18 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
void qdev_property_add_static(DeviceState *dev, Property *prop, void qdev_property_add_static(DeviceState *dev, Property *prop,
Error **errp) Error **errp)
{ {
/*
* TODO qdev_prop_ptr does not have getters or setters. It must
* go now that it can be replaced with links. The test should be
* removed along with it: all static properties are read/write.
*/
if (!prop->info->get && !prop->info->set) {
return;
}
object_property_add(OBJECT(dev), prop->name, prop->info->name, object_property_add(OBJECT(dev), prop->name, prop->info->name,
prop->info->get, prop->info->set, prop->info->get, prop->info->set,
NULL, prop->info->release,
prop, errp); prop, errp);
} }
...@@ -600,13 +612,13 @@ static void device_initfn(Object *obj) ...@@ -600,13 +612,13 @@ static void device_initfn(Object *obj)
dev->instance_id_alias = -1; dev->instance_id_alias = -1;
dev->state = DEV_STATE_CREATED; dev->state = DEV_STATE_CREATED;
qdev_prop_set_defaults(dev, qdev_get_props(dev));
for (prop = qdev_get_props(dev); prop && prop->name; prop++) { for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
qdev_property_add_legacy(dev, prop, NULL); qdev_property_add_legacy(dev, prop, NULL);
qdev_property_add_static(dev, prop, NULL); qdev_property_add_static(dev, prop, NULL);
} }
object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL); object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
qdev_prop_set_defaults(dev, qdev_get_props(dev));
} }
/* Unlink device from bus and free the structure. */ /* Unlink device from bus and free the structure. */
...@@ -614,7 +626,6 @@ static void device_finalize(Object *obj) ...@@ -614,7 +626,6 @@ static void device_finalize(Object *obj)
{ {
DeviceState *dev = DEVICE(obj); DeviceState *dev = DEVICE(obj);
BusState *bus; BusState *bus;
Property *prop;
DeviceClass *dc = DEVICE_GET_CLASS(dev); DeviceClass *dc = DEVICE_GET_CLASS(dev);
if (dev->state == DEV_STATE_INITIALIZED) { if (dev->state == DEV_STATE_INITIALIZED) {
...@@ -633,11 +644,6 @@ static void device_finalize(Object *obj) ...@@ -633,11 +644,6 @@ static void device_finalize(Object *obj)
} }
} }
QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling); QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
if (prop->info->free) {
prop->info->free(dev, prop);
}
}
} }
void device_reset(DeviceState *dev) void device_reset(DeviceState *dev)
......
...@@ -112,41 +112,22 @@ struct Property { ...@@ -112,41 +112,22 @@ struct Property {
const char *name; const char *name;
PropertyInfo *info; PropertyInfo *info;
int offset; int offset;
int bitnr; uint8_t bitnr;
void *defval; uint8_t qtype;
}; int64_t defval;
enum PropertyType {
PROP_TYPE_UNSPEC = 0,
PROP_TYPE_UINT8,
PROP_TYPE_UINT16,
PROP_TYPE_UINT32,
PROP_TYPE_INT32,
PROP_TYPE_UINT64,
PROP_TYPE_TADDR,
PROP_TYPE_MACADDR,
PROP_TYPE_LOSTTICKPOLICY,
PROP_TYPE_DRIVE,
PROP_TYPE_CHR,
PROP_TYPE_STRING,
PROP_TYPE_NETDEV,
PROP_TYPE_VLAN,
PROP_TYPE_PTR,
PROP_TYPE_BIT,
}; };
struct PropertyInfo { struct PropertyInfo {
const char *name; const char *name;
const char *legacy_name; const char *legacy_name;
size_t size; const char **enum_table;
enum PropertyType type;
int64_t min; int64_t min;
int64_t max; int64_t max;
int (*parse)(DeviceState *dev, Property *prop, const char *str); int (*parse)(DeviceState *dev, Property *prop, const char *str);
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
void (*free)(DeviceState *dev, Property *prop);
ObjectPropertyAccessor *get; ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set; ObjectPropertyAccessor *set;
ObjectPropertyRelease *release;
}; };
typedef struct GlobalProperty { typedef struct GlobalProperty {
...@@ -254,7 +235,8 @@ extern PropertyInfo qdev_prop_pci_devfn; ...@@ -254,7 +235,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
.info = &(_prop), \ .info = &(_prop), \
.offset = offsetof(_state, _field) \ .offset = offsetof(_state, _field) \
+ type_check(_type,typeof_field(_state, _field)), \ + type_check(_type,typeof_field(_state, _field)), \
.defval = (_type[]) { _defval }, \ .qtype = QTYPE_QINT, \
.defval = (_type)_defval, \
} }
#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \ #define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \
.name = (_name), \ .name = (_name), \
...@@ -262,7 +244,8 @@ extern PropertyInfo qdev_prop_pci_devfn; ...@@ -262,7 +244,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
.bitnr = (_bit), \ .bitnr = (_bit), \
.offset = offsetof(_state, _field) \ .offset = offsetof(_state, _field) \
+ type_check(uint32_t,typeof_field(_state, _field)), \ + type_check(uint32_t,typeof_field(_state, _field)), \
.defval = (bool[]) { (_defval) }, \ .qtype = QTYPE_QBOOL, \
.defval = (bool)_defval, \
} }
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ #define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
...@@ -309,7 +292,6 @@ extern PropertyInfo qdev_prop_pci_devfn; ...@@ -309,7 +292,6 @@ extern PropertyInfo qdev_prop_pci_devfn;
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
int qdev_prop_exists(DeviceState *dev, const char *name); int qdev_prop_exists(DeviceState *dev, const char *name);
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type);
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
...@@ -323,8 +305,7 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value); ...@@ -323,8 +305,7 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name, void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
LostTickPolicy *value);
/* FIXME: Remove opaque pointer properties. */ /* FIXME: Remove opaque pointer properties. */
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
void qdev_prop_set_defaults(DeviceState *dev, Property *props); void qdev_prop_set_defaults(DeviceState *dev, Property *props);
......
...@@ -55,6 +55,9 @@ typedef struct InterfaceInfo InterfaceInfo; ...@@ -55,6 +55,9 @@ typedef struct InterfaceInfo InterfaceInfo;
* *
* #define TYPE_MY_DEVICE "my-device" * #define TYPE_MY_DEVICE "my-device"
* *
* // No new virtual functions: we can reuse the typedef for the
* // superclass.
* typedef DeviceClass MyDeviceClass;
* typedef struct MyDevice * typedef struct MyDevice
* { * {
* DeviceState parent; * DeviceState parent;
...@@ -88,8 +91,21 @@ typedef struct InterfaceInfo InterfaceInfo; ...@@ -88,8 +91,21 @@ typedef struct InterfaceInfo InterfaceInfo;
* *
* Using object_new(), a new #Object derivative will be instantiated. You can * Using object_new(), a new #Object derivative will be instantiated. You can
* cast an #Object to a subclass (or base-class) type using * cast an #Object to a subclass (or base-class) type using
* object_dynamic_cast(). You typically want to define a macro wrapper around * object_dynamic_cast(). You typically want to define macro wrappers around
* object_dynamic_cast_assert() to make it easier to convert to a specific type. * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
* specific type:
*
* <example>
* <title>Typecasting macros</title>
* <programlisting>
* #define MY_DEVICE_GET_CLASS(obj) \
* OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
* #define MY_DEVICE_CLASS(klass) \
* OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
* #define MY_DEVICE(obj) \
* OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
* </programlisting>
* </example>
* *
* # Class Initialization # * # Class Initialization #
* *
...@@ -108,7 +124,61 @@ typedef struct InterfaceInfo InterfaceInfo; ...@@ -108,7 +124,61 @@ typedef struct InterfaceInfo InterfaceInfo;
* *
* Once all of the parent classes have been initialized, #TypeInfo::class_init * Once all of the parent classes have been initialized, #TypeInfo::class_init
* is called to let the class being instantiated provide default initialize for * is called to let the class being instantiated provide default initialize for
* it's virtual functions. * it's virtual functions. Here is how the above example might be modified
* to introduce an overridden virtual function:
*
* <example>
* <title>Overriding a virtual function</title>
* <programlisting>
* #include "qdev.h"
*
* void my_device_class_init(ObjectClass *klass, void *class_data)
* {
* DeviceClass *dc = DEVICE_CLASS(klass);
* dc->reset = my_device_reset;
* }
*
* static TypeInfo my_device_info = {
* .name = TYPE_MY_DEVICE,
* .parent = TYPE_DEVICE,
* .instance_size = sizeof(MyDevice),
* .class_init = my_device_class_init,
* };
* </programlisting>
* </example>
*
* Introducing new virtual functions requires a class to define its own
* struct and to add a .class_size member to the TypeInfo. Each function
* will also have a wrapper to call it easily:
*
* <example>
* <title>Defining an abstract class</title>
* <programlisting>
* #include "qdev.h"
*
* typedef struct MyDeviceClass
* {
* DeviceClass parent;
*
* void (*frobnicate) (MyDevice *obj);
* } MyDeviceClass;
*
* static TypeInfo my_device_info = {
* .name = TYPE_MY_DEVICE,
* .parent = TYPE_DEVICE,
* .instance_size = sizeof(MyDevice),
* .abstract = true, // or set a default in my_device_class_init
* .class_size = sizeof(MyDeviceClass),
* };
*
* void my_device_frobnicate(MyDevice *obj)
* {
* MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj);
*
* klass->frobnicate(obj);
* }
* </programlisting>
* </example>
* *
* # Interfaces # * # Interfaces #
* *
...@@ -258,6 +328,16 @@ struct TypeInfo ...@@ -258,6 +328,16 @@ struct TypeInfo
#define OBJECT(obj) \ #define OBJECT(obj) \
((Object *)(obj)) ((Object *)(obj))
/**
* OBJECT_CLASS:
* @class: A derivative of #ObjectClas.
*
* Converts a class to an #ObjectClass. Since all objects are #Objects,
* this function will always succeed.
*/
#define OBJECT_CLASS(class) \
((ObjectClass *)(class))
/** /**
* OBJECT_CHECK: * OBJECT_CHECK:
* @type: The C type to use for the return value. * @type: The C type to use for the return value.
...@@ -272,7 +352,7 @@ struct TypeInfo ...@@ -272,7 +352,7 @@ struct TypeInfo
* generated. * generated.
*/ */
#define OBJECT_CHECK(type, obj, name) \ #define OBJECT_CHECK(type, obj, name) \
((type *)object_dynamic_cast_assert((Object *)(obj), (name))) ((type *)object_dynamic_cast_assert(OBJECT(obj), (name)))
/** /**
* OBJECT_CLASS_CHECK: * OBJECT_CLASS_CHECK:
...@@ -280,11 +360,12 @@ struct TypeInfo ...@@ -280,11 +360,12 @@ struct TypeInfo
* @obj: A derivative of @type to cast. * @obj: A derivative of @type to cast.
* @name: the QOM typename of @class. * @name: the QOM typename of @class.
* *
* A type safe version of @object_check_class. This macro is typically wrapped * A type safe version of @object_class_dynamic_cast_assert. This macro is
* by each type to perform type safe casts of a class to a specific class type. * typically wrapped by each type to perform type safe casts of a class to a
* specific class type.
*/ */
#define OBJECT_CLASS_CHECK(class, obj, name) \ #define OBJECT_CLASS_CHECK(class, obj, name) \
((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name))) ((class *)object_class_dynamic_cast_assert(OBJECT_CLASS(obj), (name)))
/** /**
* OBJECT_GET_CLASS: * OBJECT_GET_CLASS:
...@@ -299,9 +380,6 @@ struct TypeInfo ...@@ -299,9 +380,6 @@ struct TypeInfo
#define OBJECT_GET_CLASS(class, obj, name) \ #define OBJECT_GET_CLASS(class, obj, name) \
OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name) OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
#define OBJECT_CLASS(class) \
((ObjectClass *)(class))
/** /**
* InterfaceClass: * InterfaceClass:
* @parent_class: the base class * @parent_class: the base class
...@@ -543,6 +621,100 @@ void object_unparent(Object *obj); ...@@ -543,6 +621,100 @@ void object_unparent(Object *obj);
void object_property_get(Object *obj, struct Visitor *v, const char *name, void object_property_get(Object *obj, struct Visitor *v, const char *name,
struct Error **errp); struct Error **errp);
/**
* object_property_set_str:
* @value: the value to be written to the property
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Writes a string value to a property.
*/
void object_property_set_str(Object *obj, const char *value,
const char *name, struct Error **errp);
/**
* object_property_get_str:
* @obj: the object
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Returns: the value of the property, converted to a C string, or NULL if
* an error occurs (including when the property value is not a string).
* The caller should free the string.
*/
char *object_property_get_str(Object *obj, const char *name,
struct Error **errp);
/**
* object_property_set_link:
* @value: the value to be written to the property
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Writes an object's canonical path to a property.
*/
void object_property_set_link(Object *obj, Object *value,
const char *name, struct Error **errp);
/**
* object_property_get_link:
* @obj: the object
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Returns: the value of the property, resolved from a path to an Object,
* or NULL if an error occurs (including when the property value is not a
* string or not a valid object path).
*/
Object *object_property_get_link(Object *obj, const char *name,
struct Error **errp);
/**
* object_property_set_bool:
* @value: the value to be written to the property
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Writes a bool value to a property.
*/
void object_property_set_bool(Object *obj, bool value,
const char *name, struct Error **errp);
/**
* object_property_get_bool:
* @obj: the object
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Returns: the value of the property, converted to a boolean, or NULL if
* an error occurs (including when the property value is not a bool).
*/
bool object_property_get_bool(Object *obj, const char *name,
struct Error **errp);
/**
* object_property_set_int:
* @value: the value to be written to the property
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Writes an integer value to a property.
*/
void object_property_set_int(Object *obj, int64_t value,
const char *name, struct Error **errp);
/**
* object_property_get_int:
* @obj: the object
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Returns: the value of the property, converted to an integer, or NULL if
* an error occurs (including when the property value is not an integer).
*/
int64_t object_property_get_int(Object *obj, const char *name,
struct Error **errp);
/** /**
* object_property_set: * object_property_set:
* @obj: the object * @obj: the object
...@@ -601,13 +773,34 @@ gchar *object_get_canonical_path(Object *obj); ...@@ -601,13 +773,34 @@ gchar *object_get_canonical_path(Object *obj);
* specifying objects easy. At each level of the composition tree, the partial * specifying objects easy. At each level of the composition tree, the partial
* path is matched as an absolute path. The first match is not returned. At * path is matched as an absolute path. The first match is not returned. At
* least two matches are searched for. A successful result is only returned if * least two matches are searched for. A successful result is only returned if
* only one match is founded. If more than one match is found, a flag is * only one match is found. If more than one match is found, a flag is
* return to indicate that the match was ambiguous. * returned to indicate that the match was ambiguous.
* *
* Returns: The matched object or NULL on path lookup failure. * Returns: The matched object or NULL on path lookup failure.
*/ */
Object *object_resolve_path(const char *path, bool *ambiguous); Object *object_resolve_path(const char *path, bool *ambiguous);
/**
* object_resolve_path_type:
* @path: the path to resolve
* @typename: the type to look for.
* @ambiguous: returns true if the path resolution failed because of an
* ambiguous match
*
* This is similar to object_resolve_path. However, when looking for a
* partial path only matches that implement the given type are considered.
* This restricts the search and avoids spuriously flagging matches as
* ambiguous.
*
* For both partial and absolute paths, the return value goes through
* a dynamic cast to @typename. This is important if either the link,
* or the typename itself are of interface types.
*
* Returns: The matched object or NULL on path lookup failure.
*/
Object *object_resolve_path_type(const char *path, const char *typename,
bool *ambiguous);
/** /**
* object_property_add_child: * object_property_add_child:
* @obj: the object to add a property to * @obj: the object to add a property to
......
/*
* QEMU Object Model - QObject wrappers
*
* Copyright (C) 2012 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_QOM_QOBJECT_H
#define QEMU_QOM_QOBJECT_H
#include "qemu/object.h"
/*
* object_property_get_qobject:
* @obj: the object
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Returns: the value of the property, converted to QObject, or NULL if
* an error occurs.
*/
struct QObject *object_property_get_qobject(Object *obj, const char *name,
struct Error **errp);
/**
* object_property_set_qobject:
* @obj: the object
* @ret: The value that will be written to the property.
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Writes a property to a object.
*/
void object_property_set_qobject(Object *obj, struct QObject *qobj,
const char *name, struct Error **errp);
#endif
...@@ -255,6 +255,7 @@ typedef enum LostTickPolicy { ...@@ -255,6 +255,7 @@ typedef enum LostTickPolicy {
LOST_TICK_DELAY, LOST_TICK_DELAY,
LOST_TICK_MERGE, LOST_TICK_MERGE,
LOST_TICK_SLEW, LOST_TICK_SLEW,
LOST_TICK_MAX
} LostTickPolicy; } LostTickPolicy;
void tcg_exec_init(unsigned long tb_size); void tcg_exec_init(unsigned long tb_size);
......
...@@ -47,6 +47,10 @@ static const QErrorStringTable qerror_table[] = { ...@@ -47,6 +47,10 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_ADD_CLIENT_FAILED, .error_fmt = QERR_ADD_CLIENT_FAILED,
.desc = "Could not add client", .desc = "Could not add client",
}, },
{
.error_fmt = QERR_AMBIGUOUS_PATH,
.desc = "Path '%(path)' does not uniquely identify a %(object)"
},
{ {
.error_fmt = QERR_BAD_BUS_FOR_DEVICE, .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus", .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
......
...@@ -54,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj); ...@@ -54,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_ADD_CLIENT_FAILED \ #define QERR_ADD_CLIENT_FAILED \
"{ 'class': 'AddClientFailed', 'data': {} }" "{ 'class': 'AddClientFailed', 'data': {} }"
#define QERR_AMBIGUOUS_PATH \
"{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
#define QERR_BAD_BUS_FOR_DEVICE \ #define QERR_BAD_BUS_FOR_DEVICE \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
......
...@@ -21,9 +21,8 @@ ...@@ -21,9 +21,8 @@
#include "kvm.h" #include "kvm.h"
#include "arch_init.h" #include "arch_init.h"
#include "hw/qdev.h" #include "hw/qdev.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h"
#include "blockdev.h" #include "blockdev.h"
#include "qemu/qom-qobject.h"
NameInfo *qmp_query_name(Error **errp) NameInfo *qmp_query_name(Error **errp)
{ {
...@@ -198,7 +197,6 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret) ...@@ -198,7 +197,6 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
const char *property = qdict_get_str(qdict, "property"); const char *property = qdict_get_str(qdict, "property");
QObject *value = qdict_get(qdict, "value"); QObject *value = qdict_get(qdict, "value");
Error *local_err = NULL; Error *local_err = NULL;
QmpInputVisitor *mi;
Object *obj; Object *obj;
obj = object_resolve_path(path, NULL); obj = object_resolve_path(path, NULL);
...@@ -207,10 +205,7 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret) ...@@ -207,10 +205,7 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
goto out; goto out;
} }
mi = qmp_input_visitor_new(value); object_property_set_qobject(obj, value, property, &local_err);
object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
qmp_input_visitor_cleanup(mi);
out: out:
if (local_err) { if (local_err) {
...@@ -227,7 +222,6 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret) ...@@ -227,7 +222,6 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
const char *path = qdict_get_str(qdict, "path"); const char *path = qdict_get_str(qdict, "path");
const char *property = qdict_get_str(qdict, "property"); const char *property = qdict_get_str(qdict, "property");
Error *local_err = NULL; Error *local_err = NULL;
QmpOutputVisitor *mo;
Object *obj; Object *obj;
obj = object_resolve_path(path, NULL); obj = object_resolve_path(path, NULL);
...@@ -236,13 +230,7 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret) ...@@ -236,13 +230,7 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
goto out; goto out;
} }
mo = qmp_output_visitor_new(); *ret = object_property_get_qobject(obj, property, &local_err);
object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
if (!local_err) {
*ret = qmp_output_get_qobject(mo);
}
qmp_output_visitor_cleanup(mo);
out: out:
if (local_err) { if (local_err) {
......
qom-y = object.o container.o qom-y = object.o container.o qom-qobject.o
...@@ -13,8 +13,14 @@ ...@@ -13,8 +13,14 @@
#include "qemu/object.h" #include "qemu/object.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "qapi/qapi-visit-core.h" #include "qapi/qapi-visit-core.h"
#include "hw/qdev.h"
// FIXME remove above /* TODO: replace QObject with a simpler visitor to avoid a dependency
* of the QOM core on QObject? */
#include "qemu/qom-qobject.h"
#include "qobject.h"
#include "qbool.h"
#include "qint.h"
#include "qstring.h"
#define MAX_INTERFACES 32 #define MAX_INTERFACES 32
...@@ -63,6 +69,8 @@ typedef struct Interface ...@@ -63,6 +69,8 @@ typedef struct Interface
#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE) #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
static Type type_interface;
static GHashTable *type_table_get(void) static GHashTable *type_table_get(void)
{ {
static GHashTable *type_table; static GHashTable *type_table;
...@@ -368,11 +376,9 @@ void object_delete(Object *obj) ...@@ -368,11 +376,9 @@ void object_delete(Object *obj)
g_free(obj); g_free(obj);
} }
static bool object_is_type(Object *obj, const char *typename) static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
{ {
TypeImpl *target_type = type_get_by_name(typename); assert(target_type);
TypeImpl *type = obj->class->type;
GSList *i;
/* Check if typename is a direct ancestor of type */ /* Check if typename is a direct ancestor of type */
while (type) { while (type) {
...@@ -383,24 +389,45 @@ static bool object_is_type(Object *obj, const char *typename) ...@@ -383,24 +389,45 @@ static bool object_is_type(Object *obj, const char *typename)
type = type_get_parent(type); type = type_get_parent(type);
} }
/* Check if obj has an interface of typename */
for (i = obj->interfaces; i; i = i->next) {
Interface *iface = i->data;
if (object_is_type(OBJECT(iface), typename)) {
return true;
}
}
return false; return false;
} }
static bool object_is_type(Object *obj, TypeImpl *target_type)
{
return !target_type || type_is_ancestor(obj->class->type, target_type);
}
Object *object_dynamic_cast(Object *obj, const char *typename) Object *object_dynamic_cast(Object *obj, const char *typename)
{ {
TypeImpl *target_type = type_get_by_name(typename);
GSList *i; GSList *i;
/* Check if typename is a direct ancestor */ /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
if (object_is_type(obj, typename)) { * we want to go back from interfaces to the parent.
*/
if (target_type && object_is_type(obj, target_type)) {
return obj;
}
/* Check if obj is an interface and its containing object is a direct
* ancestor of typename. In principle we could do this test at the very
* beginning of object_dynamic_cast, avoiding a second call to
* object_is_type. However, casting between interfaces is relatively
* rare, and object_is_type(obj, type_interface) would fail almost always.
*
* Perhaps we could add a magic value to the object header for increased
* (run-time) type safety and to speed up tests like this one. If we ever
* do that we can revisit the order here.
*/
if (object_is_type(obj, type_interface)) {
assert(!obj->interfaces);
obj = INTERFACE(obj)->obj;
if (object_is_type(obj, target_type)) {
return obj;
}
}
if (!target_type) {
return obj; return obj;
} }
...@@ -408,21 +435,11 @@ Object *object_dynamic_cast(Object *obj, const char *typename) ...@@ -408,21 +435,11 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
for (i = obj->interfaces; i; i = i->next) { for (i = obj->interfaces; i; i = i->next) {
Interface *iface = i->data; Interface *iface = i->data;
if (object_is_type(OBJECT(iface), typename)) { if (object_is_type(OBJECT(iface), target_type)) {
return OBJECT(iface); return OBJECT(iface);
} }
} }
/* Check if obj is an interface and its containing object is a direct
* ancestor of typename */
if (object_is_type(obj, TYPE_INTERFACE)) {
Interface *iface = INTERFACE(obj);
if (object_is_type(iface->obj, typename)) {
return iface->obj;
}
}
return NULL; return NULL;
} }
...@@ -435,7 +452,7 @@ static void register_interface(void) ...@@ -435,7 +452,7 @@ static void register_interface(void)
.abstract = true, .abstract = true,
}; };
type_register_static(&interface_info); type_interface = type_register_static(&interface_info);
} }
device_init(register_interface); device_init(register_interface);
...@@ -648,6 +665,123 @@ void object_property_set(Object *obj, Visitor *v, const char *name, ...@@ -648,6 +665,123 @@ void object_property_set(Object *obj, Visitor *v, const char *name,
} }
} }
void object_property_set_str(Object *obj, const char *value,
const char *name, Error **errp)
{
QString *qstr = qstring_from_str(value);
object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
QDECREF(qstr);
}
char *object_property_get_str(Object *obj, const char *name,
Error **errp)
{
QObject *ret = object_property_get_qobject(obj, name, errp);
QString *qstring;
char *retval;
if (!ret) {
return NULL;
}
qstring = qobject_to_qstring(ret);
if (!qstring) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
retval = NULL;
} else {
retval = g_strdup(qstring_get_str(qstring));
}
QDECREF(qstring);
return retval;
}
void object_property_set_link(Object *obj, Object *value,
const char *name, Error **errp)
{
object_property_set_str(obj, object_get_canonical_path(value),
name, errp);
}
Object *object_property_get_link(Object *obj, const char *name,
Error **errp)
{
char *str = object_property_get_str(obj, name, errp);
Object *target = NULL;
if (str && *str) {
target = object_resolve_path(str, NULL);
if (!target) {
error_set(errp, QERR_DEVICE_NOT_FOUND, str);
}
}
g_free(str);
return target;
}
void object_property_set_bool(Object *obj, bool value,
const char *name, Error **errp)
{
QBool *qbool = qbool_from_int(value);
object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
QDECREF(qbool);
}
bool object_property_get_bool(Object *obj, const char *name,
Error **errp)
{
QObject *ret = object_property_get_qobject(obj, name, errp);
QBool *qbool;
bool retval;
if (!ret) {
return false;
}
qbool = qobject_to_qbool(ret);
if (!qbool) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
retval = false;
} else {
retval = qbool_get_int(qbool);
}
QDECREF(qbool);
return retval;
}
void object_property_set_int(Object *obj, int64_t value,
const char *name, Error **errp)
{
QInt *qint = qint_from_int(value);
object_property_set_qobject(obj, QOBJECT(qint), name, errp);
QDECREF(qint);
}
int64_t object_property_get_int(Object *obj, const char *name,
Error **errp)
{
QObject *ret = object_property_get_qobject(obj, name, errp);
QInt *qint;
int64_t retval;
if (!ret) {
return -1;
}
qint = qobject_to_qint(ret);
if (!qint) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
retval = -1;
} else {
retval = qint_get_int(qint);
}
QDECREF(qint);
return retval;
}
const char *object_property_get_type(Object *obj, const char *name, Error **errp) const char *object_property_get_type(Object *obj, const char *name, Error **errp)
{ {
ObjectProperty *prop = object_property_find(obj, name); ObjectProperty *prop = object_property_find(obj, name);
...@@ -695,6 +829,12 @@ void object_property_add_child(Object *obj, const char *name, ...@@ -695,6 +829,12 @@ void object_property_add_child(Object *obj, const char *name,
{ {
gchar *type; gchar *type;
/* Registering an interface object in the composition tree will mightily
* confuse object_get_canonical_path (which, on the other hand, knows how
* to get the canonical path of an interface object).
*/
assert(!object_is_type(obj, type_interface));
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
object_property_add(obj, name, type, object_get_child_property, object_property_add(obj, name, type, object_get_child_property,
...@@ -730,6 +870,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, ...@@ -730,6 +870,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
bool ambiguous = false; bool ambiguous = false;
const char *type; const char *type;
char *path; char *path;
gchar *target_type;
type = object_property_get_type(obj, name, NULL); type = object_property_get_type(obj, name, NULL);
...@@ -737,31 +878,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, ...@@ -737,31 +878,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
if (*child) { if (*child) {
object_unref(*child); object_unref(*child);
*child = NULL;
} }
if (strcmp(path, "") != 0) { if (strcmp(path, "") != 0) {
Object *target; Object *target;
target = object_resolve_path(path, &ambiguous); /* Go from link<FOO> to FOO. */
if (target) { target_type = g_strndup(&type[5], strlen(type) - 6);
gchar *target_type; target = object_resolve_path_type(path, target_type, &ambiguous);
target_type = g_strdup(&type[5]);
target_type[strlen(target_type) - 2] = 0;
if (object_dynamic_cast(target, target_type)) { if (ambiguous) {
object_ref(target); error_set(errp, QERR_AMBIGUOUS_PATH, path);
*child = target; } else if (target) {
object_ref(target);
*child = target;
} else {
target = object_resolve_path(path, &ambiguous);
if (target || ambiguous) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
} else { } else {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type); error_set(errp, QERR_DEVICE_NOT_FOUND, path);
} }
g_free(target_type);
} else {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
} }
} else { g_free(target_type);
*child = NULL;
} }
g_free(path); g_free(path);
...@@ -788,6 +928,10 @@ gchar *object_get_canonical_path(Object *obj) ...@@ -788,6 +928,10 @@ gchar *object_get_canonical_path(Object *obj)
Object *root = object_get_root(); Object *root = object_get_root();
char *newpath = NULL, *path = NULL; char *newpath = NULL, *path = NULL;
if (object_is_type(obj, type_interface)) {
obj = INTERFACE(obj)->obj;
}
while (obj != root) { while (obj != root) {
ObjectProperty *prop = NULL; ObjectProperty *prop = NULL;
...@@ -823,17 +967,18 @@ gchar *object_get_canonical_path(Object *obj) ...@@ -823,17 +967,18 @@ gchar *object_get_canonical_path(Object *obj)
static Object *object_resolve_abs_path(Object *parent, static Object *object_resolve_abs_path(Object *parent,
gchar **parts, gchar **parts,
const char *typename,
int index) int index)
{ {
ObjectProperty *prop; ObjectProperty *prop;
Object *child; Object *child;
if (parts[index] == NULL) { if (parts[index] == NULL) {
return parent; return object_dynamic_cast(parent, typename);
} }
if (strcmp(parts[index], "") == 0) { if (strcmp(parts[index], "") == 0) {
return object_resolve_abs_path(parent, parts, index + 1); return object_resolve_abs_path(parent, parts, typename, index + 1);
} }
prop = object_property_find(parent, parts[index]); prop = object_property_find(parent, parts[index]);
...@@ -855,17 +1000,18 @@ static Object *object_resolve_abs_path(Object *parent, ...@@ -855,17 +1000,18 @@ static Object *object_resolve_abs_path(Object *parent,
return NULL; return NULL;
} }
return object_resolve_abs_path(child, parts, index + 1); return object_resolve_abs_path(child, parts, typename, index + 1);
} }
static Object *object_resolve_partial_path(Object *parent, static Object *object_resolve_partial_path(Object *parent,
gchar **parts, gchar **parts,
const char *typename,
bool *ambiguous) bool *ambiguous)
{ {
Object *obj; Object *obj;
ObjectProperty *prop; ObjectProperty *prop;
obj = object_resolve_abs_path(parent, parts, 0); obj = object_resolve_abs_path(parent, parts, typename, 0);
QTAILQ_FOREACH(prop, &parent->properties, node) { QTAILQ_FOREACH(prop, &parent->properties, node) {
Object *found; Object *found;
...@@ -874,7 +1020,8 @@ static Object *object_resolve_partial_path(Object *parent, ...@@ -874,7 +1020,8 @@ static Object *object_resolve_partial_path(Object *parent,
continue; continue;
} }
found = object_resolve_partial_path(prop->opaque, parts, ambiguous); found = object_resolve_partial_path(prop->opaque, parts,
typename, ambiguous);
if (found) { if (found) {
if (obj) { if (obj) {
if (ambiguous) { if (ambiguous) {
...@@ -893,7 +1040,8 @@ static Object *object_resolve_partial_path(Object *parent, ...@@ -893,7 +1040,8 @@ static Object *object_resolve_partial_path(Object *parent,
return obj; return obj;
} }
Object *object_resolve_path(const char *path, bool *ambiguous) Object *object_resolve_path_type(const char *path, const char *typename,
bool *ambiguous)
{ {
bool partial_path = true; bool partial_path = true;
Object *obj; Object *obj;
...@@ -913,9 +1061,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous) ...@@ -913,9 +1061,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
if (ambiguous) { if (ambiguous) {
*ambiguous = false; *ambiguous = false;
} }
obj = object_resolve_partial_path(object_get_root(), parts, ambiguous); obj = object_resolve_partial_path(object_get_root(), parts,
typename, ambiguous);
} else { } else {
obj = object_resolve_abs_path(object_get_root(), parts, 1); obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
} }
g_strfreev(parts); g_strfreev(parts);
...@@ -923,14 +1072,19 @@ Object *object_resolve_path(const char *path, bool *ambiguous) ...@@ -923,14 +1072,19 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
return obj; return obj;
} }
Object *object_resolve_path(const char *path, bool *ambiguous)
{
return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
}
typedef struct StringProperty typedef struct StringProperty
{ {
char *(*get)(Object *, Error **); char *(*get)(Object *, Error **);
void (*set)(Object *, const char *, Error **); void (*set)(Object *, const char *, Error **);
} StringProperty; } StringProperty;
static void object_property_get_str(Object *obj, Visitor *v, void *opaque, static void property_get_str(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp) const char *name, Error **errp)
{ {
StringProperty *prop = opaque; StringProperty *prop = opaque;
char *value; char *value;
...@@ -942,8 +1096,8 @@ static void object_property_get_str(Object *obj, Visitor *v, void *opaque, ...@@ -942,8 +1096,8 @@ static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
} }
} }
static void object_property_set_str(Object *obj, Visitor *v, void *opaque, static void property_set_str(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp) const char *name, Error **errp)
{ {
StringProperty *prop = opaque; StringProperty *prop = opaque;
char *value; char *value;
...@@ -959,8 +1113,8 @@ static void object_property_set_str(Object *obj, Visitor *v, void *opaque, ...@@ -959,8 +1113,8 @@ static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
g_free(value); g_free(value);
} }
static void object_property_release_str(Object *obj, const char *name, static void property_release_str(Object *obj, const char *name,
void *opaque) void *opaque)
{ {
StringProperty *prop = opaque; StringProperty *prop = opaque;
g_free(prop); g_free(prop);
...@@ -977,8 +1131,8 @@ void object_property_add_str(Object *obj, const char *name, ...@@ -977,8 +1131,8 @@ void object_property_add_str(Object *obj, const char *name,
prop->set = set; prop->set = set;
object_property_add(obj, name, "string", object_property_add(obj, name, "string",
get ? object_property_get_str : NULL, get ? property_get_str : NULL,
set ? object_property_set_str : NULL, set ? property_set_str : NULL,
object_property_release_str, property_release_str,
prop, errp); prop, errp);
} }
/*
* QEMU Object Model - QObject wrappers
*
* Copyright (C) 2012 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu-common.h"
#include "qemu/object.h"
#include "qemu/qom-qobject.h"
#include "qapi/qapi-visit-core.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h"
void object_property_set_qobject(Object *obj, QObject *value,
const char *name, Error **errp)
{
QmpInputVisitor *mi;
mi = qmp_input_visitor_new(value);
object_property_set(obj, qmp_input_get_visitor(mi), name, errp);
qmp_input_visitor_cleanup(mi);
}
QObject *object_property_get_qobject(Object *obj, const char *name,
Error **errp)
{
QObject *ret = NULL;
Error *local_err = NULL;
QmpOutputVisitor *mo;
mo = qmp_output_visitor_new();
object_property_get(obj, qmp_output_get_visitor(mo), name, &local_err);
if (!local_err) {
ret = qmp_output_get_qobject(mo);
}
error_propagate(errp, local_err);
qmp_output_visitor_cleanup(mo);
return ret;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册