> On 26 Jan 2020, at 10:11, Marc-André Lureau <marcandre.lur...@gmail.com>
> wrote:
>
> Hi
>
> On Sun, Jan 26, 2020 at 9:10 AM Christophe de Dinechin
> <dinec...@redhat.com> wrote:
>>
>>
>>
>>> On 21 Jan 2020, at 16:11, Marc-André Lureau <marcandre.lur...@gmail.com>
>>> wrote:
>>>
>>> Hi
>>>
>>> On Tue, Jan 21, 2020 at 7:01 PM Markus Armbruster <arm...@redhat.com> wrote:
>>>>
>>>> Daniel P. Berrangé <berra...@redhat.com> writes:
>>>>
>>>>> 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.
>>>>
>>>> Volunteers?
>>>>
>>>
>>> Actually, we are not that far off from being able to use GObject
>>> altogether (I hacked something like that to play with), but I
>>> disgress...
>>>
>>> So introducing GObject-like macros? sure!
>>
>> I’m still puzzled as to why anybody would switch to something like
>> GObject when there is C++.
>
> C++ is another level of complexity.
Migrating an existing code base to C++ object, I agree.
In the absolute, however, the boilerplate code is clearly
another level of complexity in qom or gobject. And I don’t
think it’s particularly hard to add dynamic properties to a
Object class either, including in a form that would call the
existing C functions.
>
> Replacing QOM with GObject would mainly bring us a more solid type
> system with better tooling/features, gobject-introspection support,
> and remove the burden of having our own OO from QEMU code base.
Agree with that.
>
> It sufficiently hard for GObject developers to allow writing GObjects
> from Rust, I don't think anyone want to repeat that work for QOM/QDev.
> I don't know how c++ and rust would interoperate, but that seems even
> more complicated to me.
Good point. But C++ has tools to solve that. Please see my response
to Paolo.
>
>
> --
> Marc-André Lureau