Paolo Bonzini <pbonz...@redhat.com> writes: > On 26/05/20 08:27, Markus Armbruster wrote: >>> It cannot happen, because a device must be unparented before it's >>> destroyed and unparenting takes care of unrealizing the device. >> >> I can't see where unparenting takes care of unrealizing. Can you help >> me? > > Hidden in plain sight: > > static void device_unparent(Object *obj) > { > DeviceState *dev = DEVICE(obj); > BusState *bus; > > if (dev->realized) { > object_property_set_bool(obj, false, "realized", NULL); > } > ... > } > > and the call stack is object_unparent -> object_property_del_child -> > object_finalize_child_property (via prop->release) -> class->unparent.
Aha. My attempt to trigger automatic unrealize of a child device after the parent device's realize failed was unsuccessful. I tried with pci-serial-2x, hacked up to make it fail as if the second child's realize failed, and hacked up some more to make it rely on automatic unrealize. No dice: $ qemu-system-x86_64 -S -nodefaults -display none -monitor stdio QEMU 5.0.50 monitor - type 'help' for more information (qemu) device_add pci-serial-2x ### serial_realize Error: mock error (qemu) q Even though it doesn't really matter here, as David pointed out, it's something I'd like to understand. diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 5f9ccfcc93..433b5caefc 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -56,7 +56,7 @@ static void multi_serial_pci_exit(PCIDevice *dev) for (i = 0; i < pci->ports; i++) { s = pci->state + i; - object_property_set_bool(OBJECT(s), false, "realized", &error_abort); +// object_property_set_bool(OBJECT(s), false, "realized", &error_abort); memory_region_del_subregion(&pci->iobar, &s->io); g_free(pci->name[i]); } @@ -106,6 +106,9 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) for (i = 0; i < nports; i++) { s = pci->state + i; + if (i) + error_setg(errp, "mock error"); + else object_property_set_bool(OBJECT(s), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/char/serial.c b/hw/char/serial.c index 7d74694587..55b0bbd8b0 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -938,6 +938,8 @@ static void serial_realize(DeviceState *dev, Error **errp) { SerialState *s = SERIAL(dev); + printf("### %s\n", __func__); + s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s); s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s); @@ -954,6 +956,8 @@ static void serial_unrealize(DeviceState *dev) { SerialState *s = SERIAL(dev); + printf("### %s\n", __func__); + qemu_chr_fe_deinit(&s->chr, false); timer_del(s->modem_status_poll);