qom: move properties from qdev to object

This is mostly code movement although not entirely.  This makes properties part
of the Object base class which means that we can now start using Object in a
meaningful way outside of qdev.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2012-01-30 08:55:55 -06:00
parent 0beb494207
commit 57c9fafe0f
14 changed files with 801 additions and 817 deletions

View File

@ -628,10 +628,10 @@ static void visit_type_int32(Visitor *v, int *value, const char *name, Error **e
visit_type_int(v, &val, name, errp);
}
static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque,
static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
ISADevice *isa = ISA_DEVICE(dev);
ISADevice *isa = ISA_DEVICE(obj);
RTCState *s = DO_UPCAST(RTCState, dev, isa);
visit_start_struct(v, NULL, "struct tm", name, 0, errp);
@ -686,8 +686,8 @@ static int rtc_initfn(ISADevice *dev)
qdev_set_legacy_instance_id(&dev->qdev, base, 2);
qemu_register_reset(rtc_reset, s);
qdev_property_add(&s->dev.qdev, "date", "struct tm",
rtc_get_date, NULL, NULL, s, NULL);
object_property_add(OBJECT(s), "date", "struct tm",
rtc_get_date, NULL, NULL, s, NULL);
return 0;
}

View File

@ -229,7 +229,7 @@ static void pc_init1(MemoryRegion *system_memory,
dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
if (dev) {
qdev_property_add_child(qdev_get_root(), "vga", dev, NULL);
object_property_add_child(object_get_root(), "vga", OBJECT(dev), NULL);
}
if (xen_enabled()) {
@ -267,8 +267,8 @@ static void pc_init1(MemoryRegion *system_memory,
* For now, let's "fix" this by making judicious use of paths. This
* is not generally the right way to do this.
*/
qdev_property_add_child(qdev_resolve_path("/i440fx/piix3", NULL),
"rtc", (DeviceState *)rtc_state, NULL);
object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
"rtc", (Object *)rtc_state, NULL);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;

View File

@ -1517,6 +1517,7 @@ static int pci_unplug_device(DeviceState *qdev)
qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
return -1;
}
object_unparent(OBJECT(dev));
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
PCI_HOTPLUG_DISABLED);
}

View File

@ -277,7 +277,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
address_space_io, 0);
s->bus = b;
qdev_init_nofail(dev);
qdev_property_add_child(qdev_get_root(), "i440fx", dev, NULL);
object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL);
d = pci_create_simple(b, 0, device_name);
*pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
@ -316,7 +316,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
PIIX_NUM_PIRQS);
}
qdev_property_add_child(dev, "piix3", &piix3->dev.qdev, NULL);
object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL);
piix3->pic = pic;
*isa_bus = DO_UPCAST(ISABus, qbus,
qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));

View File

@ -610,7 +610,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
pcihost = DO_UPCAST(PCIHostState, busdev, sys);
pcihost->address_space = get_system_memory();
qdev_init_nofail(dev);
qdev_property_add_child(qdev_get_root(), "raven", DEVICE(dev), NULL);
object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (pci_bus == NULL) {
fprintf(stderr, "Couldn't create PCI host controller.\n");

View File

@ -18,9 +18,10 @@ static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
}
static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
static void get_taddr(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@ -29,9 +30,10 @@ static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
static void set_taddr(DeviceState *dev, Visitor *v, void *opaque,
static void set_taddr(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;

View File

@ -173,30 +173,32 @@ int qdev_device_help(QemuOpts *opts)
return 1;
}
static DeviceState *qdev_get_peripheral(void)
static Object *qdev_get_peripheral(void)
{
static DeviceState *dev;
if (dev == NULL) {
dev = qdev_create(NULL, "container");
qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
object_property_add_child(object_get_root(), "peripheral",
OBJECT(dev), NULL);
qdev_init_nofail(dev);
}
return dev;
return OBJECT(dev);
}
static DeviceState *qdev_get_peripheral_anon(void)
static Object *qdev_get_peripheral_anon(void)
{
static DeviceState *dev;
if (dev == NULL) {
dev = qdev_create(NULL, "container");
qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
object_property_add_child(object_get_root(), "peripheral-anon",
OBJECT(dev), NULL);
qdev_init_nofail(dev);
}
return dev;
return OBJECT(dev);
}
static void qbus_list_bus(DeviceState *dev)
@ -455,12 +457,13 @@ DeviceState *qdev_device_add(QemuOpts *opts)
id = qemu_opts_id(opts);
if (id) {
qdev->id = id;
qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
object_property_add_child(qdev_get_peripheral(), qdev->id,
OBJECT(qdev), NULL);
} else {
static int anon_count;
gchar *name = g_strdup_printf("device[%d]", anon_count++);
qdev_property_add_child(qdev_get_peripheral_anon(), name,
qdev, NULL);
object_property_add_child(qdev_get_peripheral_anon(), name,
OBJECT(qdev), NULL);
g_free(name);
}
if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {

View File

@ -55,9 +55,10 @@ static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
}
static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
static void get_bit(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *p = qdev_get_prop_ptr(dev, prop);
bool value = (*p & qdev_get_prop_mask(prop)) != 0;
@ -65,9 +66,10 @@ static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
visit_type_bool(v, &value, name, errp);
}
static void set_bit(DeviceState *dev, Visitor *v, void *opaque,
static void set_bit(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
bool value;
@ -118,9 +120,10 @@ static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, "%" PRIu8, *ptr);
}
static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
static void get_int8(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@ -129,9 +132,10 @@ static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
static void set_int8(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
static void set_int8(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@ -224,9 +228,10 @@ static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu16, *ptr);
}
static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
static void get_int16(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@ -235,9 +240,10 @@ static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
static void set_int16(DeviceState *dev, Visitor *v, void *opaque,
static void set_int16(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@ -296,9 +302,10 @@ static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu32, *ptr);
}
static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
static void get_int32(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@ -307,9 +314,10 @@ static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
static void set_int32(DeviceState *dev, Visitor *v, void *opaque,
static void set_int32(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@ -433,18 +441,20 @@ static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu64, *ptr);
}
static void get_int64(DeviceState *dev, Visitor *v, void *opaque,
static void get_int64(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
visit_type_int(v, ptr, name, errp);
}
static void set_int64(DeviceState *dev, Visitor *v, void *opaque,
static void set_int64(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
@ -523,9 +533,10 @@ static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "\"%s\"", *ptr);
}
static void get_string(DeviceState *dev, Visitor *v, void *opaque,
static void get_string(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
@ -537,9 +548,10 @@ static void get_string(DeviceState *dev, Visitor *v, void *opaque,
}
}
static void set_string(DeviceState *dev, Visitor *v, void *opaque,
static void set_string(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@ -609,9 +621,10 @@ static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
*ptr ? bdrv_get_device_name(*ptr) : "<null>");
}
static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
static void get_generic(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
void **ptr = qdev_get_prop_ptr(dev, prop);
char buffer[1024];
@ -624,9 +637,10 @@ static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
visit_type_str(v, &p, name, errp);
}
static void set_generic(DeviceState *dev, Visitor *v, void *opaque,
static void set_generic(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
char *str;
@ -774,9 +788,10 @@ static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
}
}
static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
static void get_vlan(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
int64_t id;
@ -785,9 +800,10 @@ static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &id, name, errp);
}
static void set_vlan(DeviceState *dev, Visitor *v, void *opaque,
static void set_vlan(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@ -971,9 +987,10 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
}
}
static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque,
static void get_pci_devfn(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
char buffer[32];

491
hw/qdev.c
View File

@ -222,6 +222,7 @@ void qbus_reset_all_fn(void *opaque)
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
@ -243,46 +244,6 @@ void qdev_init_nofail(DeviceState *dev)
}
}
static void qdev_property_del_all(DeviceState *dev)
{
while (!QTAILQ_EMPTY(&dev->properties)) {
DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
QTAILQ_REMOVE(&dev->properties, prop, node);
if (prop->release) {
prop->release(dev, prop->name, prop->opaque);
}
g_free(prop->name);
g_free(prop->type);
g_free(prop);
}
}
static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
{
DeviceProperty *prop;
QTAILQ_FOREACH(prop, &dev->properties, node) {
if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
break;
}
}
g_assert(prop != NULL);
QTAILQ_REMOVE(&dev->properties, prop, node);
if (prop->release) {
prop->release(dev, prop->name, prop->opaque);
}
g_free(prop->name);
g_free(prop->type);
g_free(prop);
}
/* Unlink device from bus and free the structure. */
void qdev_free(DeviceState *dev)
{
@ -290,8 +251,6 @@ void qdev_free(DeviceState *dev)
Property *prop;
DeviceClass *dc = DEVICE_GET_CLASS(dev);
qdev_property_del_all(dev);
if (dev->state == DEV_STATE_INITIALIZED) {
while (dev->num_child_bus) {
bus = QLIST_FIRST(&dev->child_bus);
@ -313,12 +272,6 @@ void qdev_free(DeviceState *dev)
prop->info->free(dev, prop);
}
}
if (dev->parent) {
qdev_property_del_child(dev->parent, dev, NULL);
}
if (dev->ref != 0) {
qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
}
object_delete(OBJECT(dev));
}
@ -569,106 +522,19 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
return strdup(path);
}
char *qdev_get_type(DeviceState *dev, Error **errp)
static char *qdev_get_type(Object *obj, Error **errp)
{
return g_strdup(object_get_typename(OBJECT(dev)));
}
void qdev_ref(DeviceState *dev)
{
dev->ref++;
}
void qdev_unref(DeviceState *dev)
{
g_assert(dev->ref > 0);
dev->ref--;
}
void qdev_property_add(DeviceState *dev, const char *name, const char *type,
DevicePropertyAccessor *get, DevicePropertyAccessor *set,
DevicePropertyRelease *release,
void *opaque, Error **errp)
{
DeviceProperty *prop = g_malloc0(sizeof(*prop));
prop->name = g_strdup(name);
prop->type = g_strdup(type);
prop->get = get;
prop->set = set;
prop->release = release;
prop->opaque = opaque;
QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
}
static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
{
DeviceProperty *prop;
QTAILQ_FOREACH(prop, &dev->properties, node) {
if (strcmp(prop->name, name) == 0) {
return prop;
}
}
return NULL;
}
void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
Error **errp)
{
DeviceProperty *prop = qdev_property_find(dev, name);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
return;
}
if (!prop->get) {
error_set(errp, QERR_PERMISSION_DENIED);
} else {
prop->get(dev, v, prop->opaque, name, errp);
}
}
void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
Error **errp)
{
DeviceProperty *prop = qdev_property_find(dev, name);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
return;
}
if (!prop->set) {
error_set(errp, QERR_PERMISSION_DENIED);
} else {
prop->set(dev, v, prop->opaque, name, errp);
}
}
const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
{
DeviceProperty *prop = qdev_property_find(dev, name);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
return NULL;
}
return prop->type;
return g_strdup(object_get_typename(obj));
}
/**
* Legacy property handling
*/
static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char buffer[1024];
@ -678,9 +544,10 @@ static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
visit_type_str(v, &ptr, name, errp);
}
static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
char *ptr = NULL;
@ -720,11 +587,11 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
type = g_strdup_printf("legacy<%s>",
prop->info->legacy_name ?: prop->info->name);
qdev_property_add(dev, name, type,
prop->info->print ? qdev_get_legacy_property : NULL,
prop->info->parse ? qdev_set_legacy_property : NULL,
NULL,
prop, errp);
object_property_add(OBJECT(dev), name, type,
prop->info->print ? qdev_get_legacy_property : NULL,
prop->info->parse ? qdev_set_legacy_property : NULL,
NULL,
prop, errp);
g_free(type);
g_free(name);
@ -739,333 +606,10 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
void qdev_property_add_static(DeviceState *dev, Property *prop,
Error **errp)
{
qdev_property_add(dev, prop->name, prop->info->name,
prop->info->get, prop->info->set,
NULL,
prop, errp);
}
DeviceState *qdev_get_root(void)
{
static DeviceState *qdev_root;
if (!qdev_root) {
qdev_root = qdev_create(NULL, "container");
qdev_init_nofail(qdev_root);
}
return qdev_root;
}
static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState *child = opaque;
gchar *path;
path = qdev_get_canonical_path(child);
visit_type_str(v, &path, name, errp);
g_free(path);
}
static void qdev_release_child_property(DeviceState *dev, const char *name,
void *opaque)
{
DeviceState *child = opaque;
qdev_unref(child);
}
void qdev_property_add_child(DeviceState *dev, const char *name,
DeviceState *child, Error **errp)
{
gchar *type;
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
qdev_property_add(dev, name, type, qdev_get_child_property,
NULL, qdev_release_child_property,
child, errp);
qdev_ref(child);
g_assert(child->parent == NULL);
child->parent = dev;
g_free(type);
}
static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState **child = opaque;
gchar *path;
if (*child) {
path = qdev_get_canonical_path(*child);
visit_type_str(v, &path, name, errp);
g_free(path);
} else {
path = (gchar *)"";
visit_type_str(v, &path, name, errp);
}
}
static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
DeviceState **child = opaque;
bool ambiguous = false;
const char *type;
char *path;
type = qdev_property_get_type(dev, name, NULL);
visit_type_str(v, &path, name, errp);
if (*child) {
qdev_unref(*child);
}
if (strcmp(path, "") != 0) {
DeviceState *target;
target = qdev_resolve_path(path, &ambiguous);
if (target) {
gchar *target_type;
target_type = g_strdup_printf("link<%s>", object_get_typename(OBJECT(target)));
if (strcmp(target_type, type) == 0) {
*child = target;
qdev_ref(target);
} else {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
}
g_free(target_type);
} else {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
}
} else {
*child = NULL;
}
g_free(path);
}
void qdev_property_add_link(DeviceState *dev, const char *name,
const char *type, DeviceState **child,
Error **errp)
{
gchar *full_type;
full_type = g_strdup_printf("link<%s>", type);
qdev_property_add(dev, name, full_type,
qdev_get_link_property,
qdev_set_link_property,
NULL, child, errp);
g_free(full_type);
}
gchar *qdev_get_canonical_path(DeviceState *dev)
{
DeviceState *root = qdev_get_root();
char *newpath = NULL, *path = NULL;
while (dev != root) {
DeviceProperty *prop = NULL;
g_assert(dev->parent != NULL);
QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
if (!strstart(prop->type, "child<", NULL)) {
continue;
}
if (prop->opaque == dev) {
if (path) {
newpath = g_strdup_printf("%s/%s", prop->name, path);
g_free(path);
path = newpath;
} else {
path = g_strdup(prop->name);
}
break;
}
}
g_assert(prop != NULL);
dev = dev->parent;
}
newpath = g_strdup_printf("/%s", path);
g_free(path);
return newpath;
}
static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
gchar **parts,
int index)
{
DeviceProperty *prop;
DeviceState *child;
if (parts[index] == NULL) {
return parent;
}
if (strcmp(parts[index], "") == 0) {
return qdev_resolve_abs_path(parent, parts, index + 1);
}
prop = qdev_property_find(parent, parts[index]);
if (prop == NULL) {
return NULL;
}
child = NULL;
if (strstart(prop->type, "link<", NULL)) {
DeviceState **pchild = prop->opaque;
if (*pchild) {
child = *pchild;
}
} else if (strstart(prop->type, "child<", NULL)) {
child = prop->opaque;
}
if (!child) {
return NULL;
}
return qdev_resolve_abs_path(child, parts, index + 1);
}
static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
gchar **parts,
bool *ambiguous)
{
DeviceState *dev;
DeviceProperty *prop;
dev = qdev_resolve_abs_path(parent, parts, 0);
QTAILQ_FOREACH(prop, &parent->properties, node) {
DeviceState *found;
if (!strstart(prop->type, "child<", NULL)) {
continue;
}
found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
if (found) {
if (dev) {
if (ambiguous) {
*ambiguous = true;
}
return NULL;
}
dev = found;
}
if (ambiguous && *ambiguous) {
return NULL;
}
}
return dev;
}
DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
{
bool partial_path = true;
DeviceState *dev;
gchar **parts;
parts = g_strsplit(path, "/", 0);
if (parts == NULL || parts[0] == NULL) {
g_strfreev(parts);
return qdev_get_root();
}
if (strcmp(parts[0], "") == 0) {
partial_path = false;
}
if (partial_path) {
if (ambiguous) {
*ambiguous = false;
}
dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
} else {
dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
}
g_strfreev(parts);
return dev;
}
typedef struct StringProperty
{
char *(*get)(DeviceState *, Error **);
void (*set)(DeviceState *, const char *, Error **);
} StringProperty;
static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
StringProperty *prop = opaque;
char *value;
value = prop->get(dev, errp);
if (value) {
visit_type_str(v, &value, name, errp);
g_free(value);
}
}
static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
StringProperty *prop = opaque;
char *value;
Error *local_err = NULL;
visit_type_str(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
prop->set(dev, value, errp);
g_free(value);
}
static void qdev_property_release_str(DeviceState *dev, const char *name,
void *opaque)
{
StringProperty *prop = opaque;
g_free(prop);
}
void qdev_property_add_str(DeviceState *dev, const char *name,
char *(*get)(DeviceState *, Error **),
void (*set)(DeviceState *, const char *, Error **),
Error **errp)
{
StringProperty *prop = g_malloc0(sizeof(*prop));
prop->get = get;
prop->set = set;
qdev_property_add(dev, name, "string",
get ? qdev_property_get_str : NULL,
set ? qdev_property_set_str : NULL,
qdev_property_release_str,
prop, errp);
object_property_add(OBJECT(dev), prop->name, prop->info->name,
prop->info->get, prop->info->set,
NULL,
prop, errp);
}
static void device_initfn(Object *obj)
@ -1079,7 +623,6 @@ static void device_initfn(Object *obj)
}
dev->instance_id_alias = -1;
QTAILQ_INIT(&dev->properties);
dev->state = DEV_STATE_CREATED;
qdev_prop_set_defaults(dev, qdev_get_props(dev));
@ -1088,7 +631,7 @@ static void device_initfn(Object *obj)
qdev_property_add_static(dev, prop, NULL);
}
qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
}
void device_reset(DeviceState *dev)

277
hw/qdev.h
View File

@ -27,44 +27,6 @@ enum {
DEV_NVECTORS_UNSPECIFIED = -1,
};
/**
* @DevicePropertyAccessor - called when trying to get/set a property
*
* @dev the device that owns the property
* @v the visitor that contains the property data
* @opaque the device property opaque
* @name the name of the property
* @errp a pointer to an Error that is filled if getting/setting fails.
*/
typedef void (DevicePropertyAccessor)(DeviceState *dev,
Visitor *v,
void *opaque,
const char *name,
Error **errp);
/**
* @DevicePropertyRelease - called when a property is removed from a device
*
* @dev the device that owns the property
* @name the name of the property
* @opaque the opaque registered with the property
*/
typedef void (DevicePropertyRelease)(DeviceState *dev,
const char *name,
void *opaque);
typedef struct DeviceProperty
{
gchar *name;
gchar *type;
DevicePropertyAccessor *get;
DevicePropertyAccessor *set;
DevicePropertyRelease *release;
void *opaque;
QTAILQ_ENTRY(DeviceProperty) node;
} DeviceProperty;
#define TYPE_DEVICE "device"
#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
@ -114,18 +76,6 @@ struct DeviceState {
QTAILQ_ENTRY(DeviceState) sibling;
int instance_id_alias;
int alias_required_for_version;
/**
* This tracks the number of references between devices. See @qdev_ref for
* more information.
*/
uint32_t ref;
QTAILQ_HEAD(, DeviceProperty) properties;
/* Do not, under any circumstance, use this parent link below anywhere
* outside of qdev.c. You have been warned. */
DeviceState *parent;
};
typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
@ -195,8 +145,8 @@ struct PropertyInfo {
int (*parse)(DeviceState *dev, Property *prop, const char *str);
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
void (*free)(DeviceState *dev, Property *prop);
DevicePropertyAccessor *get;
DevicePropertyAccessor *set;
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
};
typedef struct GlobalProperty {
@ -389,235 +339,12 @@ char *qdev_get_fw_dev_path(DeviceState *dev);
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
extern struct BusInfo system_bus_info;
/**
* @qdev_ref
*
* Increase the reference count of a device. A device cannot be freed as long
* as its reference count is greater than zero.
*
* @dev - the device
*/
void qdev_ref(DeviceState *dev);
/**
* @qdef_unref
*
* Decrease the reference count of a device. A device cannot be freed as long
* as its reference count is greater than zero.
*
* @dev - the device
*/
void qdev_unref(DeviceState *dev);
/**
* @qdev_property_add - add a new property to a device
*
* @dev - the device to add a property to
*
* @name - the name of the property. This can contain any character except for
* a forward slash. In general, you should use hyphens '-' instead of
* underscores '_' when naming properties.
*
* @type - the type name of the property. This namespace is pretty loosely
* defined. Sub namespaces are constructed by using a prefix and then
* to angle brackets. For instance, the type 'virtio-net-pci' in the
* 'link' namespace would be 'link<virtio-net-pci>'.
*
* @get - the getter to be called to read a property. If this is NULL, then
* the property cannot be read.
*
* @set - the setter to be called to write a property. If this is NULL,
* then the property cannot be written.
*
* @release - called when the property is removed from the device. This is
* meant to allow a property to free its opaque upon device
* destruction. This may be NULL.
*
* @opaque - an opaque pointer to pass to the callbacks for the property
*
* @errp - returns an error if this function fails
*/
void qdev_property_add(DeviceState *dev, const char *name, const char *type,
DevicePropertyAccessor *get, DevicePropertyAccessor *set,
DevicePropertyRelease *release,
void *opaque, Error **errp);
/**
* @qdev_property_get - reads a property from a device
*
* @dev - the device
*
* @v - the visitor that will receive the property value. This should be an
* Output visitor and the data will be written with @name as the name.
*
* @name - the name of the property
*
* @errp - returns an error if this function fails
*/
void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
Error **errp);
/**
* @qdev_property_set - writes a property to a device
*
* @dev - the device
*
* @v - the visitor that will be used to write the property value. This should
* be an Input visitor and the data will be first read with @name as the
* name and then written as the property value.
*
* @name - the name of the property
*
* @errp - returns an error if this function fails
*/
void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
Error **errp);
/**
* @qdev_property_get_type - returns the type of a property
*
* @dev - the device
*
* @name - the name of the property
*
* @errp - returns an error if this function fails
*
* Returns:
* The type name of the property.
*/
const char *qdev_property_get_type(DeviceState *dev, const char *name,
Error **errp);
/**
* @qdev_property_add_static - add a @Property to a device referencing a
* field in a struct.
*/
void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
/**
* @qdev_get_root - returns the root device of the composition tree
*
* Returns:
* The root of the composition tree.
*/
DeviceState *qdev_get_root(void);
/**
* @qdev_get_canonical_path - returns the canonical path for a device. This
* is the path within the composition tree starting from the root.
*
* Returns:
* The canonical path in the composition tree.
*/
gchar *qdev_get_canonical_path(DeviceState *dev);
/**
* @qdev_resolve_path - resolves a path returning a device
*
* There are two types of supported paths--absolute paths and partial paths.
*
* Absolute paths are derived from the root device and can follow child<> or
* link<> properties. Since they can follow link<> properties, they can be
* arbitrarily long. Absolute paths look like absolute filenames and are
* prefixed with a leading slash.
*
* Partial paths look like relative filenames. They do not begin with a
* prefix. The matching rules for partial paths are subtle but designed to make
* specifying devices easy. At each level of the composition tree, the partial
* 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
* only one match is founded. If more than one match is found, a flag is
* return to indicate that the match was ambiguous.
*
* @path - the path to resolve
*
* @ambiguous - returns true if the path resolution failed because of an
* ambiguous match
*
* Returns:
* The matched device or NULL on path lookup failure.
*/
DeviceState *qdev_resolve_path(const char *path, bool *ambiguous);
/**
* @qdev_property_add_child - Add a child property to a device
*
* Child properties form the composition tree. All devices need to be a child
* of another device. Devices can only be a child of one device.
*
* There is no way for a child to determine what its parent is. It is not
* a bidirectional relationship. This is by design.
*
* @dev - the device to add a property to
*
* @name - the name of the property
*
* @child - the child device
*
* @errp - if an error occurs, a pointer to an area to store the area
*/
void qdev_property_add_child(DeviceState *dev, const char *name,
DeviceState *child, Error **errp);
/**
* @qdev_property_add_link - Add a link property to a device
*
* Links establish relationships between devices. Links are unidirectional
* although two links can be combined to form a bidirectional relationship
* between devices.
*
* Links form the graph in the device model.
*
* @dev - the device to add a property to
*
* @name - the name of the property
*
* @type - the qdev type of the link
*
* @child - a pointer to where the link device reference is stored
*
* @errp - if an error occurs, a pointer to an area to store the area
*/
void qdev_property_add_link(DeviceState *dev, const char *name,
const char *type, DeviceState **child,
Error **errp);
/**
* @qdev_property_add_str
*
* Add a string property using getters/setters. This function will add a
* property of type 'string'.
*
* @dev - the device to add a property to
*
* @name - the name of the property
*
* @get - the getter or NULL if the property is write-only. This function must
* return a string to be freed by @g_free().
*
* @set - the setter or NULL if the property is read-only
*
* @errp - if an error occurs, a pointer to an area to store the error
*/
void qdev_property_add_str(DeviceState *dev, const char *name,
char *(*get)(DeviceState *, Error **),
void (*set)(DeviceState *, const char *, Error **),
Error **errp);
/**
* @qdev_get_type
*
* Returns the string representation of the type of this object.
*
* @dev - the device
*
* @errp - if an error occurs, a pointer to an area to store the error
*
* Returns: a string representing the type. This must be freed by the caller
* with g_free().
*/
char *qdev_get_type(DeviceState *dev, Error **errp);
/**
* @qdev_machine_init
*

View File

@ -17,6 +17,10 @@
#include <glib.h>
#include <stdint.h>
#include <stdbool.h>
#include "qemu-queue.h"
struct Visitor;
struct Error;
struct TypeImpl;
typedef struct TypeImpl *Type;
@ -114,6 +118,47 @@ typedef struct InterfaceInfo InterfaceInfo;
* to one of its #Interface types and vice versa.
*/
/**
* ObjectPropertyAccessor:
* @obj: the object that owns the property
* @v: the visitor that contains the property data
* @opaque: the object property opaque
* @name: the name of the property
* @errp: a pointer to an Error that is filled if getting/setting fails.
*
* Called when trying to get/set a property.
*/
typedef void (ObjectPropertyAccessor)(Object *obj,
struct Visitor *v,
void *opaque,
const char *name,
struct Error **errp);
/**
* ObjectPropertyRelease:
* @obj: the object that owns the property
* @name: the name of the property
* @opaque: the opaque registered with the property
*
* Called when a property is removed from a object.
*/
typedef void (ObjectPropertyRelease)(Object *obj,
const char *name,
void *opaque);
typedef struct ObjectProperty
{
gchar *name;
gchar *type;
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
ObjectPropertyRelease *release;
void *opaque;
QTAILQ_ENTRY(ObjectProperty) node;
} ObjectProperty;
/**
* ObjectClass:
*
@ -145,8 +190,10 @@ struct Object
{
/*< private >*/
ObjectClass *class;
GSList *interfaces;
QTAILQ_HEAD(, ObjectProperty) properties;
uint32_t ref;
Object *parent;
};
/**
@ -435,5 +482,181 @@ ObjectClass *object_class_by_name(const char *typename);
void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
const char *implements_type, bool include_abstract,
void *opaque);
/**
* object_ref:
* @obj: the object
*
* Increase the reference count of a object. A object cannot be freed as long
* as its reference count is greater than zero.
*/
void object_ref(Object *obj);
/**
* qdef_unref:
* @obj: the object
*
* Decrease the reference count of a object. A object cannot be freed as long
* as its reference count is greater than zero.
*/
void object_unref(Object *obj);
/**
* object_property_add:
* @obj: the object to add a property to
* @name: the name of the property. This can contain any character except for
* a forward slash. In general, you should use hyphens '-' instead of
* underscores '_' when naming properties.
* @type: the type name of the property. This namespace is pretty loosely
* defined. Sub namespaces are constructed by using a prefix and then
* to angle brackets. For instance, the type 'virtio-net-pci' in the
* 'link' namespace would be 'link<virtio-net-pci>'.
* @get: The getter to be called to read a property. If this is NULL, then
* the property cannot be read.
* @set: the setter to be called to write a property. If this is NULL,
* then the property cannot be written.
* @release: called when the property is removed from the object. This is
* meant to allow a property to free its opaque upon object
* destruction. This may be NULL.
* @opaque: an opaque pointer to pass to the callbacks for the property
* @errp: returns an error if this function fails
*/
void object_property_add(Object *obj, const char *name, const char *type,
ObjectPropertyAccessor *get,
ObjectPropertyAccessor *set,
ObjectPropertyRelease *release,
void *opaque, struct Error **errp);
void object_property_del(Object *obj, const char *name, struct Error **errp);
void object_unparent(Object *obj);
/**
* object_property_get:
* @obj: the object
* @v: the visitor that will receive the property value. This should be an
* Output visitor and the data will be written with @name as the name.
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Reads a property from a object.
*/
void object_property_get(Object *obj, struct Visitor *v, const char *name,
struct Error **errp);
/**
* object_property_set:
* @obj: the object
* @v: the visitor that will be used to write the property value. This should
* be an Input visitor and the data will be first read with @name as the
* name and then written as the property value.
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Writes a property to a object.
*/
void object_property_set(Object *obj, struct Visitor *v, const char *name,
struct Error **errp);
/**
* @object_property_get_type:
* @obj: the object
* @name: the name of the property
* @errp: returns an error if this function fails
*
* Returns: The type name of the property.
*/
const char *object_property_get_type(Object *obj, const char *name,
struct Error **errp);
/**
* object_get_root:
*
* Returns: the root object of the composition tree
*/
Object *object_get_root(void);
/**
* object_get_canonical_path:
*
* Returns: The canonical path for a object. This is the path within the
* composition tree starting from the root.
*/
gchar *object_get_canonical_path(Object *obj);
/**
* object_resolve_path:
* @path: the path to resolve
* @ambiguous: returns true if the path resolution failed because of an
* ambiguous match
*
* There are two types of supported paths--absolute paths and partial paths.
*
* Absolute paths are derived from the root object and can follow child<> or
* link<> properties. Since they can follow link<> properties, they can be
* arbitrarily long. Absolute paths look like absolute filenames and are
* prefixed with a leading slash.
*
* Partial paths look like relative filenames. They do not begin with a
* prefix. The matching rules for partial paths are subtle but designed to make
* 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
* 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
* return to indicate that the match was ambiguous.
*
* Returns: The matched object or NULL on path lookup failure.
*/
Object *object_resolve_path(const char *path, bool *ambiguous);
/**
* object_property_add_child:
* @obj: the object to add a property to
* @name: the name of the property
* @child: the child object
* @errp: if an error occurs, a pointer to an area to store the area
*
* Child properties form the composition tree. All objects need to be a child
* of another object. Objects can only be a child of one object.
*
* There is no way for a child to determine what its parent is. It is not
* a bidirectional relationship. This is by design.
*/
void object_property_add_child(Object *obj, const char *name,
Object *child, struct Error **errp);
/**
* object_property_add_link:
* @obj: the object to add a property to
* @name: the name of the property
* @type: the qobj type of the link
* @child: a pointer to where the link object reference is stored
* @errp: if an error occurs, a pointer to an area to store the area
*
* Links establish relationships between objects. Links are unidirectional
* although two links can be combined to form a bidirectional relationship
* between objects.
*
* Links form the graph in the object model.
*/
void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child,
struct Error **errp);
/**
* object_property_add_str:
* @obj: the object to add a property to
* @name: the name of the property
* @get: the getter or NULL if the property is write-only. This function must
* return a string to be freed by g_free().
* @set: the setter or NULL if the property is read-only
* @errp: if an error occurs, a pointer to an area to store the error
*
* Add a string property using getters/setters. This function will add a
* property of type 'string'.
*/
void object_property_add_str(Object *obj, const char *name,
char *(*get)(Object *, struct Error **),
void (*set)(Object *, const char *, struct Error **),
struct Error **errp);
#endif

View File

@ -1228,20 +1228,20 @@
#
# Notes: This type is experimental. Its syntax may change in future releases.
##
{ 'type': 'DevicePropertyInfo',
{ 'type': 'ObjectPropertyInfo',
'data': { 'name': 'str', 'type': 'str' } }
##
# @qom-list:
#
# This command will list any properties of a device given a path in the device
# This command will list any properties of a object given a path in the object
# model.
#
# @path: the path within the device model. See @qom-get for a description of
# @path: the path within the object model. See @qom-get for a description of
# this parameter.
#
# Returns: a list of @DevicePropertyInfo that describe the properties of the
# device.
# Returns: a list of @ObjectPropertyInfo that describe the properties of the
# object.
#
# Since: 1.1
#
@ -1250,25 +1250,25 @@
##
{ 'command': 'qom-list',
'data': { 'path': 'str' },
'returns': [ 'DevicePropertyInfo' ] }
'returns': [ 'ObjectPropertyInfo' ] }
##
# @qom-get:
#
# This command will get a property from a device model path and return the
# This command will get a property from a object model path and return the
# value.
#
# @path: The path within the device model. There are two forms of supported
# @path: The path within the object model. There are two forms of supported
# paths--absolute and partial paths.
#
# Absolute paths are derived from the root device and can follow child<>
# Absolute paths are derived from the root object and can follow child<>
# or link<> properties. Since they can follow link<> properties, they
# can be arbitrarily long. Absolute paths look like absolute filenames
# and are prefixed with a leading slash.
#
# Partial paths look like relative filenames. They do not begin
# with a prefix. The matching rules for partial paths are subtle but
# designed to make specifying devices easy. At each level of the
# designed to make 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 least two matches are searched
# for. A successful result is only returned if only one match is
@ -1294,7 +1294,7 @@
##
# @qom-set:
#
# This command will set a property from a device model path.
# This command will set a property from a object model path.
#
# @path: see @qom-get for a description of this parameter
#

34
qmp.c
View File

@ -164,23 +164,23 @@ void qmp_cont(Error **errp)
vm_start();
}
DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
{
DeviceState *dev;
Object *obj;
bool ambiguous = false;
DevicePropertyInfoList *props = NULL;
DeviceProperty *prop;
ObjectPropertyInfoList *props = NULL;
ObjectProperty *prop;
dev = qdev_resolve_path(path, &ambiguous);
if (dev == NULL) {
obj = object_resolve_path(path, &ambiguous);
if (obj == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
return NULL;
}
QTAILQ_FOREACH(prop, &dev->properties, node) {
DevicePropertyInfoList *entry = g_malloc0(sizeof(*entry));
QTAILQ_FOREACH(prop, &obj->properties, node) {
ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
entry->value = g_malloc0(sizeof(DevicePropertyInfo));
entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
entry->next = props;
props = entry;
@ -199,16 +199,16 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
QObject *value = qdict_get(qdict, "value");
Error *local_err = NULL;
QmpInputVisitor *mi;
DeviceState *dev;
Object *obj;
dev = qdev_resolve_path(path, NULL);
if (!dev) {
obj = object_resolve_path(path, NULL);
if (!obj) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
}
mi = qmp_input_visitor_new(value);
qdev_property_set(dev, qmp_input_get_visitor(mi), property, &local_err);
object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
qmp_input_visitor_cleanup(mi);
@ -228,16 +228,16 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
const char *property = qdict_get_str(qdict, "property");
Error *local_err = NULL;
QmpOutputVisitor *mo;
DeviceState *dev;
Object *obj;
dev = qdev_resolve_path(path, NULL);
if (!dev) {
obj = object_resolve_path(path, NULL);
if (!obj) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
}
mo = qmp_output_visitor_new();
qdev_property_get(dev, qmp_output_get_visitor(mo), property, &local_err);
object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
if (!local_err) {
*ret = qmp_output_get_qobject(mo);
}

View File

@ -12,6 +12,9 @@
#include "qemu/object.h"
#include "qemu-common.h"
#include "qapi/qapi-visit-core.h"
#include "hw/qdev.h"
// FIXME remove above
#define MAX_INTERFACES 32
@ -258,6 +261,7 @@ void object_initialize_with_type(void *data, TypeImpl *type)
memset(obj, 0, type->instance_size);
obj->class = type->class;
QTAILQ_INIT(&obj->properties);
object_init_with_type(obj, type);
}
@ -268,6 +272,45 @@ void object_initialize(void *data, const char *typename)
object_initialize_with_type(data, type);
}
static void object_property_del_all(Object *obj)
{
while (!QTAILQ_EMPTY(&obj->properties)) {
ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
QTAILQ_REMOVE(&obj->properties, prop, node);
if (prop->release) {
prop->release(obj, prop->name, prop->opaque);
}
g_free(prop->name);
g_free(prop->type);
g_free(prop);
}
}
static void object_property_del_child(Object *obj, Object *child, Error **errp)
{
ObjectProperty *prop;
QTAILQ_FOREACH(prop, &obj->properties, node) {
if (!strstart(prop->type, "child<", NULL)) {
continue;
}
if (prop->opaque == child) {
object_property_del(obj, prop->name, errp);
}
}
}
void object_unparent(Object *obj)
{
if (obj->parent) {
object_property_del_child(obj->parent, obj, NULL);
}
}
static void object_deinit(Object *obj, TypeImpl *type)
{
if (type->instance_finalize) {
@ -283,6 +326,8 @@ static void object_deinit(Object *obj, TypeImpl *type)
if (type_has_parent(type)) {
object_deinit(obj, type_get_parent(type));
}
object_unparent(obj);
}
void object_finalize(void *data)
@ -291,6 +336,7 @@ void object_finalize(void *data)
TypeImpl *ti = obj->class->type;
object_deinit(obj, ti);
object_property_del_all(obj);
}
Object *object_new_with_type(Type type)
@ -502,3 +548,425 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
}
void object_ref(Object *obj)
{
obj->ref++;
}
void object_unref(Object *obj)
{
g_assert(obj->ref > 0);
obj->ref--;
/* parent always holds a reference to its children */
if (obj->ref == 0) {
object_finalize(obj);
}
}
void object_property_add(Object *obj, const char *name, const char *type,
ObjectPropertyAccessor *get,
ObjectPropertyAccessor *set,
ObjectPropertyRelease *release,
void *opaque, Error **errp)
{
ObjectProperty *prop = g_malloc0(sizeof(*prop));
prop->name = g_strdup(name);
prop->type = g_strdup(type);
prop->get = get;
prop->set = set;
prop->release = release;
prop->opaque = opaque;
QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
}
static ObjectProperty *object_property_find(Object *obj, const char *name)
{
ObjectProperty *prop;
QTAILQ_FOREACH(prop, &obj->properties, node) {
if (strcmp(prop->name, name) == 0) {
return prop;
}
}
return NULL;
}
void object_property_del(Object *obj, const char *name, Error **errp)
{
ObjectProperty *prop = object_property_find(obj, name);
QTAILQ_REMOVE(&obj->properties, prop, node);
prop->release(obj, prop->name, prop->opaque);
g_free(prop->name);
g_free(prop->type);
g_free(prop);
}
void object_property_get(Object *obj, Visitor *v, const char *name,
Error **errp)
{
ObjectProperty *prop = object_property_find(obj, name);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
return;
}
if (!prop->get) {
error_set(errp, QERR_PERMISSION_DENIED);
} else {
prop->get(obj, v, prop->opaque, name, errp);
}
}
void object_property_set(Object *obj, Visitor *v, const char *name,
Error **errp)
{
ObjectProperty *prop = object_property_find(obj, name);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
return;
}
if (!prop->set) {
error_set(errp, QERR_PERMISSION_DENIED);
} else {
prop->set(obj, v, prop->opaque, name, errp);
}
}
const char *object_property_get_type(Object *obj, const char *name, Error **errp)
{
ObjectProperty *prop = object_property_find(obj, name);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
return NULL;
}
return prop->type;
}
Object *object_get_root(void)
{
static DeviceState *object_root;
if (!object_root) {
object_root = qdev_create(NULL, "container");
qdev_init_nofail(object_root);
}
return OBJECT(object_root);
}
static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Object *child = opaque;
gchar *path;
path = object_get_canonical_path(child);
visit_type_str(v, &path, name, errp);
g_free(path);
}
void object_property_add_child(Object *obj, const char *name,
Object *child, Error **errp)
{
gchar *type;
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
object_property_add(obj, name, type, object_get_child_property,
NULL, NULL, child, errp);
object_ref(child);
g_assert(child->parent == NULL);
child->parent = obj;
g_free(type);
}
static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Object **child = opaque;
gchar *path;
if (*child) {
path = object_get_canonical_path(*child);
visit_type_str(v, &path, name, errp);
g_free(path);
} else {
path = (gchar *)"";
visit_type_str(v, &path, name, errp);
}
}
static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
Object **child = opaque;
bool ambiguous = false;
const char *type;
char *path;
type = object_property_get_type(obj, name, NULL);
visit_type_str(v, &path, name, errp);
if (*child) {
object_unref(*child);
}
if (strcmp(path, "") != 0) {
Object *target;
target = object_resolve_path(path, &ambiguous);
if (target) {
gchar *target_type;
target_type = g_strdup_printf("link<%s>",
object_get_typename(OBJECT(target)));
if (strcmp(target_type, type) == 0) {
*child = target;
object_ref(target);
} else {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
}
g_free(target_type);
} else {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
}
} else {
*child = NULL;
}
g_free(path);
}
void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child,
Error **errp)
{
gchar *full_type;
full_type = g_strdup_printf("link<%s>", type);
object_property_add(obj, name, full_type,
object_get_link_property,
object_set_link_property,
NULL, child, errp);
g_free(full_type);
}
gchar *object_get_canonical_path(Object *obj)
{
Object *root = object_get_root();
char *newpath = NULL, *path = NULL;
while (obj != root) {
ObjectProperty *prop = NULL;
g_assert(obj->parent != NULL);
QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
if (!strstart(prop->type, "child<", NULL)) {
continue;
}
if (prop->opaque == obj) {
if (path) {
newpath = g_strdup_printf("%s/%s", prop->name, path);
g_free(path);
path = newpath;
} else {
path = g_strdup(prop->name);
}
break;
}
}
g_assert(prop != NULL);
obj = obj->parent;
}
newpath = g_strdup_printf("/%s", path);
g_free(path);
return newpath;
}
static Object *object_resolve_abs_path(Object *parent,
gchar **parts,
int index)
{
ObjectProperty *prop;
Object *child;
if (parts[index] == NULL) {
return parent;
}
if (strcmp(parts[index], "") == 0) {
return object_resolve_abs_path(parent, parts, index + 1);
}
prop = object_property_find(parent, parts[index]);
if (prop == NULL) {
return NULL;
}
child = NULL;
if (strstart(prop->type, "link<", NULL)) {
Object **pchild = prop->opaque;
if (*pchild) {
child = *pchild;
}
} else if (strstart(prop->type, "child<", NULL)) {
child = prop->opaque;
}
if (!child) {
return NULL;
}
return object_resolve_abs_path(child, parts, index + 1);
}
static Object *object_resolve_partial_path(Object *parent,
gchar **parts,
bool *ambiguous)
{
Object *obj;
ObjectProperty *prop;
obj = object_resolve_abs_path(parent, parts, 0);
QTAILQ_FOREACH(prop, &parent->properties, node) {
Object *found;
if (!strstart(prop->type, "child<", NULL)) {
continue;
}
found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
if (found) {
if (obj) {
if (ambiguous) {
*ambiguous = true;
}
return NULL;
}
obj = found;
}
if (ambiguous && *ambiguous) {
return NULL;
}
}
return obj;
}
Object *object_resolve_path(const char *path, bool *ambiguous)
{
bool partial_path = true;
Object *obj;
gchar **parts;
parts = g_strsplit(path, "/", 0);
if (parts == NULL || parts[0] == NULL) {
g_strfreev(parts);
return object_get_root();
}
if (strcmp(parts[0], "") == 0) {
partial_path = false;
}
if (partial_path) {
if (ambiguous) {
*ambiguous = false;
}
obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
} else {
obj = object_resolve_abs_path(object_get_root(), parts, 1);
}
g_strfreev(parts);
return obj;
}
typedef struct StringProperty
{
char *(*get)(Object *, Error **);
void (*set)(Object *, const char *, Error **);
} StringProperty;
static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
StringProperty *prop = opaque;
char *value;
value = prop->get(obj, errp);
if (value) {
visit_type_str(v, &value, name, errp);
g_free(value);
}
}
static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
StringProperty *prop = opaque;
char *value;
Error *local_err = NULL;
visit_type_str(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
prop->set(obj, value, errp);
g_free(value);
}
static void object_property_release_str(Object *obj, const char *name,
void *opaque)
{
StringProperty *prop = opaque;
g_free(prop);
}
void object_property_add_str(Object *obj, const char *name,
char *(*get)(Object *, Error **),
void (*set)(Object *, const char *, Error **),
Error **errp)
{
StringProperty *prop = g_malloc0(sizeof(*prop));
prop->get = get;
prop->set = set;
object_property_add(obj, name, "string",
get ? object_property_get_str : NULL,
set ? object_property_set_str : NULL,
object_property_release_str,
prop, errp);
}