On Wed, Dec 02, 2020 at 04:17:13PM +0100, Kevin Wolf wrote:
Am 02.12.2020 um 14:54 hat Eduardo Habkost geschrieben:
> On Wed, Dec 02, 2020 at 02:26:44PM +0100, Paolo Bonzini wrote:
> > On 02/12/20 13:51, Eduardo Habkost wrote:
> > > > > I'm liking the direction this is taking. However, I would
still
> > > > > like to have a clearer and feasible plan that would work for
> > > > > -device, -machine, and -cpu.
> > > >
> > > > -cpu is not a problem since it's generally created with a static
> > > > configuration (now done with global properties, in the future it
could be a
> > > > struct).
> > >
> > > It is a problem if it requires manually converting existing code
> > > defining CPU properties and we don't have a transition plan.
> >
> > We do not have to convert everything _if_ for some objects there are good
> > reasons to do programmatically-generated properties. CPUs might be one of
> > those cases (or if we decide to convert them, they might endure some more
> > code duplication than other devices because they have so many properties).
>
> OK, we just need to agree on what the transition will look like
> when we do it. I think we should put as much care into
> transition/glue infrastructure as we put into the new
> infrastructure.
>
>
> >
> > > Would a -device conversion also involve non-user-creatable
> > > devices, or would we keep existing internal usage of QOM
> > > properties?
> > >
> > > Even if it's just for user-creatable devices, getting rid of QOM
> > > property usage in devices sounds like a very ambitious goal. I'd
> > > like us to have a good transition plan, in addition to declaring
> > > what's our ideal end goal.
> >
> > For user-creatable objects Kevin is doing work in lockstep on all classes;
> > but once we have the infrastructure for QAPI object configuration schemas we
> > can proceed in the other direction and operate on one device at a time.
> >
> > With some handwaving, something like (see create_unimplemented_device)
> >
> > DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
> >
> > qdev_prop_set_string(dev, "name", name);
> > qdev_prop_set_uint64(dev, "size", size);
> > sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> >
> > might become something like
> >
> > { 'object': 'unimplemented-device',
> > 'config': {
> > 'name': 'str',
> > 'size': 'size'
> > },
> > }
> >
> > DeviceState *dev = qapi_Unimplemented_new(&(
> > (UnimplementedDeviceOptions) {
> > .name = name,
> > .size = size
> > }, &error_fatal);
> > object_unref(dev);
> >
> > (i.e. all typesafe!) and the underlying code would be something like
> [...]
> >
>
> Looks nice as end goal. Then, these are a few questions I would
> have about the transition plan:
>
> Would it require changing both device implementation and device
> users in lockstep? Should we have a compatibility layer to allow
> existing qdev_new()+qdev_prop_set_*() code to keep working after
> the devices are converted to the new system? If not, why not?
Technically, it doesn't strictly require a lockstep update. You can have
two code paths leading to a fully initialised device, one being the
traditional way of setting properties and finally calling dc->realize,
the other being a new method that takes the configuration in its
parameters and also sets dev->realized = true at the end.
If at all possible, I would however prefer a lockstep update because
having two paths is a weird intermediate state and the code paths could
easily diverge. Keeping the old way around for a device also means that
property setters are still doing two different jobs (initial
configuration and updates at runtime).
I'd like to understand better how that intermediate state would
look like and why there's risk of separate code paths diverging.
Could we have an intermediate state that doesn't require any
duplication and thus have no separate code paths that could
diverge?
> If we add a compatibility layer, is the end goal to convert all
> existing qdev_new() users to the new system? If yes, why? If
> not, why not?
My personal goal is covering -object and -device, i.e. the external
interfaces. Converting purely internally created devices is not as
interesting (especially as long as we focus only on object creation),
but might be desirable for consistency.
I wonder how much consistency we will lose and how much confusion
we'll cause if we end up with two completely separate methods for
creating devices.
> What about subclasses? Would base classes need to be converted
> in lockstep with all subclasses? How would the transition
> process of (e.g.) PCI devices look like?
I don't think so.
If you want to convert base classes first, you may need to take the
path shown above where both initialisation paths coexist while the
children are converted because instantiation of a child class involves
setting properties of the base class. So you can only restrict these
properties to runtime-only after all children have been converted.
The other way around might be easier: You will need to describe the
properties of base classes in the QAPI schema from the beginning, but
that doesn't mean that their initialisation code has to change just yet.
The child classes will need to forward the part of their configuration
that belongs to the base class. The downside is that this code will have
to be changed again when the base class is finally converted.
So we have options there, and we can decide case by case which one is
most appropriate for the specific class to be converted (depending on
how many child classes exist, how many properties are inherited, etc.)
Right now it's hard for me to understand what those intermediate
states would look like. It sounds like it requires too many
complicated manual changes to be done by humans, and lots of room
for mistakes when maintaining two parallel code paths. I'd
prefer to delegate the translation job to a machine.
In other words, I'd prefer to have compatibility layer(s) that
would make the same implementation work with the both old-style
and new-style APIs for creating devices. Maybe this would
involve generating QAPI code from QOM/qdev property lists, and/or
generating qdev property registration code from the QAPI schema,
I don't know.
Providing a compatibility layer would also help us be more
confident that there are no gaps in the abstractions provided by
the two systems (QOM properties and QAPI schema) that we still
need to address.
--
Eduardo