Message ID | 1306949089-15597-22-git-send-email-mdroth@linux.vnet.ibm.com |
---|---|
State | New |
Headers | show |
Here go some minor text corrections. Michael Roth writes: > Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com> > --- > 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: > + > + mdroth@illuin:~/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' } > + 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 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: > + > + 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-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); > + } > + > + 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 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: > + > + 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(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); > + } > + 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(Visiter *m, UserDefOne ** obj, const char *name, Error **errp); > + void visit_type_UserDefOneList(Visiter *m, UserDefOneList ** obj, const char *name, Error **errp); > + > + #endif > + mdroth@illuin:~/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: > + > + 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-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); > + 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$ > -- > 1.7.0.4
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. + +To map QMP-defined interfaces to the native C QAPI implementations, +and 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 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 +executable Python. While dictionaries are used, they are parsed as +OrderedDicts so that ordering is preserved. + +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 +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' } } + + { 'commands': '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 to 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-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); + } + + 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 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 + 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 visiter + 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(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); + } + 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(Visiter *m, UserDefOne ** obj, const char *name, Error **errp); + void visit_type_UserDefOneList(Visiter *m, UserDefOneList ** obj, const char *name, Error **errp); + + #endif + mdroth@illuin:~/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 + function parameters, and uses the same + visiter 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-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); + 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$
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com> --- docs/qapi-code-gen.txt | 315 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 315 insertions(+), 0 deletions(-) create mode 100644 docs/qapi-code-gen.txt