Commit 249d4172 authored by Andreas Färber's avatar Andreas Färber Committed by Anthony Liguori
Browse files

qdev: Prepare "realized" property



Introduce the QOM realizefn suggested by Anthony.
Detailed documentation is supplied in the qdev header.

For now this implements a default DeviceClass::realize callback that
just wraps DeviceClass::init, which it deprecates.
Once all devices have been converted to DeviceClass::realize,
DeviceClass::init is to be removed.

Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarAndreas Färber <afaerber@suse.de>
Cc: Anthony Liguori <anthony@codemonkey.ws>
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parent 7983c8a3
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -20,11 +20,59 @@ enum {
typedef int (*qdev_initfn)(DeviceState *dev);
typedef int (*qdev_event)(DeviceState *dev);
typedef void (*qdev_resetfn)(DeviceState *dev);
typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);

struct VMStateDescription;

/**
 * DeviceClass:
 * @props: Properties accessing state fields.
 * @realize: Callback function invoked when the #DeviceState:realized
 * property is changed to %true. The default invokes @init if not %NULL.
 * @unrealize: Callback function invoked when the #DeviceState:realized
 * property is changed to %false.
 * @init: Callback function invoked when the #DeviceState::realized property
 * is changed to %true. Deprecated, new types inheriting directly from
 * TYPE_DEVICE should use @realize instead, new leaf types should consult
 * their respective parent type.
 *
 * # Realization #
 * Devices are constructed in two stages,
 * 1) object instantiation via object_initialize() and
 * 2) device realization via #DeviceState:realized property.
 * The former may not fail (it might assert or exit), the latter may return
 * error information to the caller and must be re-entrant.
 * Trivial field initializations should go into #TypeInfo.instance_init.
 * Operations depending on @props static properties should go into @realize.
 * After successful realization, setting static properties will fail.
 *
 * As an interim step, the #DeviceState:realized property is set by deprecated
 * functions qdev_init() and qdev_init_nofail().
 * In the future, devices will propagate this state change to their children
 * and along busses they expose.
 * The point in time will be deferred to machine creation, so that values
 * set in @realize will not be introspectable beforehand. Therefore devices
 * must not create children during @realize; they should initialize them via
 * object_initialize() in their own #TypeInfo.instance_init and forward the
 * realization events appropriately.
 *
 * The @init callback is considered private to a particular bus implementation
 * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
 * "init" callback on their parent class instead.
 * Any type may override the @realize and/or @unrealize callbacks but needs
 * to call (and thus save) the parent type's implementation if so desired.
 * Usually this means storing the previous value of, e.g., @realized inside
 * the type's class structure and overwriting it with a function that first
 * invokes the stored callback, then performs any additional steps.
 * If a type derived directly from TYPE_DEVICE implements @realize, it does
 * not need to implement @init and therefore does not need to store and call
 * #DeviceClass' default @realize callback.
 */
typedef struct DeviceClass {
    /*< private >*/
    ObjectClass parent_class;
    /*< public >*/

    const char *fw_name;
    const char *desc;
@@ -33,12 +81,14 @@ typedef struct DeviceClass {

    /* callbacks */
    void (*reset)(DeviceState *dev);
    DeviceRealize realize;
    DeviceUnrealize unrealize;

    /* device state */
    const struct VMStateDescription *vmsd;

    /* Private to qdev / bus.  */
    qdev_initfn init;
    qdev_initfn init; /* TODO remove, once users are converted to realize */
    qdev_event unplug;
    qdev_event exit;
    const char *bus_type;
+71 −23
Original line number Diff line number Diff line
@@ -148,37 +148,30 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
   Return 0 on success.  */
int qdev_init(DeviceState *dev)
{
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
    int rc;
    Error *local_err = NULL;

    assert(!dev->realized);

    rc = dc->init(dev);
    if (rc < 0) {
    object_property_set_bool(OBJECT(dev), true, "realized", &local_err);
    if (local_err != NULL) {
        error_free(local_err);
        qdev_free(dev);
        return rc;
        return -1;
    }

    if (!OBJECT(dev)->parent) {
        static int unattached_count = 0;
        gchar *name = g_strdup_printf("device[%d]", unattached_count++);

        object_property_add_child(container_get(qdev_get_machine(),
                                                "/unattached"),
                                  name, OBJECT(dev), NULL);
        g_free(name);
    return 0;
}

    if (qdev_get_vmsd(dev)) {
        vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
                                       dev->instance_id_alias,
                                       dev->alias_required_for_version);
static void device_realize(DeviceState *dev, Error **err)
{
    DeviceClass *dc = DEVICE_GET_CLASS(dev);

    if (dc->init) {
        int rc = dc->init(dev);
        if (rc < 0) {
            error_setg(err, "Device initialization failed.");
            return;
        }
    dev->realized = true;
    if (dev->hotplugged) {
        device_reset(dev);
    }
    return 0;
}

void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
@@ -641,6 +634,55 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
    assert_no_error(local_err);
}

static bool device_get_realized(Object *obj, Error **err)
{
    DeviceState *dev = DEVICE(obj);
    return dev->realized;
}

static void device_set_realized(Object *obj, bool value, Error **err)
{
    DeviceState *dev = DEVICE(obj);
    DeviceClass *dc = DEVICE_GET_CLASS(dev);
    Error *local_err = NULL;

    if (value && !dev->realized) {
        if (dc->realize) {
            dc->realize(dev, &local_err);
        }

        if (!obj->parent && local_err == NULL) {
            static int unattached_count;
            gchar *name = g_strdup_printf("device[%d]", unattached_count++);

            object_property_add_child(container_get(qdev_get_machine(),
                                                    "/unattached"),
                                      name, obj, &local_err);
            g_free(name);
        }

        if (qdev_get_vmsd(dev) && local_err == NULL) {
            vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
                                           dev->instance_id_alias,
                                           dev->alias_required_for_version);
        }
        if (dev->hotplugged && local_err == NULL) {
            device_reset(dev);
        }
    } else if (!value && dev->realized) {
        if (dc->unrealize) {
            dc->unrealize(dev, &local_err);
        }
    }

    if (local_err != NULL) {
        error_propagate(err, local_err);
        return;
    }

    dev->realized = value;
}

static void device_initfn(Object *obj)
{
    DeviceState *dev = DEVICE(obj);
@@ -655,6 +697,9 @@ static void device_initfn(Object *obj)
    dev->instance_id_alias = -1;
    dev->realized = false;

    object_property_add_bool(obj, "realized",
                             device_get_realized, device_set_realized, NULL);

    class = object_get_class(OBJECT(dev));
    do {
        for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
@@ -714,7 +759,10 @@ static void device_unparent(Object *obj)

static void device_class_init(ObjectClass *class, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(class);

    class->unparent = device_unparent;
    dc->realize = device_realize;
}

void device_reset(DeviceState *dev)