qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Avi Kivity <avi@redhat.com>
To: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: aliguori@us.ibm.com, yamahata@valinux.co.jp, quintela@redhat.com,
	qemu-devel@nongnu.org, owasserm@redhat.com, pbonzini@redhat.com,
	akong@redhat.com, afaerber@suse.de
Subject: Re: [Qemu-devel] [PATCH 01/17] qidl: add QEMU IDL processor
Date: Tue, 05 Jun 2012 13:06:10 +0300	[thread overview]
Message-ID: <4FCDDA12.4040907@redhat.com> (raw)
In-Reply-To: <1338858018-17189-2-git-send-email-mdroth@linux.vnet.ibm.com>

On 06/05/2012 04:00 AM, Michael Roth wrote:
> This is an import of Anthony's qidl compiler, with some changes squashed
> in to add support for doing the visitor generation via QEMU's qapi code
> generators rather than directly.
> 
> Documentation has been imported as well, as is also viewable at:
> 
> https://github.com/aliguori/qidl/blob/master/qc.md
> 
> This will be used to add annotations to device structs to aid in
> generating visitors that can be used to serialize/unserialize them.
> 
> +
> +    typedef struct SerialDevice {
> +        SysBusDevice parent;
> +    
> +        uint8_t thr;            // transmit holding register
> +        uint8_t lsr;            // line status register
> +        uint8_t ier;            // interrupt enable register
> +    
> +        int int_pending;        // whether we have a pending queued interrupt
> +        CharDriverState *chr;   // backend
> +    } SerialDevice;
> +
> +Getting Started
> +---------------
> +
> +The first step is to move your device struct definition to a header file.  This
> +header file should only contain the struct definition and any preprocessor
> +declarations you need to define the structure.  This header file will act as
> +the source for the QC IDL compiler.
> +

Is is possible to let the compiler process the .c file, with the IDL
delimited by some marker?  I like how device models are self contained
in one file now.


> +Do not include any function declarations in this header file as QC does not
> +understand function declarations.
> +
> +Determining What State Gets Saved
> +---------------------------------
> +
> +By default, QC saves every field in a structure it sees.  This provides maximum
> +correctness by default.  However, device structures generally contain state
> +that reflects state that is in someway duplicated or not guest visible.  This
> +more often that not reflects design implementation details.
> +
> +Since design implementation details change over time, saving this state makes
> +compatibility hard to maintain since it would effectively lock down a device's
> +implementation.
> +
> +QC allows a device author to suppress certain fields from being saved although
> +there are very strict rules about when this is allowed and what needs to be done
> +to ensure that this does not impact correctness.
> +
> +There are three cases where state can be suppressed: when it is **immutable**,
> +**derived**, or **broken**.  

There is a fourth class, non-guest-visible state (below).  There is a
fifth class, migrated by other means, which includes memory and block
device state, but of course it isn't interesting in this context.

In addition, QC can decide at run time whether to
> +suppress a field by assigning it a **default** value.
> +
> +## Immutable Fields
> +
> +If a field is only set during device construction, based on parameters passed to
> +the device's constructor, then there is no need to send save and restore this
> +value.  We call these fields immutable and we tell QC about this fact by using
> +a **_immutable** marker.
> +
> +In our *SerialDevice* example, the *CharDriverState* pointer reflects the host
> +backend that we use to send serial output to the user.  This is only assigned
> +during device construction and never changes.  This means we can add an
> +**_immutable** marker to it:

Even if it does change (suppose we add a monitor command to retarget a
the serial device's chardev), it need not be migrated since it doesn't
describe guest state, only host state.  Maybe we should mark *chr _host
instead of _immutable.

> +
> +    typedef struct SerialDevice {
> +        SysBusDevice parent;
> +    
> +        uint8_t thr;            // transmit holding register
> +        uint8_t lsr;            // line status register
> +        uint8_t ier;            // interrupt enable register
> +    
> +        int int_pending;        // whether we have a pending queued interrupt
> +        CharDriverState _immutable *chr;
> +    } SerialDevice;
> +
> +When reviewing patches that make use of the **_immutable** marker, the following
> +guidelines should be followed to determine if the marker is being used
> +correctly.
> +
> + 1. Check to see if the field is assigned anywhere other than the device
> +    initialization function.
> +
> + 2. Check to see if any function is being called that modifies the state of the
> +    field outside of the initialization function.
> +
> +It can be subtle whether a field is truly immutable.  A good example is a
> +*QEMUTimer*.  Timer's will usually have their timeout modified with a call to
> +*qemu_mod_timer()* even though they are only assigned in the device
> +initialization function.

I think this is where _host is useful.  You can have two QEMUTimers, one
driven by the guest and the other by the host (like, say, the display
refresh timer).  You would want to migrate one but not the other.

> +
> +If the timer is always modified with a fixed value that is not dependent on
> +guest state, then the timer is immutable since it's unaffected by the state of
> +the guest.
> +
> +On the other hand, if the timer is modified based on guest state (such as a
> +guest programmed time out), then the timer carries state.  It may be necessary
> +to save/restore the timer or mark it as **_derived** and work with it
> +accordingly.
> +
> +### Derived Fields
> +
> +If a field is set based on some other field in the device's structure, then its
> +value is derived.  Since this is effectively duplicate state, we can avoid
> +sending it and then recompute it when we need to.  Derived state requires a bit
> +more handling that immutable state.
> +
> +In our *SerialDevice* example, our *int_pending* flag is really derived from
> +two pieces of state.  It is set based on whether interrupts are enabled in the
> +*ier* register and whether there is *THRE* flag is not set in the *lsr*
> +register.

Device model authors should be encouraged to avoid derived state in
simple cases like that, instead use a function.

> +
> +To mark a field as derived, use the **_derived** marker.  To update our
> +example, we would do:
> +
> +    typedef struct SerialDevice {
> +        SysBusDevice parent;
> +    
> +        uint8_t thr;            // transmit holding register
> +        uint8_t lsr;            // line status register
> +        uint8_t ier;            // interrupt enable register
> +    
> +        int _derived int_pending; // whether we have a pending queued interrupt
> +        CharDriverState _immutable *chr;
> +    } SerialDevice;
> +
> +There is one other critical step needed when marking a field as derived.  A
> +*post_load* function must be added that updates this field after loading the
> +rest of the device state.  This function is implemented in the device's source
> +file, not in the QC header.  Below is an example of what this function may do:
> +
> +    static void serial_post_load(SerialDevice *s)
> +    {
> +        s->int_pending = !(s->lsr & THRE) && (s->ier & INTE);
> +    }
> +
> +When reviewing a patch that marks a field as *_derived*, the following criteria
> +should be used:
> +
> + 1. Does the device have a post load function?
> +
> + 2. Does the post load function assign a value to all of the derived fields?
> +
> + 3. Are there any obvious places where a derived field is holding unique state?
> +

<snip>

Suggestion: add a _guest marker for ordinary state.  Fail the build on
unmarked fields.  This ensures that some thought is given to each field,
instead of having a default that may be correct most of the time, but
not always.

Suggestion: add a mandatory position hint (_guest(7) or _pos(7)) that
generates ordering within the fields.  This decouples the order of lines
in the struct from the protocol, so you can add state where it make
sense, or rearrange lines when they don't, and detect copy/paste errors.


> diff --git a/scripts/qc.py b/scripts/qc.py
> new file mode 100755
> index 0000000..74f2a40
> --- /dev/null
> +++ b/scripts/qc.py
> @@ -0,0 +1,494 @@
> +#!/usr/bin/python
> +
> +import sys
> +from ordereddict import OrderedDict
> +
> +marker = "qc_declaration"
> +marked = False
> +
> +class Input(object):
> +    def __init__(self, fp):
> +        self.fp = fp
> +        self.buf = ''
> +        self.eof = False
> +
> +    def pop(self):
> +        if len(self.buf) == 0:
> +            if self.eof:
> +                return ''
> +
> +            data = self.fp.read(1024)
> +            if data == '':
> +                self.eof = True
> +                return ''
> +
> +            self.buf += data
> +
> +        ch = self.buf[0]
> +        self.buf = self.buf[1:]
> +        return ch


Could be simplified as fp.read(1).  Does the performance really suffer
if you read a byte at a time?

> +
> +def in_range(ch, start, end):
> +    if ch >= start and ch <= end:
> +        return True
> +    return False
> +
> +# D			[0-9]
> +# L			[a-zA-Z_]
> +# H			[a-fA-F0-9]
> +# E			[Ee][+-]?{D}+
> +# FS			(f|F|l|L)
> +# IS			(u|U|l|L)*
> +
> +def is_D(ch):
> +    return in_range(ch, '0', '9')
> +
> +def is_L(ch):
> +    return in_range(ch, 'a', 'z') or in_range(ch, 'A', 'Z') or ch == '_'
> +
> +def is_H(ch):
> +    return in_range(ch, 'a', 'f') or in_range(ch, 'A', 'F') or is_D(ch)
> +
> +def is_FS(ch):
> +    return ch in 'fFlL'
> +
> +def is_IS(ch):
> +    return ch in 'uUlL'


import re

D = re.compile(r'[0-9]')
...
IS = re.compile(r'[uUlL]+')

<snip parser>

Surely there are available lexer/parser packages?


-- 
error compiling committee.c: too many arguments to function

  parent reply	other threads:[~2012-06-05 10:06 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-05  1:00 [Qemu-devel] [RFC] Use QEMU IDL for device serialization/vmstate Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 01/17] qidl: add QEMU IDL processor Michael Roth
2012-06-05  1:57   ` Anthony Liguori
2012-06-05  9:25   ` Kevin Wolf
2012-06-05  9:47     ` Anthony Liguori
2012-06-05 10:11       ` Kevin Wolf
2012-06-05 16:21     ` Michael Roth
2012-06-05 19:56       ` Paolo Bonzini
2012-06-05 23:40         ` Anthony Liguori
2012-06-06  5:12           ` Paolo Bonzini
2012-06-06  5:43             ` Anthony Liguori
2012-06-06  7:30       ` Kevin Wolf
2012-06-05 10:00   ` Peter Maydell
2012-06-05 10:10     ` Anthony Liguori
2012-06-11  7:13     ` Andreas Färber
2012-06-11  7:20       ` Paolo Bonzini
2012-06-11  7:56         ` Andreas Färber
2012-06-11  7:59           ` Paolo Bonzini
2012-06-11  9:02             ` Andreas Färber
2012-06-11  8:04           ` Andreas Färber
2012-06-11 13:12         ` Anthony Liguori
2012-06-11 13:37           ` Peter Maydell
2012-06-11 13:09       ` Peter Maydell
2012-06-05 10:06   ` Avi Kivity [this message]
2012-06-05 12:19     ` Gerd Hoffmann
2012-06-05 23:41       ` Anthony Liguori
2012-06-06  7:19       ` Avi Kivity
2012-06-05 21:11     ` Michael Roth
2012-06-06  7:31       ` Avi Kivity
2012-06-06 21:36         ` Michael Roth
2012-06-07  7:08           ` Avi Kivity
2012-06-05 23:51     ` Anthony Liguori
2012-06-06  1:25       ` Peter Maydell
2012-06-06  7:45       ` Avi Kivity
2012-06-06  8:27         ` Anthony Liguori
2012-06-06  8:37           ` Avi Kivity
2012-06-06  8:45             ` Anthony Liguori
2012-06-06  8:59               ` Avi Kivity
2012-06-06  9:17                 ` Anthony Liguori
2012-06-06  9:58                   ` Avi Kivity
2012-06-06 11:12                     ` Anthony Liguori
2012-06-06 11:25                       ` Avi Kivity
2012-06-06 23:20     ` Anthony Liguori
2012-06-05  1:00 ` [Qemu-devel] [PATCH 02/17] qidl: add qc definitions Michael Roth
2012-06-05  9:25   ` Kevin Wolf
2012-06-05 10:35   ` Jan Kiszka
2012-06-05 11:12     ` Anthony Liguori
2012-06-05 11:26       ` Jan Kiszka
2012-06-05 11:42         ` Kevin Wolf
2012-06-05 14:08   ` Paolo Bonzini
2012-06-05 21:44     ` Michael Roth
2012-06-05 23:35       ` Anthony Liguori
2012-06-05  1:00 ` [Qemu-devel] [PATCH 03/17] qapi: add visitor interfaces for arrays Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 04/17] qapi: QmpOutputVisitor, implement array handling Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 05/17] qapi: qapi-visit.py, support arrays and complex qapi definitions Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 06/17] qapi: qapi-visit.py, add gen support for existing types Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 07/17] qapi: add open-coded visitors for QEMUTimer/struct tm types Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 08/17] rtc: move RTCState declaration to header Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 09/17] rtc: add qc annotations Michael Roth
2012-06-05 10:25   ` Avi Kivity
2012-06-05 10:40     ` Jan Kiszka
2012-06-05 12:42       ` Avi Kivity
2012-06-05 22:07         ` Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 10/17] Makefile: add infrastructure to incorporate qidl-generated files Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 11/17] qapi: add qidl-generated qapi schema for rtc Michael Roth
2012-06-05  9:29   ` Kevin Wolf
2012-06-05 16:03     ` Michael Roth
2012-06-06  7:38       ` Kevin Wolf
2012-06-06 22:40         ` Michael Roth
2012-06-05 10:11   ` Avi Kivity
2012-06-05  1:00 ` [Qemu-devel] [PATCH 12/17] rtc: add a QOM property for accessing device state Michael Roth
2012-06-05 14:14   ` Paolo Bonzini
2012-06-05 17:54     ` Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 13/17] rtc: add _version() qidl annotations Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 14/17] qidl: add qidl-based generation of vmstate field bindings Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 15/17] Makefile: add qidl-generation of vmstate field descriptions Michael Roth
2012-06-05  1:00 ` [Qemu-devel] [PATCH 16/17] qidl: add qidl-generated vmstate fields for rtc Michael Roth
2012-06-05 10:26   ` Avi Kivity
2012-06-05 23:38     ` Anthony Liguori
2012-06-06  7:47       ` Avi Kivity
2012-06-05  1:00 ` [Qemu-devel] [PATCH 17/17] rtc: use qidl-generated vmstate bindings Michael Roth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4FCDDA12.4040907@redhat.com \
    --to=avi@redhat.com \
    --cc=afaerber@suse.de \
    --cc=akong@redhat.com \
    --cc=aliguori@us.ibm.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=owasserm@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    --cc=yamahata@valinux.co.jp \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).