Re: Integrating QOM into QAPI

2020-01-29 Thread Christophe de Dinechin



> On 28 Jan 2020, at 11:03, Daniel P. Berrangé  wrote:
> 
> On Mon, Jan 27, 2020 at 08:05:36PM +0100, Christophe de Dinechin wrote:
>> 
>> 
>>> On 26 Jan 2020, at 16:04, Peter Maydell  wrote:
>>> 
>>> On Sun, 26 Jan 2020 at 08:10, Christophe de Dinechin
>>>  wrote:
 I’m still puzzled as to why anybody would switch to something like
 GObject when there is C++.
>>> 
>>> I'm fairly strongly against using C++.
>> 
>> Just to be clear, so am I ;-)
>> 
>>> C++'s language design
>>> is an "everything including the kitchen sink, lots of "this
>>> is here for back compat but it's a bear trap", lots of new
>>> stuff arriving all the time.
>> 
>> Actually, the new stuff is not that bad, overall.
>> 
>> I do agree C++ is an overly complicated language, and that in
>> practice, there is zero chance of qemu moving to it. But that does
>> not invalidate my point that creating a class in C++ is easier
>> than creating a class in any C-based macro-heavy reinvention
>> of basic OO concepts.
>> 
>> (I write this after having read Paolo’s response, which points
>> out IMO better reasons for GObject, which I will discuss there).
>> 
>>> It's just too big to keep in
>>> your head all at once. C has its faults, absolutely, but at
>>> least it tries to be a reasonably sized vaguely coherent
>>> language.
>>> 
>>> You'd have more luck persuading me we should move to Rust:
>>> at least then we'd get some clear benefits (no more buffer
>>> overrun security bugs) for the upheaval :-)
>> 
>> This is largely a myth as soon as you need to do “your own stuff”.
>> Example: CVE-2019-18960, https://seclists.org/oss-sec/2019/q4/141.
> 
> Calling it a "myth" from from that one data point is not really credible.

A single failure is enough to credibly counter any “no more X” claim ;-)

Also, I carefully qualified that as for “your own stuff”. IOW, if you write
your own buffer management, Rust does not help. Well, dealing with
guest memory forces us to have our own buffer management.

> 
> No language is perfect & such that it can eliminate all possible CVEs.
> Rust *can*, however, eliminate a very large set of bugs which lead to 
> memory corruption in unchecked languages like C/C++.

The Rust hype today eerily reminds me so strongly of the C++ hype
20 years ago. C++ too was supposed to be a safer C. And indeed,
if you stick to the standard library, you _do_ eliminate a very large set
of bugs which lead to memory corruption, leaks, etc in C. So the
claim C++ made was not wrong. The claim Rust makes is not wrong
either. The false sense of safety that some people get from it is.


>  You'll still have
> CVEs to deal with, but they'll be different classes of bugs, or rare
> edge cases like the one you show above.

How exactly was it an “edge case”? From what I saw, it was the most
basic kind of range check, exactly the kind that you see in 99.9% of all
range checks.

> 
> 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 :|
> 




Re: Integrating QOM into QAPI

2020-01-28 Thread Daniel P . Berrangé
On Mon, Jan 27, 2020 at 08:05:36PM +0100, Christophe de Dinechin wrote:
> 
> 
> > On 26 Jan 2020, at 16:04, Peter Maydell  wrote:
> > 
> > On Sun, 26 Jan 2020 at 08:10, Christophe de Dinechin
> >  wrote:
> >> I’m still puzzled as to why anybody would switch to something like
> >> GObject when there is C++.
> > 
> > I'm fairly strongly against using C++.
> 
> Just to be clear, so am I ;-)
> 
> > C++'s language design
> > is an "everything including the kitchen sink, lots of "this
> > is here for back compat but it's a bear trap", lots of new
> > stuff arriving all the time.
> 
> Actually, the new stuff is not that bad, overall.
> 
> I do agree C++ is an overly complicated language, and that in
> practice, there is zero chance of qemu moving to it. But that does
> not invalidate my point that creating a class in C++ is easier
> than creating a class in any C-based macro-heavy reinvention
> of basic OO concepts.
> 
> (I write this after having read Paolo’s response, which points
> out IMO better reasons for GObject, which I will discuss there).
> 
> > It's just too big to keep in
> > your head all at once. C has its faults, absolutely, but at
> > least it tries to be a reasonably sized vaguely coherent
> > language.
> > 
> > You'd have more luck persuading me we should move to Rust:
> > at least then we'd get some clear benefits (no more buffer
> > overrun security bugs) for the upheaval :-)
> 
> This is largely a myth as soon as you need to do “your own stuff”.
> Example: CVE-2019-18960, https://seclists.org/oss-sec/2019/q4/141.

Calling it a "myth" from from that one data point is not really credible.

No language is perfect & such that it can eliminate all possible CVEs.
Rust *can*, however, eliminate a very large set of bugs which lead to 
memory corruption in unchecked languages like C/C++.  You'll still have
CVEs to deal with, but they'll be different classes of bugs, or rare
edge cases like the one you show above.

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 :|




Re: Integrating QOM into QAPI

2020-01-28 Thread Markus Armbruster
Christophe de Dinechin  writes:

>> On 26 Jan 2020, at 16:04, Peter Maydell  wrote:
>> 
>> On Sun, 26 Jan 2020 at 08:10, Christophe de Dinechin
>>  wrote:
[...]
>> You'd have more luck persuading me we should move to Rust:
>> at least then we'd get some clear benefits (no more buffer
>> overrun security bugs) for the upheaval :-)
>
> This is largely a myth as soon as you need to do “your own stuff”.
> Example: CVE-2019-18960, https://seclists.org/oss-sec/2019/q4/141.

I think "largely a myth" is too harsh.  Yes, it's not a silver bullet to
insta-slay all memory and concurrency safety vampires.  It does provide
useful guarantees, though.  How useful exactly in practice time will
tell.




Re: Integrating QOM into QAPI

2020-01-27 Thread Christophe de Dinechin



> On 26 Jan 2020, at 16:04, Peter Maydell  wrote:
> 
> On Sun, 26 Jan 2020 at 08:10, Christophe de Dinechin
>  wrote:
>> I’m still puzzled as to why anybody would switch to something like
>> GObject when there is C++.
> 
> I'm fairly strongly against using C++.

Just to be clear, so am I ;-)

> C++'s language design
> is an "everything including the kitchen sink, lots of "this
> is here for back compat but it's a bear trap", lots of new
> stuff arriving all the time.

Actually, the new stuff is not that bad, overall.

I do agree C++ is an overly complicated language, and that in
practice, there is zero chance of qemu moving to it. But that does
not invalidate my point that creating a class in C++ is easier
than creating a class in any C-based macro-heavy reinvention
of basic OO concepts.

(I write this after having read Paolo’s response, which points
out IMO better reasons for GObject, which I will discuss there).

> It's just too big to keep in
> your head all at once. C has its faults, absolutely, but at
> least it tries to be a reasonably sized vaguely coherent
> language.
> 
> You'd have more luck persuading me we should move to Rust:
> at least then we'd get some clear benefits (no more buffer
> overrun security bugs) for the upheaval :-)

This is largely a myth as soon as you need to do “your own stuff”.
Example: CVE-2019-18960, https://seclists.org/oss-sec/2019/q4/141.

> 
> thanks
> -- PMM
> 




Re: Integrating QOM into QAPI

2020-01-27 Thread Christophe de Dinechin



> On 26 Jan 2020, at 10:11, Marc-André Lureau  
> wrote:
> 
> Hi
> 
> On Sun, Jan 26, 2020 at 9:10 AM Christophe de Dinechin
>  wrote:
>> 
>> 
>> 
>>> On 21 Jan 2020, at 16:11, Marc-André Lureau  
>>> wrote:
>>> 
>>> Hi
>>> 
>>> On Tue, Jan 21, 2020 at 7:01 PM Markus Armbruster  wrote:
 
 Daniel P. Berrangé  writes:
 
> On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:
>> Marc-André Lureau  writes:
>> 
>>> Hi
>>> 
>>> On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi  
>>> wrote:
 
 On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote:
> Stefan Hajnoczi  writes:
> 
>> On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote:
>>> Christophe de Dinechin  writes:
> On 15 Jan 2020, at 10:20, Markus Armbruster  
> 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 waaay 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 

Re: Integrating QOM into QAPI

2020-01-27 Thread Christophe de Dinechin



> On 26 Jan 2020, at 17:47, Paolo Bonzini  wrote:
> 
> On 26/01/20 10:11, Marc-André Lureau wrote:
>>> I’m still puzzled as to why anybody would switch to something like
>>> GObject when there is C++.
>> C++ is another level of complexity.
>> 
>> 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.
> 
> In fact, C++ doesn't solve any of the problems that either QOM or
> GObject try to solve.  (Neither does Rust for that matter).

It does not solve all of them _easily_. I do believe that any solution
to these problems can be engineered in C++, if only because C++
is essentially a superset of C. The question is whether the result can
be made easier / safer to use and generally more elegant. I believe
that the answer is yes, see proof at end of mail.

However, before going further, glib offers way more than gobject.
So there’s that too… And I’m not saying migrating to C++ is a good
idea, I’m just trying to evaluate the various options fairly.


> Nevertheless, there is no stupid question, only stupid answers, and I
> think Christophe's remark is an example of a common misconception.  In
> the hope of not making this a stupid answer, let my try to formulate
> succinctly what I think the differences are between QOM, GObject and the
> C++ object model:

Thank you for this remarkably non-stupid answer ;-) You have really
isolated, in very clear terms, the essence of the discussion.

> 
> - the C++ object model (at least "old-style" C++ with virtual functions
> and the like) provides you with _the intersection_ of what QOM and
> GObject try to solve.  This is what Marc-André calls "OO", and it's
> essentially virtual functions and dynamic casts.  It's a relatively
> small part of both QOM and GObject, and unfortunately a wheel that
> almost every large C program ends up reinventing.

This was the part I was pointing to in my initial comment.

C++ solves that basic “OO” stuff well, and goes a little beyond QOM
or GObject in offering IMO many other benefits, e.g. wrt type safety.

> 
> - Marc-André also described above what GObject provides: a fully
> introspectable type system and the tools so that _libraries_ can define
> _types that will be used from multiple programming languages_.

This kind of things has existed for a very long time. CORBA dates back
to 1991. Also, I’m not sure how important multiple programming languages
are for the qemu use-case. I believe that what matters more is remotely
accessible objects (e.g. over a socket), which in turn makes it almost
trivial to call from another language as long as you accept some kind
of serialization / deserialization process along the way.

GObject only seems marginally better for the “in same process” use case,
in the sense that it makes “objects” that can be used from any language,
indeed, but at the cost of being somewhat foreign and weird in all languages,
including C.

Look at the GClosure marshalling, for example, and compare it with the
example I give you at end of this email, and you tell me which one looks
easier and safer to use.

> 
> - QOM also provides a fully introspectable type system, but with a
> different focus: it's so that _objects_ can expose _properties that will
> be accessed from multiple channels_.

Exposing the properties and making them introspectable are the
fundamental feature we need to discuss. So agreement here.

What you have not explained to my satisfaction
yet is how GObject is a better starting point for re-creating a new
externally-accessible API than some kind of wrapper built in C++
and taking advantage of modern C++ features.


> Everything else in both GObject and QOM follows from this core purpose,
> and the differences between the two follow from the differences.  For
> example:
> 
> - GObject's focus on multiple programming languages:
> gobject-introspection, GClosure, support for non-object types (scalar
> and GBoxed)

How much of that is actually useful to create a new usable qemu API?

> 
> - QOM's focus on objects: dynamic properties, object tree, all types are
> classes

That, to me, looks fundamental, since not having it would require
a total re-architecture of the rest of qemu.

But it looks also somewhat trivial to implement in C++.
For example, obj[“id”] could return a PropertyAccessor
that lets you read or write the object knowing that it is of type
T, so you could write:

if (my_object[“id”] < 3) // Automatically checks the type

or 

my_object[“id”] = 42;

The latter would call PropertyAccessor::operator=(int), which
in turn would check if property “id” exists in my_object, if it has type
“int”, and so on.

Implementation-wise, a simple std::map of BaseProperty pointers,
where each would be an instance of some

template
class Property : public BaseProperty
{
operator T(); // get
T& 

Re: Integrating QOM into QAPI

2020-01-26 Thread Paolo Bonzini
On 26/01/20 10:11, Marc-André Lureau wrote:
>> I’m still puzzled as to why anybody would switch to something like
>> GObject when there is C++.
> C++ is another level of complexity.
> 
> 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.

In fact, C++ doesn't solve any of the problems that either QOM or
GObject try to solve.  (Neither does Rust for that matter).
Nevertheless, there is no stupid question, only stupid answers, and I
think Christophe's remark is an example of a common misconception.  In
the hope of not making this a stupid answer, let my try to formulate
succinctly what I think the differences are between QOM, GObject and the
C++ object model:

- the C++ object model (at least "old-style" C++ with virtual functions
and the like) provides you with _the intersection_ of what QOM and
GObject try to solve.  This is what Marc-André calls "OO", and it's
essentially virtual functions and dynamic casts.  It's a relatively
small part of both QOM and GObject, and unfortunately a wheel that
almost every large C program ends up reinventing.

- Marc-André also described above what GObject provides: a fully
introspectable type system and the tools so that _libraries_ can define
_types that will be used from multiple programming languages_.

- QOM also provides a fully introspectable type system, but with a
different focus: it's so that _objects_ can expose _properties that will
be accessed from multiple channels_.


Everything else in both GObject and QOM follows from this core purpose,
and the differences between the two follow from the differences.  For
example:

- GObject's focus on multiple programming languages:
gobject-introspection, GClosure, support for non-object types (scalar
and GBoxed)

- QOM's focus on objects: dynamic properties, object tree, all types are
classes

- QOM's focus on properties: no introspection of methods

- QOM's support for multiple channels: visitors

Paolo




Re: Integrating QOM into QAPI

2020-01-26 Thread Peter Maydell
On Sun, 26 Jan 2020 at 08:10, Christophe de Dinechin
 wrote:
> I’m still puzzled as to why anybody would switch to something like
> GObject when there is C++.

I'm fairly strongly against using C++. C++'s language design
is an "everything including the kitchen sink, lots of "this
is here for back compat but it's a bear trap", lots of new
stuff arriving all the time. It's just too big to keep in
your head all at once. C has its faults, absolutely, but at
least it tries to be a reasonably sized vaguely coherent
language.

You'd have more luck persuading me we should move to Rust:
at least then we'd get some clear benefits (no more buffer
overrun security bugs) for the upheaval :-)

thanks
-- PMM



Re: Integrating QOM into QAPI

2020-01-26 Thread Marc-André Lureau
Hi

On Sun, Jan 26, 2020 at 9:10 AM Christophe de Dinechin
 wrote:
>
>
>
> > On 21 Jan 2020, at 16:11, Marc-André Lureau  
> > wrote:
> >
> > Hi
> >
> > On Tue, Jan 21, 2020 at 7:01 PM Markus Armbruster  wrote:
> >>
> >> Daniel P. Berrangé  writes:
> >>
> >>> On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:
>  Marc-André Lureau  writes:
> 
> > Hi
> >
> > On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi  
> > wrote:
> >>
> >> On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote:
> >>> Stefan Hajnoczi  writes:
> >>>
>  On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote:
> > Christophe de Dinechin  writes:
> >>> On 15 Jan 2020, at 10:20, Markus Armbruster  
> >>> 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 waaay 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 

Re: Integrating QOM into QAPI

2020-01-26 Thread Christophe de Dinechin



> On 21 Jan 2020, at 16:11, Marc-André Lureau  
> wrote:
> 
> Hi
> 
> On Tue, Jan 21, 2020 at 7:01 PM Markus Armbruster  wrote:
>> 
>> Daniel P. Berrangé  writes:
>> 
>>> On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:
 Marc-André Lureau  writes:
 
> Hi
> 
> On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi  
> wrote:
>> 
>> On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote:
>>> Stefan Hajnoczi  writes:
>>> 
 On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote:
> Christophe de Dinechin  writes:
>>> On 15 Jan 2020, at 10:20, Markus Armbruster  
>>> 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 waaay 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.
>>> 
>>>  
>>> 

Re: Integrating QOM into QAPI

2020-01-25 Thread Peter Maydell
On Sat, 25 Jan 2020 at 09:28, Paolo Bonzini  wrote:
>
> On 25/01/20 05:44, Marc-André Lureau wrote:
> > I try to find a good reason qom was chosen over gobject, and I can't
> > find it.
>
> The main reasons were integration with QAPI, and the object tree.
> Though everything I say here is a kind of reverse engineering of
> Anthony's brain because there aren't really any design documents besides
> what's in include/qom/object.h (and he overlooked some aspects, for
> example "unparent" was introduced a few months later).

I vagely recall that back at that time we were a lot less heavy
in our usage of glib also, so "just use the glib version of whatever"
would not have been quite as easy a sell as it might be today.
Anthony's original RFC email lists some "key differences" between
QOM and GObject, which presumably seemed to him at the time
to be sufficient to justify not using GObject:
https://lists.gnu.org/archive/html/qemu-devel/2011-07/msg01673.html

thanks
-- PMM



Re: Integrating QOM into QAPI

2020-01-25 Thread Paolo Bonzini
On 25/01/20 05:44, Marc-André Lureau wrote:
> On 22/01/20 13:42, Marc-André Lureau wrote:
> > From the top of my mind, this is the pain point when trying to use
> GObject:
> > - static/inlined object, not supported by GObject, unlikely to ever be
> > - few users in qemu, transition possible.
> > - 64k limit of GObject, for some reason, unlikely to change but I will
> > take a look. Some users in qemu, code adaptation possible.
> > - dynamic properties, possible in GObject with hacks, but not
> > recommended and going to be deprecated from what I remember
> > - "array" properties - would need extra layer/tweaks for compatibility
> > - link properties - would need special handling
> > - different limitations for type names and properties names
> 
> The properties in general are very different between QOM and QAPI.  They
> have different limitations and features as Marc-André mentioned, but an
> especially important one is the integration with QAPI visitors.  This is
> what allows us to support -object and object-add with the same code, and
> is what separates QOM from GObject the most.
> 
> Maybe it would be possible to build an adapter, but having written in
> the past code that uses GType to do marshalling and unmarshalling, I'm
> not really fond of repeating the experience...
> 
> I agree it is one of the things that look very different from gobject.
> At the same time, I think defining conventions/types or interface to
> describe hierarchy isn't so difficult, and then adapting the visitors
> shouldn't be either.

Note that there are a few "structured" properties that export a QAPI
struct rather than a scalar.  Those would be a bit more complex.  Links
might also be tricky.

Another small difference that came to mind is the different object
liveness model; GObject is mostly plain old reference counting (plus the
"floating reference" idea), while in QOM reference counting is secondary
and lifetime is mostly dictated by the object tree and "unparenting".
This is more of a conceptual difference; it could be easily retrofitted
in GObject.

> I try to find a good reason qom was chosen over gobject, and I can't
> find it.

The main reasons were integration with QAPI, and the object tree.
Though everything I say here is a kind of reverse engineering of
Anthony's brain because there aren't really any design documents besides
what's in include/qom/object.h (and he overlooked some aspects, for
example "unparent" was introduced a few months later).

Overall I don't think there would be much benefit in reusing GObject.
It's about 3k lines of code, quite a few would stay (those implementing
the tree) and a bunch more would have to be rewritten.  I don't think
we'd have any use for most of the features that QOM lacks, such as
signals.  Also, QOM is quite well documented and we should include its
documentation in docs/devel instead.

That said, coccinell-ing efforts on QOM code are definitely a good idea
since it's quite mature now and we know better what we need.  And there
are practical advantages too, it's not just code cleanups---see how your
series shows the default value of the properties in -device foo,help.

Paolo




Re: Integrating QOM into QAPI

2020-01-24 Thread Marc-André Lureau
Hi

Le ven. 24 janv. 2020 à 19:32, Paolo Bonzini  a écrit :

> On 22/01/20 13:42, Marc-André Lureau wrote:
> > From the top of my mind, this is the pain point when trying to use
> GObject:
> > - static/inlined object, not supported by GObject, unlikely to ever be
> > - few users in qemu, transition possible.
> > - 64k limit of GObject, for some reason, unlikely to change but I will
> > take a look. Some users in qemu, code adaptation possible.
> > - dynamic properties, possible in GObject with hacks, but not
> > recommended and going to be deprecated from what I remember
> > - "array" properties - would need extra layer/tweaks for compatibility
> > - link properties - would need special handling
> > - different limitations for type names and properties names
>
> The properties in general are very different between QOM and QAPI.  They
> have different limitations and features as Marc-André mentioned, but an
> especially important one is the integration with QAPI visitors.  This is
> what allows us to support -object and object-add with the same code, and
> is what separates QOM from GObject the most.
>
> Maybe it would be possible to build an adapter, but having written in
> the past code that uses GType to do marshalling and unmarshalling, I'm
> not really fond of repeating the experience...
>

I agree it is one of the things that look very different from gobject. At
the same time, I think defining conventions/types or interface to describe
hierarchy isn't so difficult, and then adapting the visitors shouldn't be
either.

I try to find a good reason qom was chosen over gobject, and I can't find
it.

>


Re: Integrating QOM into QAPI

2020-01-24 Thread Paolo Bonzini
On 22/01/20 13:42, Marc-André Lureau wrote:
> From the top of my mind, this is the pain point when trying to use GObject:
> - static/inlined object, not supported by GObject, unlikely to ever be
> - few users in qemu, transition possible.
> - 64k limit of GObject, for some reason, unlikely to change but I will
> take a look. Some users in qemu, code adaptation possible.
> - dynamic properties, possible in GObject with hacks, but not
> recommended and going to be deprecated from what I remember
> - "array" properties - would need extra layer/tweaks for compatibility
> - link properties - would need special handling
> - different limitations for type names and properties names

The properties in general are very different between QOM and QAPI.  They
have different limitations and features as Marc-André mentioned, but an
especially important one is the integration with QAPI visitors.  This is
what allows us to support -object and object-add with the same code, and
is what separates QOM from GObject the most.

Maybe it would be possible to build an adapter, but having written in
the past code that uses GType to do marshalling and unmarshalling, I'm
not really fond of repeating the experience...

Paolo




Re: Integrating QOM into QAPI

2020-01-22 Thread Markus Armbruster
Marc-André Lureau  writes:

> Hi
>
> On Wed, Jan 22, 2020 at 4:25 PM Markus Armbruster  wrote:
>>
>> Alex Bennée  writes:
>>
>> > Marc-André Lureau  writes:
>> >> 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...
>> >
>> > As a mostly hands off observer who mainly c's QOM code when he has to
>> > I have to ask is this a long term plan?
>> >
>> > I've always found having our own hand rolled object system a little
>> > incongruous given we lean heavily on the rest of glib.
>>
>> I vaguely remember claims that GObject falls short of our needs.  Sadly,
>> I don't remember the details.  This is why major features should come
>> with a design document.
>>
>> https://wiki.qemu.org/Features/QOM ain't: it does not mention GObject.
>> I'm afraid that page has fallen too far behind the code to be useful to
>> anyone not familiar with the code.
>
>>From the top of my mind, this is the pain point when trying to use GObject:
> - static/inlined object, not supported by GObject, unlikely to ever be

Lame.

Okay for us as long as the pointer chasing stays off the hot paths.  But
that's not obvious.

> - few users in qemu, transition possible.

Peter challenged this idea.

> - 64k limit of GObject, for some reason, unlikely to change but I will
> take a look. Some users in qemu, code adaptation possible.

Also lame.  I figure code adaption will involve pointer chasing.  Again,
beware of hot paths.  This one feels less likely to be a problem,
though.

> - dynamic properties, possible in GObject with hacks, but not
> recommended and going to be deprecated from what I remember

Never understood our need for them for longer than half a day after
getting it explained to me.  I guess that's my fault.  Anyway, the less
we use them, the better.

Hacks exploiting deprecated GObject features would be a bad idea.
Perhaps we can hack something up that doesn't.

> - "array" properties - would need extra layer/tweaks for compatibility

I hated them from day one, tried to kill them, lost the argument.

> - link properties - would need special handling

Hard or not?

> - different limitations for type names and properties names

What to do?

Our naming rules and conventions are weakly documented.

> A possible initial approach is to have all the type system and object
> allocation done by GObject under the hood (what I hacked), while
> keeping all the properties handled by QOM. Then, figure out a
> migration to GObject properties (which are also being refactored a bit
> upstream).

So most QOM properties would be based on a GObject property, but some
wouldn't be, correct?

>If there is enough interest, I will keep investigating. But
> for now, helping with meson seems more urgent.

Yes.

/me warily eyes the monster lurking in the review queue...

[...]




Re: Integrating QOM into QAPI

2020-01-22 Thread Marc-André Lureau
Hi

On Wed, Jan 22, 2020 at 5:28 PM Peter Maydell  wrote:
>
> On Wed, 22 Jan 2020 at 12:42, Marc-André Lureau
>  wrote:
> > From the top of my mind, this is the pain point when trying to use GObject:
> > - static/inlined object, not supported by GObject, unlikely to ever be
> > - few users in qemu, transition possible.
>
> Isn't there lots of use of this in the device emulation, or am I
> misunderstanding what the restriction is?

There are a bunch, from what I remember. Yes, that's a bit painful,
but spatch managed to rewrite most of dev.subdev.foo to
dev.subdev->foo iirc.


-- 
Marc-André Lureau



Re: Integrating QOM into QAPI

2020-01-22 Thread Peter Maydell
On Wed, 22 Jan 2020 at 12:42, Marc-André Lureau
 wrote:
> From the top of my mind, this is the pain point when trying to use GObject:
> - static/inlined object, not supported by GObject, unlikely to ever be
> - few users in qemu, transition possible.

Isn't there lots of use of this in the device emulation, or am I
misunderstanding what the restriction is?

thanks
-- PMM



Re: Integrating QOM into QAPI

2020-01-22 Thread Marc-André Lureau
Hi

On Wed, Jan 22, 2020 at 4:25 PM Markus Armbruster  wrote:
>
> Alex Bennée  writes:
>
> > Marc-André Lureau  writes:
> >> 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...
> >
> > As a mostly hands off observer who mainly c's QOM code when he has to
> > I have to ask is this a long term plan?
> >
> > I've always found having our own hand rolled object system a little
> > incongruous given we lean heavily on the rest of glib.
>
> I vaguely remember claims that GObject falls short of our needs.  Sadly,
> I don't remember the details.  This is why major features should come
> with a design document.
>
> https://wiki.qemu.org/Features/QOM ain't: it does not mention GObject.
> I'm afraid that page has fallen too far behind the code to be useful to
> anyone not familiar with the code.

>From the top of my mind, this is the pain point when trying to use GObject:
- static/inlined object, not supported by GObject, unlikely to ever be
- few users in qemu, transition possible.
- 64k limit of GObject, for some reason, unlikely to change but I will
take a look. Some users in qemu, code adaptation possible.
- dynamic properties, possible in GObject with hacks, but not
recommended and going to be deprecated from what I remember
- "array" properties - would need extra layer/tweaks for compatibility
- link properties - would need special handling
- different limitations for type names and properties names

A possible initial approach is to have all the type system and object
allocation done by GObject under the hood (what I hacked), while
keeping all the properties handled by QOM. Then, figure out a
migration to GObject properties (which are also being refactored a bit
upstream). If there is enough interest, I will keep investigating. But
for now, helping with meson seems more urgent.

>
> >> So introducing GObject-like macros? sure!
> >>
> >> There are plenty of refactoring to do. The problem when touching the
> >> whole code-base, imho, is review time. It may take a couple of
> >> hours/days to come up with a cocci/spatch, and make various patches
> >> here and there. But it takes often weeks and a lot of constant push to
> >> various folks to get all the reviews (as seens by the qdev prop-ptr
> >> series earlier for example). How can we better address whole code-base
> >> changes?
> >
> > The problem with review time - especially for QOM - is having domain
> > knowledge to understand what is happening.
> >
> > Are we happy that the existing qdev/qmp tests sufficiently exercise
> > QEMU's object model? Perhaps with a little extra tweaking of the tests
> > we could dump the object hierarchy and then compare it to the hierarchy
> > presented after modification. That might make it easier to have
> > confidence that these large scale but mostly mechanical changes don't
> > change anything externally visible?
>
> Comparing the composition tree complete with properties and property
> values before and after feels like a useful regression test.  Any
> takers?
>


-- 
Marc-André Lureau



Re: Integrating QOM into QAPI

2020-01-22 Thread Markus Armbruster
Alex Bennée  writes:

> Marc-André Lureau  writes:
>> 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...
>
> As a mostly hands off observer who mainly c's QOM code when he has to
> I have to ask is this a long term plan?
>
> I've always found having our own hand rolled object system a little
> incongruous given we lean heavily on the rest of glib.

I vaguely remember claims that GObject falls short of our needs.  Sadly,
I don't remember the details.  This is why major features should come
with a design document.

https://wiki.qemu.org/Features/QOM ain't: it does not mention GObject.
I'm afraid that page has fallen too far behind the code to be useful to
anyone not familiar with the code.

>> So introducing GObject-like macros? sure!
>>
>> There are plenty of refactoring to do. The problem when touching the
>> whole code-base, imho, is review time. It may take a couple of
>> hours/days to come up with a cocci/spatch, and make various patches
>> here and there. But it takes often weeks and a lot of constant push to
>> various folks to get all the reviews (as seens by the qdev prop-ptr
>> series earlier for example). How can we better address whole code-base
>> changes?
>
> The problem with review time - especially for QOM - is having domain
> knowledge to understand what is happening.
>
> Are we happy that the existing qdev/qmp tests sufficiently exercise
> QEMU's object model? Perhaps with a little extra tweaking of the tests
> we could dump the object hierarchy and then compare it to the hierarchy
> presented after modification. That might make it easier to have
> confidence that these large scale but mostly mechanical changes don't
> change anything externally visible?

Comparing the composition tree complete with properties and property
values before and after feels like a useful regression test.  Any
takers?




Re: Integrating QOM into QAPI

2020-01-22 Thread Alex Bennée


Marc-André Lureau  writes:

> Hi
>
> On Tue, Jan 21, 2020 at 7:01 PM Markus Armbruster  wrote:
>> Daniel P. Berrangé  writes:
>> > On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:

>> >> 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 waaay 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...

As a mostly hands off observer who mainly c's QOM code when he has to
I have to ask is this a long term plan?

I've always found having our own hand rolled object system a little
incongruous given we lean heavily on the rest of glib.

> So introducing GObject-like macros? sure!
>
> There are plenty of refactoring to do. The problem when touching the
> whole code-base, imho, is review time. It may take a couple of
> hours/days to come up with a cocci/spatch, and make various patches
> here and there. But it takes often weeks and a lot of constant push to
> various folks to get all the reviews (as seens by the qdev prop-ptr
> series earlier for example). How can we better address whole code-base
> changes?

The problem with review time - especially for QOM - is having domain
knowledge to understand what is happening.

Are we happy that the existing qdev/qmp tests sufficiently exercise
QEMU's object model? Perhaps with a little extra tweaking of the tests
we could dump the object hierarchy and then compare it to the hierarchy
presented after modification. That might make it easier to have
confidence that these large scale but mostly mechanical changes don't
change anything externally visible?

--
Alex Bennée



Re: Integrating QOM into QAPI

2020-01-21 Thread Peter Maydell
On Tue, 21 Jan 2020 at 15:11, Marc-André Lureau
 wrote:
> There are plenty of refactoring to do. The problem when touching the
> whole code-base, imho, is review time. It may take a couple of
> hours/days to come up with a cocci/spatch, and make various patches
> here and there. But it takes often weeks and a lot of constant push to
> various folks to get all the reviews (as seens by the qdev prop-ptr
> series earlier for example). How can we better address whole code-base
> changes?

It depends. If it's literally just a cocci/spatch mechanical
transformation, I think we should be OK with reviewing that
transform and then applying it; we don't need to get acks
from every submaintainer for that kind of thing. The
prop-ptr series was harder work because it required making
active non-mechanical changes to various devices, which
means the specific changes needed review.

PS: thanks for pushing that prop-ptr work through and
especially the serial device part which was both awkward
and definitely needed.

thanks
-- PMM



Re: Integrating QOM into QAPI

2020-01-21 Thread Marc-André Lureau
Hi

On Tue, Jan 21, 2020 at 7:01 PM Markus Armbruster  wrote:
>
> Daniel P. Berrangé  writes:
>
> > On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:
> >> Marc-André Lureau  writes:
> >>
> >> > Hi
> >> >
> >> > On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi  
> >> > wrote:
> >> >>
> >> >> On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote:
> >> >> > Stefan Hajnoczi  writes:
> >> >> >
> >> >> > > On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote:
> >> >> > >> Christophe de Dinechin  writes:
> >> >> > >> >> On 15 Jan 2020, at 10:20, Markus Armbruster  
> >> >> > >> >> 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 waaay 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 

Re: Integrating QOM into QAPI

2020-01-21 Thread Markus Armbruster
Daniel P. Berrangé  writes:

> On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:
>> Marc-André Lureau  writes:
>> 
>> > Hi
>> >
>> > On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi  wrote:
>> >>
>> >> On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote:
>> >> > Stefan Hajnoczi  writes:
>> >> >
>> >> > > On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote:
>> >> > >> Christophe de Dinechin  writes:
>> >> > >> >> On 15 Jan 2020, at 10:20, Markus Armbruster  
>> >> > >> >> 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 waaay 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
> 

Re: Integrating QOM into QAPI (was: Making QEMU easier for management tools and applications)

2020-01-21 Thread Daniel P . Berrangé
On Tue, Jan 21, 2020 at 02:36:17PM +0100, Markus Armbruster wrote:
> Marc-André Lureau  writes:
> 
> > Hi
> >
> > On Tue, Jan 21, 2020 at 3:32 PM Stefan Hajnoczi  wrote:
> >>
> >> On Tue, Jan 21, 2020 at 06:42:47AM +0100, Markus Armbruster wrote:
> >> > Stefan Hajnoczi  writes:
> >> >
> >> > > On Wed, Jan 15, 2020 at 01:15:17PM +0100, Markus Armbruster wrote:
> >> > >> Christophe de Dinechin  writes:
> >> > >> >> On 15 Jan 2020, at 10:20, Markus Armbruster  
> >> > >> >> 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 waaay 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);