On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote: > Marc-André Lureau <marcandre.lur...@gmail.com> writes: > > > Hi > > > > On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi <stefa...@gmail.com> wrote: > >> > >> On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote: > >> > Stefan Hajnoczi <stefa...@gmail.com> writes: > >> > > >> > > On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote: > >> > >> Christophe de Dinechin <dinec...@redhat.com> writes: > >> > >> >> On 15 Jan 2020, at 10:20, Markus Armbruster <arm...@redhat.com> > >> > >> >> wrote: > >> > >> * qemuMonitorJSONSetIOThread() uses it to control iothread's > >> > >> properties > >> > >> poll-max-ns, poll-grow, poll-shrink. Their use with -object is > >> > >> documented (in qemu-options.hx), their use with qom-set is not. > >> > > > >> > > I'm happy to use a different interface. > >> > > > >> > > Writing a boilerplate "iothread-set-poll-params" QMP command in C would > >> > > be a step backwards. > >> > > >> > No argument. > >> > > >> > > Maybe the QAPI code generator could map something like this: > >> > > > >> > > { 'command': 'iothread-set-poll-params', > >> > > 'data': { > >> > > 'id': 'str', > >> > > '*max-ns': 'uint64', > >> > > '*grow': 'uint64', > >> > > '*shrink': 'uint64' > >> > > }, > >> > > 'map-to-qom-set': 'IOThread' > >> > > } > >> > > > >> > > And turn it into QOM accessors on the IOThread object. > >> > > >> > I think a generic "set this configuration to that value" command is just > >> > fine. qom-set fails on several counts, though: > >> > > >> > * Tolerable: qom-set is not actually generic, it applies only to QOM. > >> > > >> > * qom-set lets you set tons of stuff that is not meant to be changed at > >> > run time. If it breaks your guest, you get to keep the pieces. > >> > > >> > * There is virtually no documentation on what can be set to what values, > >> > and their semantics. > >> > > >> > In its current state, QOM is a user interface superfund site. > >> > >> Thoughts about a solution: > >> > >> Static QOM properties should be declared via QAPI instead of > >> imperatively via QOM APIs. That way they are introspectable and type > >> information is present in the schema. > >> > >> The QAPI code generator could emit a function that is callable from > >> .class_init(). This eliminates the need to manually call > >> object_class_property_add(). > > We need to make up our minds what exactly we want generated. Then we > can design the QAPI language, and code up the generator. > > Skeleton QOM type, to help with the discussion: > > #define TYPE_FOO "foo" > > #define FOO(obj) OBJECT_CHECK(Foo, (obj), TYPE_FOO) > #define FOO_CLASS(klass) \ > OBJECT_CLASS_CHECK(FooClass, (klass), TYPE_FOO) > #define FOO_GET_CLASS(obj) \ > OBJECT_GET_CLASS(FooClass, (obj), TYPE_FOO) > > typedef FooClass { > ParentClass parent_class; > ... // hand-written per-class state > } > > struct Chardev { > ParentObject parent_obj; > ... // hand-written instance (per-object) state > }; > > static const TypeInfo char_type_info = { > .name = TYPE_FOO, > .parent = TYPE_OBJECT, > .instance_size = sizeof(Foo), > .instance_init = ..., // methods to initialize > .instance_post_init = ..., // and finalize instances, > .instance_finalize = ..., // all optional > .abstract = ..., // true or false (d'oh) > .class_size = sizeof(FooClass), > .class_init = ..., // methods to initialize > .class_base_init = ..., // classes, optional > .class_data = ..., // extra argument for them > .interfaces = ... > }; > > There's substantial boilerplate, with plenty of hand-written code in the > gaps. What of the boilerplate do we plan to generate? How do we plan > to fill the gaps, if any?
FWIW, even without a QOM generator, we can do waaaaaaay better on the amount of boilerplate needed for QOM without very much work. It just needs a few convenience macros writing. QOM is not GObject, but is heavily inspired by it and so looking at GObject gives us a design pattern we can aim to match in terms of amount of boilerplate. What we do manually with TypeInfo struct there has essentially always been done by a 1 line macro in GObject: G_DEFINE_TYPE(virIdentity, vir_identity, G_TYPE_OBJECT) If implementing interfaces, there's 1 extra line needed per interface to associate them. https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DEFINE-TYPE:CAPS And what we do in the header file to add the 4 or more FOO_XXX macros, and the class struct and the object struct has recently been turned into a 2-liner: #define VIR_TYPE_IDENTITY vir_identity_get_type() G_DECLARE_FINAL_TYPE(virIdentity, vir_identity, VIR, IDENTITY, GObject); https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DECLARE-FINAL-TYPE:CAPS Or #define VIR_TYPE_IDENTITY vir_identity_get_type() G_DECLARE_DERIVABLE_TYPE(virIdentity, vir_identity, VIR, IDENTITY, GObject); https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DECLARE-DERIVABLE-TYPE:CAPS It would be nice to have a QOM code generator so that we can statically declare properties & parent/child/interface relationships, but for an immediate low cost win, better macros would be very useful IMHO. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|