qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v1][ 21/21] qapi: add QAPI code generation docum


From: Lluís
Subject: Re: [Qemu-devel] [PATCH v1][ 21/21] qapi: add QAPI code generation documentation
Date: Thu, 02 Jun 2011 15:25:50 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux)

Here go some minor text corrections.

Michael Roth writes:

> Signed-off-by: Michael Roth <address@hidden>
> ---
>  docs/qapi-code-gen.txt |  315 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 315 insertions(+), 0 deletions(-)
>  create mode 100644 docs/qapi-code-gen.txt

> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> new file mode 100644
> index 0000000..1ba7a9e
> --- /dev/null
> +++ b/docs/qapi-code-gen.txt
> @@ -0,0 +1,315 @@
> += How to use the QAPI code generator =
> +
> +* Note: as of this writing, QMP does not use QAPI. Eventually QMP
> +commands will be converted to use QAPI internally. The following
> +information describes QMP/QAPI as it will exist afterward the
> +conversion.
> +
> +QAPI is a native C API within QEMU which provides management-level
> +functionality to internal/external users. For external
> +users/processes, this interface is made available by a JSON-based
> +QEMU Monitor protocol which provided by the QMP server.

s/which provided/that is provided/


> +
> +To map QMP-defined interfaces to the native C QAPI implementations,
> +and JSON-based schema is used to define types and function

s/and JSON-based/a JSON-based/


> +signatures, and a set of scripts is used to generate types/signatures,
> +and marshaling/dispatch code. The QEMU Guest Agent also uses these
> +scripts, paired with a seperate schema, to generate
> +marshaling/dispatch code for the guest agent server running in the
> +guest.
> +
> +This document will describe how the schemas, scripts, and resulting
> +code is used.
> +
> +
> +== QMP/Guest agent schema ==
> +
> +This file defines the types, commands, and events used by QMP.  It should
> +fully describe the interface used by QMP.
> +
> +This file is designed to be loosely based on JSON although it's technical

s/technical/technically/


> +executable Python.  While dictionaries are used, they are parsed as
> +OrderedDicts so that ordering is preserved.

Valid data types should probably be explained/listed.


> +
> +There are two basic syntaxes used.  The first syntax defines a type and is
> +represented by a dictionary.  There are three kinds of types that are
> +supported.
> +
> +A complex type is a dictionary containing a single key who's value is a
> +dictionary.  This corresponds to a struct in C or an Object in JSON.  An
> +example of a complex type is:
> +
> + { 'type': 'MyType',
> +   'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } }
> +
> +The use of '*' as a prefix to the name means the member is optional.  
> Optional
> +members should always be added to the end of the dictionary to preserve
> +backwards compatibility.
> +
> +An enumeration type is a dictionary containing a single key who's value is a
> +list of strings.  An example enumeration is:
> +
> + { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
> +
> +Generally speaking, complex types and enums should always use CamelCase for
> +the type names.
> +
> +Commands are defined by using a list containing three members.  The first
> +member is the command name, the second member is a dictionary containing
> +arguments, and the third member is the return type.
> +
> +An example command is:
> +
> + { 'command': 'my-command',
> +   'data': { 'arg1': 'str', '*arg2': 'str' },
> +   'returns': 'str' ]
> +
> +Command names should be all lower case with words separated by a hyphen.
> +
> +
> +== Code generation ==
> +
> +Schemas are fed into 3 scripts to generate all the code/files that, paired
> +with the core QAPI libraries, comprise everything required to take JSON
> +commands read in by a QMP/guest agent server, unmarshal the arguments into
> +the underlying C types, call into the corresponding C function, and map the
> +response back to a QMP/guest agent response to be returned to the user.
> +
> +For example usage, we'll use the following schema, which describes a single

s/For example usage/As an (usage )example/


> +complex user-defined type (which will produce a C struct, along with a list
> +node structure that can be used to chain together a list of such types in
> +case we want to accept/return a list of this type with a command), and a
> +command which takes that type as a parameter and returns the same type:
> +
> +    address@hidden:~/w/qemu2.git$ cat example-schema.json 
> +    { 'type': 'UserDefOne',
> +      'data': { 'integer': 'int', 'string': 'str' } }
> +    
> +    { 'commands': 'my-command',

s/commands/command/


> +      'data':     {'arg1': 'UserDefOne'},
> +      'returns':  'UserDefOne' }
> +    address@hidden:~/w/qemu2.git$
> +
> +=== scripts/qapi-types.py ===
> +
> +Used to generate the C types defined by a schema. The following files are
> +created:
> +
> +$(prefix)qapi-types.h - C types corresponding to types defined in
> +                        the schema you pass in
> +$(prefix)qapi-types.c - Cleanup functions for the above C types
> +    
> +The $(prefix) is an optional parameter used to as a namespace to keep the

s/used to as/used as/


> +generated code from one schema/code-generation separated from others so code
> +can be generated/used from multiple schemas without clobbering previously
> +created code.
> +
> +Example:
> +
> +    address@hidden:~/w/qemu2.git$ python scripts/qapi-types.py \
> +      --output-dir="qapi-generated" --prefix="example-" < example-schema.json
> +    address@hidden:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c 
> +    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +
> +    #include "qapi/qapi-dealloc-visiter.h"
> +    #include "example-qapi-types.h"
> +    #include "example-qapi-visit.h"
> +
> +    void qapi_free_UserDefOne(UserDefOne * obj)
> +    {
> +        QapiDeallocVisiter *md;
> +        Visiter *v;
> +
> +        if (!obj) {
> +            return;
> +        }
> +
> +        md = qapi_dealloc_visiter_new();
> +        v = qapi_dealloc_get_visiter(md);
> +        visit_type_UserDefOne(v, &obj, NULL, NULL);
> +        qapi_dealloc_visiter_cleanup(md);
> +    }
> +
> +    address@hidden:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h 
> +    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
> +    #define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
> +
> +    #include "qapi/qapi-types-core.h"
> +
> +    typedef struct UserDefOne UserDefOne;
> +
> +    typedef struct UserDefOneList
> +    {
> +        UserDefOne *value;
> +        struct UserDefOneList *next;
> +    } UserDefOneList;
> +
> +    struct UserDefOne
> +    {
> +        int64_t integer;
> +        char * string;
> +    };
> +
> +    void qapi_free_UserDefOne(UserDefOne * obj);
> +
> +    #endif
> +
> +
> +=== scripts/qapi-visit.py ===
> +
> +Used to generate the visiter functions used to walk through and convert
> +a QObject (as provided by QMP) to a native C data structure and
> +vice-versa, as well as the visiter function used to dealloc a complex
> +schema-defined C type.
> +
> +The following files are generated:
> +
> +$(prefix)qapi-visit.c: visiter function for a particular c type, used

s/c type/C type/


> +                       to automagically convert qobjects into the

s/qobjects/QObjects/


> +                       corresponding C type and vice-versa, as well
> +                       as for deallocating memory for an existing C
> +                       type
> +
> +$(prefix)qapi-visit.h: declarations for previously mentioned visiter
> +                       functions
> +
> +Example:
> +
> +    address@hidden:~/w/qemu2.git$ python scripts/qapi-visit.py \
> +        --output-dir="qapi-generated" --prefix="example-" < 
> example-schema.json
> +    address@hidden:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
> +    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +    
> +    #include "example-qapi-visit.h"
> +    
> +    void visit_type_UserDefOne(Visiter *m, UserDefOne ** obj, const char 
> *name, Error **errp)
> +    {
> +        visit_start_struct(m, (void **)obj, "UserDefOne", name, errp);
> +        visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, 
> "integer", errp);
> +        visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", 
> errp);
> +        visit_end_struct(m, errp);
> +    }
> +    
> +    void visit_type_UserDefOneList(Visiter *m, UserDefOneList ** obj, const 
> char *name, Error **errp)
> +    {
> +        GenericList *i;
> +    
> +        visit_start_list(m, name, errp);
> +    
> +        for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = 
> visit_next_list(m, &i, errp)) {
> +            UserDefOneList *native_i = (UserDefOneList *)i;
> +            visit_type_UserDefOne(m, &native_i->value, NULL, errp);
> +        }
> +    
> +        visit_end_list(m, errp);
> +    }
> +    address@hidden:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
> +    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +    
> +    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
> +    #define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
> +    
> +    #include "qapi/qapi-visit-core.h"
> +    #include "example-qapi-types.h"
> +    
> +    void visit_type_UserDefOne(Visiter *m, UserDefOne ** obj, const char 
> *name, Error **errp);
> +    void visit_type_UserDefOneList(Visiter *m, UserDefOneList ** obj, const 
> char *name, Error **errp);
> +    
> +    #endif
> +    address@hidden:~/w/qemu2.git$
> +
> +
> +=== scripts/qapi-commands.py ===
> +
> +Used to generate the marshaling/dispatch functions for the commands defined
> +in the schema. The following files are generated:
> +
> +$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
> +                        QMP command defined in the schema. Functions
> +                        generated by qapi-visit.py are used to
> +                        convert qobjects recieved from the wire into

s/qobjects/QObjects/


> +                        function parameters, and uses the same
> +                        visiter functions to convert native C return
> +                        values to qobjects from transmission back

s/qobjects/QObjects/


> +                        over the wire.
> +
> +$(prefix)qmp-commands.h: Function prototypes for the QMP commands
> +                         specified in the schema.
> +
> +Example:
> +
> +    address@hidden:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c 
> +    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +    
> +    #include "qemu-objects.h"
> +    #include "qapi/qmp-core.h"
> +    #include "qapi/qapi-visit-core.h"
> +    #include "qapi/qmp-output-visiter.h"
> +    #include "qapi/qmp-input-visiter.h"
> +    #include "qapi/qapi-dealloc-visiter.h"
> +    #include "example-qapi-types.h"
> +    #include "example-qapi-visit.h"
> +    
> +    #include "example-qmp-commands.h"
> +    static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject 
> **ret_out, Error **errp)
> +    {
> +        QapiDeallocVisiter *md = qapi_dealloc_visiter_new();
> +        QmpOutputVisiter *mo = qmp_output_visiter_new();
> +        Visiter *v;
> +        
> +        v = qmp_output_get_visiter(mo);
> +        visit_type_UserDefOne(v, &ret_in, "unused", errp);
> +        v = qapi_dealloc_get_visiter(md);
> +        visit_type_UserDefOne(v, &ret_in, "unused", errp);
> +        qapi_dealloc_visiter_cleanup(md);
> +        
> +    
> +        *ret_out = qmp_output_get_qobject(mo);
> +    }
> +    
> +    static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict 
> *args, QObject **ret, Error **errp)
> +    {
> +        UserDefOne * retval = NULL;
> +        QmpInputVisiter *mi;
> +        QapiDeallocVisiter *md;
> +        Visiter *v;
> +        UserDefOne * arg1 = NULL;
> +    
> +        mi = qmp_input_visiter_new(QOBJECT(args));
> +        v = qmp_input_get_visiter(mi);
> +        visit_type_UserDefOne(v, &arg1, "arg1", errp);
> +    
> +        if (error_is_set(errp)) {
> +            goto out;
> +        }
> +        retval = qmp_my_command(arg1, errp);
> +        qmp_marshal_output_my_command(retval, ret, errp);
> +    
> +    out:
> +        md = qapi_dealloc_visiter_new();
> +        v = qapi_dealloc_get_visiter(md);
> +        visit_type_UserDefOne(v, &arg1, "arg1", errp);
> +        qapi_dealloc_visiter_cleanup(md);
> +        return;
> +    }
> +    
> +    static void qmp_init_marshal(void)
> +    {
> +        qmp_register_command("my-command", qmp_marshal_input_my_command);
> +    }
> +    
> +    qapi_init(qmp_init_marshal);
> +    address@hidden:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h 
> +    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +    
> +    #ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
> +    #define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
> +    
> +    #include "example-qapi-types.h"
> +    #include "error.h"
> +    
> +    UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
> +    
> +    #endif
> +    address@hidden:~/w/qemu2.git$
> -- 
> 1.7.0.4

-- 
 "And it's much the same thing with knowledge, for whenever you learn
 something new, the whole world becomes that much richer."
 -- The Princess of Pure Reason, as told by Norton Juster in The Phantom
 Tollbooth



reply via email to

[Prev in Thread] Current Thread [Next in Thread]