 d195325b05
			
		
	
	
		d195325b05
		
	
	
	
	
		
			
			Don't overwrite / leak previously set errors. Make traversal cope with missing mandatory sub-structs. Don't try to end a container that could not be started. v1->v2: - unchanged v2->v3: - instead of examining, assert that we never overwrite errors with error_set() - allow visitors to set a NULL struct pointer successfully, so traversal of incomplete objects can continue - check for a NULL "obj" before accessing "(*obj)->has_XXX" (this is not a typo, "obj != NULL" implies "*obj != NULL" here) - fix start_struct / end_struct balance for unions as well Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
		
			
				
	
	
		
			319 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			319 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| = 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 after 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 that is provided by the QMP server.
 | |
| 
 | |
| To map QMP-defined interfaces to the native C QAPI implementations,
 | |
| a JSON-based schema is used to define types and function
 | |
| 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 separate 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 technically
 | |
| executable Python.  While dictionaries are used, they are parsed as
 | |
| OrderedDicts so that ordering is preserved.
 | |
| 
 | |
| There are two basic syntaxes used, type definitions and command definitions.
 | |
| 
 | |
| The first syntax defines a type and is represented by a dictionary.  There are
 | |
| two kinds of types that are supported: complex user-defined types, and enums.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| As an example, we'll use the following schema, which describes a single
 | |
| 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:
 | |
| 
 | |
|     mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
 | |
|     { 'type': 'UserDefOne',
 | |
|       'data': { 'integer': 'int', 'string': 'str' } }
 | |
| 
 | |
|     { 'command': 'my-command',
 | |
|       'data':    {'arg1': 'UserDefOne'},
 | |
|       'returns': 'UserDefOne' }
 | |
|     mdroth@illuin:~/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 as a namespace to keep the
 | |
| 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:
 | |
| 
 | |
|     mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
 | |
|       --output-dir="qapi-generated" --prefix="example-" < example-schema.json
 | |
|     mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
 | |
|     /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
 | |
| 
 | |
|     #include "qapi/qapi-dealloc-visitor.h"
 | |
|     #include "example-qapi-types.h"
 | |
|     #include "example-qapi-visit.h"
 | |
| 
 | |
|     void qapi_free_UserDefOne(UserDefOne * obj)
 | |
|     {
 | |
|         QapiDeallocVisitor *md;
 | |
|         Visitor *v;
 | |
| 
 | |
|         if (!obj) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         md = qapi_dealloc_visitor_new();
 | |
|         v = qapi_dealloc_get_visitor(md);
 | |
|         visit_type_UserDefOne(v, &obj, NULL, NULL);
 | |
|         qapi_dealloc_visitor_cleanup(md);
 | |
|     }
 | |
| 
 | |
|     mdroth@illuin:~/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 visitor 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 visitor function used to dealloc a complex
 | |
| schema-defined C type.
 | |
| 
 | |
| The following files are generated:
 | |
| 
 | |
| $(prefix)qapi-visit.c: visitor function for a particular C type, used
 | |
|                        to automagically convert QObjects into the
 | |
|                        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 visitor
 | |
|                        functions
 | |
| 
 | |
| Example:
 | |
| 
 | |
|     mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
 | |
|         --output-dir="qapi-generated" --prefix="example-" < example-schema.json
 | |
|     mdroth@illuin:~/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(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
 | |
|     {
 | |
|         visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), 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(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
 | |
|     {
 | |
|         GenericList *i, **prev = (GenericList **)obj;
 | |
| 
 | |
|         visit_start_list(m, name, errp);
 | |
| 
 | |
|         for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
 | |
|             UserDefOneList *native_i = (UserDefOneList *)i;
 | |
|             visit_type_UserDefOne(m, &native_i->value, NULL, errp);
 | |
|         }
 | |
| 
 | |
|         visit_end_list(m, errp);
 | |
|     }
 | |
|     mdroth@illuin:~/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(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
 | |
|     void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
 | |
| 
 | |
|     #endif
 | |
|     mdroth@illuin:~/w/qemu2.git$
 | |
| 
 | |
| (The actual structure of the visit_type_* functions is a bit more complex
 | |
| in order to propagate errors correctly and avoid leaking memory).
 | |
| 
 | |
| === 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 received from the wire into
 | |
|                         function parameters, and uses the same
 | |
|                         visitor functions to convert native C return
 | |
|                         values to QObjects from transmission back
 | |
|                         over the wire.
 | |
| 
 | |
| $(prefix)qmp-commands.h: Function prototypes for the QMP commands
 | |
|                          specified in the schema.
 | |
| 
 | |
| Example:
 | |
| 
 | |
|     mdroth@illuin:~/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-visitor.h"
 | |
|     #include "qapi/qmp-input-visitor.h"
 | |
|     #include "qapi/qapi-dealloc-visitor.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)
 | |
|     {
 | |
|         QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
 | |
|         QmpOutputVisitor *mo = qmp_output_visitor_new();
 | |
|         Visitor *v;
 | |
| 
 | |
|         v = qmp_output_get_visitor(mo);
 | |
|         visit_type_UserDefOne(v, &ret_in, "unused", errp);
 | |
|         v = qapi_dealloc_get_visitor(md);
 | |
|         visit_type_UserDefOne(v, &ret_in, "unused", errp);
 | |
|         qapi_dealloc_visitor_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;
 | |
|         QmpInputVisitor *mi;
 | |
|         QapiDeallocVisitor *md;
 | |
|         Visitor *v;
 | |
|         UserDefOne * arg1 = NULL;
 | |
| 
 | |
|         mi = qmp_input_visitor_new(QOBJECT(args));
 | |
|         v = qmp_input_get_visitor(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_visitor_new();
 | |
|         v = qapi_dealloc_get_visitor(md);
 | |
|         visit_type_UserDefOne(v, &arg1, "arg1", errp);
 | |
|         qapi_dealloc_visitor_cleanup(md);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     static void qmp_init_marshal(void)
 | |
|     {
 | |
|         qmp_register_command("my-command", qmp_marshal_input_my_command);
 | |
|     }
 | |
| 
 | |
|     qapi_init(qmp_init_marshal);
 | |
|     mdroth@illuin:~/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
 | |
|     mdroth@illuin:~/w/qemu2.git$
 |