diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-07-01 11:55:48 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-07-01 11:55:49 +0100 |
commit | c26f3a0a6dfe5ef2973ddfab03b1ceff641a7ebe (patch) | |
tree | 286413832e3d84d7d1cf3fd4d1093f2c48e87f7d | |
parent | b3959efdbb2dc3d5959e3b0a8e188126930beca8 (diff) | |
parent | 352e8da743f26948cb12d0ee53c455f328f59bbe (diff) | |
download | qemu-c26f3a0a6dfe5ef2973ddfab03b1ceff641a7ebe.zip qemu-c26f3a0a6dfe5ef2973ddfab03b1ceff641a7ebe.tar.gz qemu-c26f3a0a6dfe5ef2973ddfab03b1ceff641a7ebe.tar.bz2 |
Merge remote-tracking branch 'remotes/bonzini/memory' into staging
* remotes/bonzini/memory:
qdev: correctly send DEVICE_DELETED for recursively-deleted devices
memory: do not give a name to the internal exec.c regions
memory: MemoryRegion: Add size property
memory: MemoryRegion: Add may-overlap and priority props
memory: MemoryRegion: Add container and addr props
memory: MemoryRegion: replace owner field with QOM parent
memory: MemoryRegion: QOMify
memory: MemoryRegion: use /machine as default owner
libqtest: escape strings in QMP commands, fix leak
qom: object: Ignore refs/unrefs of NULL
qom: object: remove parent pointer when unparenting
mc146818rtc: add "rtc-time" link to "/machine/rtc"
qom: allow creating an alias of a child<> property
qom: add a generic mechanism to resolve paths
qom: add object_property_add_alias()
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | exec.c | 12 | ||||
-rw-r--r-- | hw/core/qdev.c | 5 | ||||
-rw-r--r-- | hw/timer/mc146818rtc.c | 9 | ||||
-rw-r--r-- | include/exec/memory.h | 9 | ||||
-rw-r--r-- | include/hw/qdev-core.h | 1 | ||||
-rw-r--r-- | include/qom/object.h | 54 | ||||
-rw-r--r-- | memory.c | 231 | ||||
-rw-r--r-- | qom/object.c | 147 | ||||
-rw-r--r-- | tests/fdc-test.c | 2 | ||||
-rw-r--r-- | tests/libqtest.c | 47 | ||||
-rw-r--r-- | tests/qom-test.c | 6 | ||||
-rw-r--r-- | tests/tmp105-test.c | 4 | ||||
-rw-r--r-- | vl.c | 3 |
13 files changed, 441 insertions, 89 deletions
@@ -883,7 +883,7 @@ static void phys_section_destroy(MemoryRegion *mr) if (mr->subpage) { subpage_t *subpage = container_of(mr, subpage_t, iomem); - memory_region_destroy(&subpage->iomem); + object_unref(OBJECT(&subpage->iomem)); g_free(subpage); } } @@ -1768,7 +1768,7 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base) mmio->as = as; mmio->base = base; memory_region_init_io(&mmio->iomem, NULL, &subpage_ops, mmio, - "subpage", TARGET_PAGE_SIZE); + NULL, TARGET_PAGE_SIZE); mmio->iomem.subpage = true; #if defined(DEBUG_SUBPAGE) printf("%s: %p base " TARGET_FMT_plx " len %08x\n", __func__, @@ -1801,13 +1801,13 @@ MemoryRegion *iotlb_to_region(AddressSpace *as, hwaddr index) static void io_mem_init(void) { - memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, "rom", UINT64_MAX); + memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX); memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL, - "unassigned", UINT64_MAX); + NULL, UINT64_MAX); memory_region_init_io(&io_mem_notdirty, NULL, ¬dirty_mem_ops, NULL, - "notdirty", UINT64_MAX); + NULL, UINT64_MAX); memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL, - "watch", UINT64_MAX); + NULL, UINT64_MAX); } static void mem_begin(MemoryListener *listener) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 371b427..a2feb5a 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -848,6 +848,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) if (dev->hotplugged && local_err == NULL) { device_reset(dev); } + dev->pending_deleted_event = false; } else if (!value && dev->realized) { QLIST_FOREACH(bus, &dev->child_bus, sibling) { object_property_set_bool(OBJECT(bus), false, "realized", @@ -862,6 +863,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) if (dc->unrealize && local_err == NULL) { dc->unrealize(dev, &local_err); } + dev->pending_deleted_event = true; } if (local_err != NULL) { @@ -972,7 +974,6 @@ static void device_unparent(Object *obj) { DeviceState *dev = DEVICE(obj); BusState *bus; - bool have_realized = dev->realized; if (dev->realized) { object_property_set_bool(obj, false, "realized", NULL); @@ -988,7 +989,7 @@ static void device_unparent(Object *obj) } /* Only send event if the device had been completely realized */ - if (have_realized) { + if (dev->pending_deleted_event) { gchar *path = object_get_canonical_path(OBJECT(dev)); qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort); diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 307732c..9d817ca 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -909,6 +909,9 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) object_property_add(OBJECT(s), "date", "struct tm", rtc_get_date, NULL, NULL, s, NULL); + + object_property_add_alias(qdev_get_machine(), "rtc-time", + OBJECT(s), "date", NULL); } ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) @@ -950,11 +953,17 @@ static void rtc_class_initfn(ObjectClass *klass, void *data) dc->cannot_instantiate_with_device_add_yet = true; } +static void rtc_finalize(Object *obj) +{ + object_property_del(qdev_get_machine(), "rtc", NULL); +} + static const TypeInfo mc146818rtc_info = { .name = TYPE_MC146818_RTC, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(RTCState), .class_init = rtc_class_initfn, + .instance_finalize = rtc_finalize, }; static void mc146818rtc_register_types(void) diff --git a/include/exec/memory.h b/include/exec/memory.h index 3d778d7..e2c8e3e 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -32,10 +32,15 @@ #include "qemu/int128.h" #include "qemu/notify.h" #include "qapi/error.h" +#include "qom/object.h" #define MAX_PHYS_ADDR_SPACE_BITS 62 #define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1) +#define TYPE_MEMORY_REGION "qemu:memory-region" +#define MEMORY_REGION(obj) \ + OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION) + typedef struct MemoryRegionOps MemoryRegionOps; typedef struct MemoryRegionMmio MemoryRegionMmio; @@ -131,11 +136,11 @@ typedef struct CoalescedMemoryRange CoalescedMemoryRange; typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; struct MemoryRegion { + Object parent_obj; /* All fields are private - violators will be prosecuted */ const MemoryRegionOps *ops; const MemoryRegionIOMMUOps *iommu_ops; void *opaque; - struct Object *owner; MemoryRegion *container; Int128 size; hwaddr addr; @@ -152,7 +157,7 @@ struct MemoryRegion { bool flush_coalesced_mmio; MemoryRegion *alias; hwaddr alias_offset; - int priority; + int32_t priority; bool may_overlap; QTAILQ_HEAD(subregions, MemoryRegion) subregions; QTAILQ_ENTRY(MemoryRegion) subregions_link; diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 9221cfc..0799ff2 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -156,6 +156,7 @@ struct DeviceState { const char *id; bool realized; + bool pending_deleted_event; QemuOpts *opts; int hotplugged; BusState *parent_bus; diff --git a/include/qom/object.h b/include/qom/object.h index b882ccc..8a05a81 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -304,6 +304,25 @@ typedef void (ObjectPropertyAccessor)(Object *obj, Error **errp); /** + * ObjectPropertyResolve: + * @obj: the object that owns the property + * @opaque: the opaque registered with the property + * @part: the name of the property + * + * Resolves the #Object corresponding to property @part. + * + * The returned object can also be used as a starting point + * to resolve a relative path starting with "@part". + * + * Returns: If @path is the path that led to @obj, the function + * returns the #Object corresponding to "@path/@part". + * If "@path/@part" is not a valid object path, it returns #NULL. + */ +typedef Object *(ObjectPropertyResolve)(Object *obj, + void *opaque, + const char *part); + +/** * ObjectPropertyRelease: * @obj: the object that owns the property * @name: the name of the property @@ -321,6 +340,7 @@ typedef struct ObjectProperty gchar *type; ObjectPropertyAccessor *get; ObjectPropertyAccessor *set; + ObjectPropertyResolve *resolve; ObjectPropertyRelease *release; void *opaque; @@ -787,12 +807,16 @@ void object_unref(Object *obj); * 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 + * + * Returns: The #ObjectProperty; this can be used to set the @resolve + * callback for child and link properties. */ -void object_property_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque, Error **errp); +ObjectProperty *object_property_add(Object *obj, const char *name, + const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp); void object_property_del(Object *obj, const char *name, Error **errp); @@ -1231,6 +1255,26 @@ void object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, Error **Errp); /** + * object_property_add_alias: + * @obj: the object to add a property to + * @name: the name of the property + * @target_obj: the object to forward property access to + * @target_name: the name of the property on the forwarded object + * @errp: if an error occurs, a pointer to an area to store the error + * + * Add an alias for a property on an object. This function will add a property + * of the same type as the forwarded property. + * + * The caller must ensure that <code>@target_obj</code> stays alive as long as + * this property exists. In the case of a child object or an alias on the same + * object this will be the case. For aliases to other objects the caller is + * responsible for taking a reference. + */ +void object_property_add_alias(Object *obj, const char *name, + Object *target_obj, const char *target_name, + Error **errp); + +/** * object_child_foreach: * @obj: the object whose children will be navigated * @fn: the iterator function to be called @@ -16,6 +16,7 @@ #include "exec/memory.h" #include "exec/address-spaces.h" #include "exec/ioport.h" +#include "qapi/visitor.h" #include "qemu/bitops.h" #include "qom/object.h" #include "trace.h" @@ -842,40 +843,178 @@ static void memory_region_destructor_rom_device(MemoryRegion *mr) qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK); } +static bool memory_region_need_escape(char c) +{ + return c == '/' || c == '[' || c == '\\' || c == ']'; +} + +static char *memory_region_escape_name(const char *name) +{ + const char *p; + char *escaped, *q; + uint8_t c; + size_t bytes = 0; + + for (p = name; *p; p++) { + bytes += memory_region_need_escape(*p) ? 4 : 1; + } + if (bytes == p - name) { + return g_memdup(name, bytes + 1); + } + + escaped = g_malloc(bytes + 1); + for (p = name, q = escaped; *p; p++) { + c = *p; + if (unlikely(memory_region_need_escape(c))) { + *q++ = '\\'; + *q++ = 'x'; + *q++ = "0123456789abcdef"[c >> 4]; + c = "0123456789abcdef"[c & 15]; + } + *q++ = c; + } + *q = 0; + return escaped; +} + +static void object_property_add_child_array(Object *owner, + const char *name, + Object *child) +{ + int i; + char *base_name = memory_region_escape_name(name); + + for (i = 0; ; i++) { + char *full_name = g_strdup_printf("%s[%d]", base_name, i); + Error *local_err = NULL; + + object_property_add_child(owner, full_name, child, &local_err); + g_free(full_name); + if (!local_err) { + break; + } + + error_free(local_err); + } + + g_free(base_name); +} + + void memory_region_init(MemoryRegion *mr, Object *owner, const char *name, uint64_t size) { - mr->ops = &unassigned_mem_ops; - mr->opaque = NULL; - mr->owner = owner; - mr->iommu_ops = NULL; - mr->container = NULL; + if (!owner) { + owner = qdev_get_machine(); + } + + object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION); mr->size = int128_make64(size); if (size == UINT64_MAX) { mr->size = int128_2_64(); } - mr->addr = 0; - mr->subpage = false; + mr->name = g_strdup(name); + + if (name) { + object_property_add_child_array(owner, name, OBJECT(mr)); + object_unref(OBJECT(mr)); + } +} + +static void memory_region_get_addr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + uint64_t value = mr->addr; + + visit_type_uint64(v, &value, name, errp); +} + +static void memory_region_get_container(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + gchar *path = (gchar *)""; + + if (mr->container) { + path = object_get_canonical_path(OBJECT(mr->container)); + } + visit_type_str(v, &path, name, errp); + if (mr->container) { + g_free(path); + } +} + +static Object *memory_region_resolve_container(Object *obj, void *opaque, + const char *part) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + + return OBJECT(mr->container); +} + +static void memory_region_get_priority(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + int32_t value = mr->priority; + + visit_type_int32(v, &value, name, errp); +} + +static bool memory_region_get_may_overlap(Object *obj, Error **errp) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + + return mr->may_overlap; +} + +static void memory_region_get_size(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + uint64_t value = memory_region_size(mr); + + visit_type_uint64(v, &value, name, errp); +} + +static void memory_region_initfn(Object *obj) +{ + MemoryRegion *mr = MEMORY_REGION(obj); + ObjectProperty *op; + + mr->ops = &unassigned_mem_ops; mr->enabled = true; - mr->terminates = false; - mr->ram = false; mr->romd_mode = true; - mr->readonly = false; - mr->rom_device = false; mr->destructor = memory_region_destructor_none; - mr->priority = 0; - mr->may_overlap = false; - mr->alias = NULL; QTAILQ_INIT(&mr->subregions); - memset(&mr->subregions_link, 0, sizeof mr->subregions_link); QTAILQ_INIT(&mr->coalesced); - mr->name = g_strdup(name); - mr->dirty_log_mask = 0; - mr->ioeventfd_nb = 0; - mr->ioeventfds = NULL; - mr->flush_coalesced_mmio = false; + + op = object_property_add(OBJECT(mr), "container", + "link<" TYPE_MEMORY_REGION ">", + memory_region_get_container, + NULL, /* memory_region_set_container */ + NULL, NULL, &error_abort); + op->resolve = memory_region_resolve_container; + + object_property_add(OBJECT(mr), "addr", "uint64", + memory_region_get_addr, + NULL, /* memory_region_set_addr */ + NULL, NULL, &error_abort); + object_property_add(OBJECT(mr), "priority", "uint32", + memory_region_get_priority, + NULL, /* memory_region_set_priority */ + NULL, NULL, &error_abort); + object_property_add_bool(OBJECT(mr), "may-overlap", + memory_region_get_may_overlap, + NULL, /* memory_region_set_may_overlap */ + &error_abort); + object_property_add(OBJECT(mr), "size", "uint64", + memory_region_get_size, + NULL, /* memory_region_set_size, */ + NULL, NULL, &error_abort); } static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, @@ -1113,8 +1252,10 @@ void memory_region_init_reservation(MemoryRegion *mr, memory_region_init_io(mr, owner, &unassigned_mem_ops, mr, name, size); } -void memory_region_destroy(MemoryRegion *mr) +static void memory_region_finalize(Object *obj) { + MemoryRegion *mr = MEMORY_REGION(obj); + assert(QTAILQ_EMPTY(&mr->subregions)); assert(memory_region_transaction_depth == 0); mr->destructor(mr); @@ -1123,22 +1264,45 @@ void memory_region_destroy(MemoryRegion *mr) g_free(mr->ioeventfds); } +void memory_region_destroy(MemoryRegion *mr) +{ + object_unparent(OBJECT(mr)); +} + + Object *memory_region_owner(MemoryRegion *mr) { - return mr->owner; + Object *obj = OBJECT(mr); + return obj->parent; } void memory_region_ref(MemoryRegion *mr) { - if (mr && mr->owner) { - object_ref(mr->owner); + /* MMIO callbacks most likely will access data that belongs + * to the owner, hence the need to ref/unref the owner whenever + * the memory region is in use. + * + * The memory region is a child of its owner. As long as the + * owner doesn't call unparent itself on the memory region, + * ref-ing the owner will also keep the memory region alive. + * Memory regions without an owner are supposed to never go away, + * but we still ref/unref them for debugging purposes. + */ + Object *obj = OBJECT(mr); + if (obj && obj->parent) { + object_ref(obj->parent); + } else { + object_ref(obj); } } void memory_region_unref(MemoryRegion *mr) { - if (mr && mr->owner) { - object_unref(mr->owner); + Object *obj = OBJECT(mr); + if (obj && obj->parent) { + object_unref(obj->parent); + } else { + object_unref(obj); } } @@ -1946,3 +2110,18 @@ void mtree_info(fprintf_function mon_printf, void *f) g_free(ml); } } + +static const TypeInfo memory_region_info = { + .parent = TYPE_OBJECT, + .name = TYPE_MEMORY_REGION, + .instance_size = sizeof(MemoryRegion), + .instance_init = memory_region_initfn, + .instance_finalize = memory_region_finalize, +}; + +static void memory_register_types(void) +{ + type_register_static(&memory_region_info); +} + +type_init(memory_register_types) diff --git a/qom/object.c b/qom/object.c index 7cefdf2..0e8267b 100644 --- a/qom/object.c +++ b/qom/object.c @@ -356,11 +356,6 @@ static inline bool object_property_is_child(ObjectProperty *prop) return strstart(prop->type, "child<", NULL); } -static inline bool object_property_is_link(ObjectProperty *prop) -{ - return strstart(prop->type, "link<", NULL); -} - static void object_property_del_all(Object *obj) { while (!QTAILQ_EMPTY(&obj->properties)) { @@ -716,11 +711,17 @@ GSList *object_class_get_list(const char *implements_type, void object_ref(Object *obj) { + if (!obj) { + return; + } atomic_inc(&obj->ref); } void object_unref(Object *obj) { + if (!obj) { + return; + } g_assert(obj->ref > 0); /* parent always holds a reference to its children */ @@ -729,11 +730,12 @@ void object_unref(Object *obj) } } -void object_property_add(Object *obj, const char *name, const char *type, - ObjectPropertyAccessor *get, - ObjectPropertyAccessor *set, - ObjectPropertyRelease *release, - void *opaque, Error **errp) +ObjectProperty * +object_property_add(Object *obj, const char *name, const char *type, + ObjectPropertyAccessor *get, + ObjectPropertyAccessor *set, + ObjectPropertyRelease *release, + void *opaque, Error **errp) { ObjectProperty *prop; @@ -742,7 +744,7 @@ void object_property_add(Object *obj, const char *name, const char *type, error_setg(errp, "attempt to add duplicate property '%s'" " to object (type '%s')", name, object_get_typename(obj)); - return; + return NULL; } } @@ -757,6 +759,7 @@ void object_property_add(Object *obj, const char *name, const char *type, prop->opaque = opaque; QTAILQ_INSERT_TAIL(&obj->properties, prop, node); + return prop; } ObjectProperty *object_property_find(Object *obj, const char *name, @@ -1029,6 +1032,11 @@ static void object_get_child_property(Object *obj, Visitor *v, void *opaque, g_free(path); } +static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) +{ + return opaque; +} + static void object_finalize_child_property(Object *obj, const char *name, void *opaque) { @@ -1042,15 +1050,18 @@ void object_property_add_child(Object *obj, const char *name, { Error *local_err = NULL; gchar *type; + ObjectProperty *op; type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); - object_property_add(obj, name, type, object_get_child_property, NULL, - object_finalize_child_property, child, &local_err); + op = object_property_add(obj, name, type, object_get_child_property, NULL, + object_finalize_child_property, child, &local_err); if (local_err) { error_propagate(errp, local_err); goto out; } + + op->resolve = object_resolve_child_property; object_ref(child); g_assert(child->parent == NULL); child->parent = obj; @@ -1155,13 +1166,16 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, return; } - if (new_target) { - object_ref(new_target); - } + object_ref(new_target); *child = new_target; - if (old_target != NULL) { - object_unref(old_target); - } + object_unref(old_target); +} + +static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) +{ + LinkProperty *lprop = opaque; + + return *lprop->child; } static void object_release_link_property(Object *obj, const char *name, @@ -1185,6 +1199,7 @@ void object_property_add_link(Object *obj, const char *name, Error *local_err = NULL; LinkProperty *prop = g_malloc(sizeof(*prop)); gchar *full_type; + ObjectProperty *op; prop->child = child; prop->check = check; @@ -1192,17 +1207,21 @@ void object_property_add_link(Object *obj, const char *name, full_type = g_strdup_printf("link<%s>", type); - object_property_add(obj, name, full_type, - object_get_link_property, - check ? object_set_link_property : NULL, - object_release_link_property, - prop, - &local_err); + op = object_property_add(obj, name, full_type, + object_get_link_property, + check ? object_set_link_property : NULL, + object_release_link_property, + prop, + &local_err); if (local_err) { error_propagate(errp, local_err); g_free(prop); + goto out; } + op->resolve = object_resolve_link_property; + +out: g_free(full_type); } @@ -1261,11 +1280,8 @@ Object *object_resolve_path_component(Object *parent, const gchar *part) return NULL; } - if (object_property_is_link(prop)) { - LinkProperty *lprop = prop->opaque; - return *lprop->child; - } else if (object_property_is_child(prop)) { - return prop->opaque; + if (prop->resolve) { + return prop->resolve(parent, prop->opaque, part); } else { return NULL; } @@ -1551,6 +1567,77 @@ void object_property_add_uint64_ptr(Object *obj, const char *name, NULL, NULL, (void *)v, errp); } +typedef struct { + Object *target_obj; + const char *target_name; +} AliasProperty; + +static void property_get_alias(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + AliasProperty *prop = opaque; + + object_property_get(prop->target_obj, v, prop->target_name, errp); +} + +static void property_set_alias(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + AliasProperty *prop = opaque; + + object_property_set(prop->target_obj, v, prop->target_name, errp); +} + +static Object *property_resolve_alias(Object *obj, void *opaque, + const gchar *part) +{ + AliasProperty *prop = opaque; + + return object_resolve_path_component(prop->target_obj, prop->target_name); +} + +static void property_release_alias(Object *obj, const char *name, void *opaque) +{ + AliasProperty *prop = opaque; + + g_free(prop); +} + +void object_property_add_alias(Object *obj, const char *name, + Object *target_obj, const char *target_name, + Error **errp) +{ + AliasProperty *prop; + ObjectProperty *op; + ObjectProperty *target_prop; + gchar *prop_type; + + target_prop = object_property_find(target_obj, target_name, errp); + if (!target_prop) { + return; + } + + if (object_property_is_child(target_prop)) { + prop_type = g_strdup_printf("link%s", + target_prop->type + strlen("child")); + } else { + prop_type = g_strdup(target_prop->type); + } + + prop = g_malloc(sizeof(*prop)); + prop->target_obj = target_obj; + prop->target_name = target_name; + + op = object_property_add(obj, name, prop_type, + property_get_alias, + property_set_alias, + property_release_alias, + prop, errp); + op->resolve = property_resolve_alias; + + g_free(prop_type); +} + static void object_instance_init(Object *obj) { object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); diff --git a/tests/fdc-test.c b/tests/fdc-test.c index 37096dc..c8e1e7b 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -291,7 +291,7 @@ static void test_media_insert(void) /* Insert media in drive. DSKCHK should not be reset until a step pulse * is sent. */ qmp_discard_response("{'execute':'change', 'arguments':{" - " 'device':'floppy0', 'target': '%s' }}", + " 'device':'floppy0', 'target': %s }}", test_image); qmp_discard_response(""); /* ignore event (FIXME open -> open transition?!) */ diff --git a/tests/libqtest.c b/tests/libqtest.c index 71468ac..98e8f4b 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -30,8 +30,9 @@ #include "qemu/compiler.h" #include "qemu/osdep.h" -#include "qapi/qmp/json-streamer.h" #include "qapi/qmp/json-parser.h" +#include "qapi/qmp/json-streamer.h" +#include "qapi/qmp/qjson.h" #define MAX_IRQ 256 #define SOCKET_TIMEOUT 5 @@ -220,19 +221,15 @@ void qtest_quit(QTestState *s) g_free(s); } -static void socket_sendf(int fd, const char *fmt, va_list ap) +static void socket_send(int fd, const char *buf, size_t size) { - gchar *str; - size_t size, offset; - - str = g_strdup_vprintf(fmt, ap); - size = strlen(str); + size_t offset; offset = 0; while (offset < size) { ssize_t len; - len = write(fd, str + offset, size - offset); + len = write(fd, buf + offset, size - offset); if (len == -1 && errno == EINTR) { continue; } @@ -244,6 +241,15 @@ static void socket_sendf(int fd, const char *fmt, va_list ap) } } +static void socket_sendf(int fd, const char *fmt, va_list ap) +{ + gchar *str = g_strdup_vprintf(fmt, ap); + size_t size = strlen(str); + + socket_send(fd, str, size); + g_free(str); +} + static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...) { va_list ap; @@ -378,8 +384,29 @@ QDict *qtest_qmp_receive(QTestState *s) QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) { - /* Send QMP request */ - socket_sendf(s->qmp_fd, fmt, ap); + va_list ap_copy; + QObject *qobj; + + /* Going through qobject ensures we escape strings properly. + * This seemingly unnecessary copy is required in case va_list + * is an array type. + */ + va_copy(ap_copy, ap); + qobj = qobject_from_jsonv(fmt, &ap_copy); + va_end(ap_copy); + + /* No need to send anything for an empty QObject. */ + if (qobj) { + QString *qstr = qobject_to_json(qobj); + const char *str = qstring_get_str(qstr); + size_t size = qstring_get_length(qstr); + + /* Send QMP request */ + socket_send(s->qmp_fd, str, size); + + QDECREF(qstr); + qobject_decref(qobj); + } /* Receive reply */ return qtest_qmp_receive(s); diff --git a/tests/qom-test.c b/tests/qom-test.c index d8d1d8d..4246382 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c @@ -53,7 +53,7 @@ static void test_properties(const char *path, bool recurse) g_test_message("Obtaining properties of %s", path); response = qmp("{ 'execute': 'qom-list'," - " 'arguments': { 'path': '%s' } }", path); + " 'arguments': { 'path': %s } }", path); g_assert(response); if (!recurse) { @@ -76,8 +76,8 @@ static void test_properties(const char *path, bool recurse) const char *prop = qdict_get_str(tuple, "name"); g_test_message("Testing property %s.%s", path, prop); response = qmp("{ 'execute': 'qom-get'," - " 'arguments': { 'path': '%s'," - " 'property': '%s' } }", + " 'arguments': { 'path': %s," + " 'property': %s } }", path, prop); /* qom-get may fail but should not, e.g., segfault. */ g_assert(response); diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c index 15ddaf3..99db538 100644 --- a/tests/tmp105-test.c +++ b/tests/tmp105-test.c @@ -69,7 +69,7 @@ static int qmp_tmp105_get_temperature(const char *id) QDict *response; int ret; - response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': '%s', " + response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, " "'property': 'temperature' } }", id); g_assert(qdict_haskey(response, "return")); ret = qdict_get_int(response, "return"); @@ -81,7 +81,7 @@ static void qmp_tmp105_set_temperature(const char *id, int value) { QDict *response; - response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': '%s', " + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, " "'property': 'temperature', 'value': %d } }", id, value); g_assert(qdict_haskey(response, "return")); QDECREF(response); @@ -3986,12 +3986,11 @@ int main(int argc, char **argv, char **envp) exit(1); } - cpu_exec_init_all(); - current_machine = MACHINE(object_new(object_class_get_name( OBJECT_CLASS(machine_class)))); object_property_add_child(object_get_root(), "machine", OBJECT(current_machine), &error_abort); + cpu_exec_init_all(); if (machine_class->hw_version) { qemu_set_version(machine_class->hw_version); |