mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 10:34:58 -06:00
docs/devel/writing-monitor-commands: Repair a decade of rot
The tutorial doesn't match reality since at least 2013. Repairing it involves fixing the following issues: * Update for commit6d32717155
(aio / timers: Remove alarm timers): replace the broken examples. Instead of having one for returning a struct and another for returning a list of structs, do just one for the latter. This resolves the FIXME added in commite218052f92
(aio / timers: De-document -clock) back in 2014. * Update for commit895a2a80e0
(qapi: Use 'struct' instead of 'type' in schema). * Update for commit3313b6124b
(qapi: add qapi2texi script): add required documentation to the schema snippets, and drop section "Command Documentation". * Update for commita3c45b3e62
(qapi: New special feature flag "unstable"): supply the required feature, deemphasize the x- prefix. * Update for commitdd98234c05
(qapi: introduce x-query-roms QMP command): rephrase from "add new command" to "examine existing command". * Update for commit9492718b7c
(qapi misc: Elide redundant has_FOO in generated C): hello-world's message argument no longer comes with a has_message, add a second argument that does. * Update for moved and renamed files. While there, update QMP version output to current output. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-ID: <20240227115617.237875-2-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [Whitespace tidied up, typo fixed]
This commit is contained in:
parent
e1f684ea2e
commit
59807e2098
1 changed files with 184 additions and 282 deletions
|
@ -66,12 +66,13 @@ Then, in a different terminal::
|
||||||
"version": {
|
"version": {
|
||||||
"qemu": {
|
"qemu": {
|
||||||
"micro": 50,
|
"micro": 50,
|
||||||
"minor": 15,
|
"minor": 2,
|
||||||
"major": 0
|
"major": 8
|
||||||
},
|
},
|
||||||
"package": ""
|
"package": ...
|
||||||
},
|
},
|
||||||
"capabilities": [
|
"capabilities": [
|
||||||
|
"oob"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +108,11 @@ The first step is defining the command in the appropriate QAPI schema
|
||||||
module. We pick module qapi/misc.json, and add the following line at
|
module. We pick module qapi/misc.json, and add the following line at
|
||||||
the bottom::
|
the bottom::
|
||||||
|
|
||||||
|
##
|
||||||
|
# @hello-world:
|
||||||
|
#
|
||||||
|
# Since: 9.0
|
||||||
|
##
|
||||||
{ 'command': 'hello-world' }
|
{ 'command': 'hello-world' }
|
||||||
|
|
||||||
The "command" keyword defines a new QMP command. It's an JSON object. All
|
The "command" keyword defines a new QMP command. It's an JSON object. All
|
||||||
|
@ -148,37 +154,50 @@ you don't see it then something went wrong.
|
||||||
Arguments
|
Arguments
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
Let's add an argument called "message" to our "hello-world" command. The new
|
Let's add arguments to our "hello-world" command.
|
||||||
argument will contain the string to be printed to stdout. It's an optional
|
|
||||||
argument, if it's not present we print our default "Hello, World" string.
|
|
||||||
|
|
||||||
The first change we have to do is to modify the command specification in the
|
The first change we have to do is to modify the command specification in the
|
||||||
schema file to the following::
|
schema file to the following::
|
||||||
|
|
||||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
##
|
||||||
|
# @hello-world:
|
||||||
|
#
|
||||||
|
# @message: message to be printed (default: "Hello, world!")
|
||||||
|
#
|
||||||
|
# @times: how many times to print the message (default: 1)
|
||||||
|
#
|
||||||
|
# Since: 9.0
|
||||||
|
##
|
||||||
|
{ 'command': 'hello-world',
|
||||||
|
'data': { '*message': 'str', '*times': 'int' } }
|
||||||
|
|
||||||
Notice the new 'data' member in the schema. It's an JSON object whose each
|
Notice the new 'data' member in the schema. It specifies an argument
|
||||||
element is an argument to the command in question. Also notice the asterisk,
|
'message' of QAPI type 'str', and an argument 'times' of QAPI type
|
||||||
it's used to mark the argument optional (that means that you shouldn't use it
|
'int'. Also notice the asterisk, it's used to mark the argument
|
||||||
for mandatory arguments). Finally, 'str' is the argument's type, which
|
optional.
|
||||||
stands for "string". The QAPI also supports integers, booleans, enumerations
|
|
||||||
and user defined types.
|
|
||||||
|
|
||||||
Now, let's update our C implementation in monitor/qmp-cmds.c::
|
Now, let's update our C implementation in monitor/qmp-cmds.c::
|
||||||
|
|
||||||
void qmp_hello_world(const char *message, Error **errp)
|
void qmp_hello_world(const char *message, bool has_times, int64_t times,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
if (message) {
|
if (!message) {
|
||||||
|
message = "Hello, world";
|
||||||
|
}
|
||||||
|
if (!has_times) {
|
||||||
|
times = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < times; i++) {
|
||||||
printf("%s\n", message);
|
printf("%s\n", message);
|
||||||
} else {
|
|
||||||
printf("Hello, world\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
There are two important details to be noticed:
|
There are two important details to be noticed:
|
||||||
|
|
||||||
1. All optional arguments are accompanied by a 'has\_' boolean, which is set
|
1. Optional arguments other than pointers are accompanied by a 'has\_'
|
||||||
if the optional argument is present or false otherwise
|
boolean, which is set if the optional argument is present or false
|
||||||
|
otherwise
|
||||||
2. The C implementation signature must follow the schema's argument ordering,
|
2. The C implementation signature must follow the schema's argument ordering,
|
||||||
which is defined by the "data" member
|
which is defined by the "data" member
|
||||||
|
|
||||||
|
@ -254,35 +273,6 @@ If the failure you want to report falls into one of the two cases above,
|
||||||
use error_set() with a second argument of an ErrorClass value.
|
use error_set() with a second argument of an ErrorClass value.
|
||||||
|
|
||||||
|
|
||||||
Command Documentation
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
There's only one step missing to make "hello-world"'s implementation complete,
|
|
||||||
and that's its documentation in the schema file.
|
|
||||||
|
|
||||||
There are many examples of such documentation in the schema file already, but
|
|
||||||
here goes "hello-world"'s new entry for qapi/misc.json::
|
|
||||||
|
|
||||||
##
|
|
||||||
# @hello-world:
|
|
||||||
#
|
|
||||||
# Print a client provided string to the standard output stream.
|
|
||||||
#
|
|
||||||
# @message: string to be printed
|
|
||||||
#
|
|
||||||
# Returns: Nothing on success.
|
|
||||||
#
|
|
||||||
# Notes: if @message is not provided, the "Hello, world" string will
|
|
||||||
# be printed instead
|
|
||||||
#
|
|
||||||
# Since: <next qemu stable release, eg. 1.0>
|
|
||||||
##
|
|
||||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
|
||||||
|
|
||||||
Please, note that the "Returns" clause is optional if a command doesn't return
|
|
||||||
any data nor any errors.
|
|
||||||
|
|
||||||
|
|
||||||
Implementing the HMP command
|
Implementing the HMP command
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -306,18 +296,20 @@ Here's the implementation of the "hello-world" HMP command::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Also, you have to add the function's prototype to the hmp.h file.
|
Add it to monitor/hmp-cmds.c. Also, add its prototype to
|
||||||
|
include/monitor/hmp.h.
|
||||||
|
|
||||||
There are three important points to be noticed:
|
There are four important points to be noticed:
|
||||||
|
|
||||||
1. The "mon" and "qdict" arguments are mandatory for all HMP functions. The
|
1. The "mon" and "qdict" arguments are mandatory for all HMP functions. The
|
||||||
former is the monitor object. The latter is how the monitor passes
|
former is the monitor object. The latter is how the monitor passes
|
||||||
arguments entered by the user to the command implementation
|
arguments entered by the user to the command implementation
|
||||||
2. hmp_hello_world() performs error checking. In this example we just call
|
2. We chose not to support the "times" argument in HMP
|
||||||
|
3. hmp_hello_world() performs error checking. In this example we just call
|
||||||
hmp_handle_error() which prints a message to the user, but we could do
|
hmp_handle_error() which prints a message to the user, but we could do
|
||||||
more, like taking different actions depending on the error
|
more, like taking different actions depending on the error
|
||||||
qmp_hello_world() returns
|
qmp_hello_world() returns
|
||||||
3. The "err" variable must be initialized to NULL before performing the
|
4. The "err" variable must be initialized to NULL before performing the
|
||||||
QMP call
|
QMP call
|
||||||
|
|
||||||
There's one last step to actually make the command available to monitor users,
|
There's one last step to actually make the command available to monitor users,
|
||||||
|
@ -372,7 +364,7 @@ data, it is not expected that machines will need to parse the result.
|
||||||
The overhead of defining a fine grained QAPI type for the data may not
|
The overhead of defining a fine grained QAPI type for the data may not
|
||||||
be justified by the potential benefit. In such cases, it is permitted
|
be justified by the potential benefit. In such cases, it is permitted
|
||||||
to have a command return a simple string that contains formatted data,
|
to have a command return a simple string that contains formatted data,
|
||||||
however, it is mandatory for the command to use the 'x-' name prefix.
|
however, it is mandatory for the command to be marked unstable.
|
||||||
This indicates that the command is not guaranteed to be long term
|
This indicates that the command is not guaranteed to be long term
|
||||||
stable / liable to change in future and is not following QAPI design
|
stable / liable to change in future and is not following QAPI design
|
||||||
best practices. An example where this approach is taken is the QMP
|
best practices. An example where this approach is taken is the QMP
|
||||||
|
@ -386,302 +378,207 @@ an illustration.
|
||||||
User Defined Types
|
User Defined Types
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
FIXME This example needs to be redone after commit 6d32717
|
For this example we will write the query-option-roms command, which
|
||||||
|
returns information about ROMs loaded into the option ROM space. For
|
||||||
|
more information about it, please check the "-option-rom" command-line
|
||||||
|
option.
|
||||||
|
|
||||||
For this example we will write the query-alarm-clock command, which returns
|
For each option ROM, we want to return two pieces of information: the
|
||||||
information about QEMU's timer alarm. For more information about it, please
|
ROM image's file name, and its bootindex, if any. We need to create a
|
||||||
check the "-clock" command-line option.
|
new QAPI type for that, as shown below::
|
||||||
|
|
||||||
We want to return two pieces of information. The first one is the alarm clock's
|
|
||||||
name. The second one is when the next alarm will fire. The former information is
|
|
||||||
returned as a string, the latter is an integer in nanoseconds (which is not
|
|
||||||
very useful in practice, as the timer has probably already fired when the
|
|
||||||
information reaches the client).
|
|
||||||
|
|
||||||
The best way to return that data is to create a new QAPI type, as shown below::
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# @QemuAlarmClock
|
# @OptionRomInfo:
|
||||||
#
|
#
|
||||||
# QEMU alarm clock information.
|
# @filename: option ROM image file name
|
||||||
#
|
#
|
||||||
# @clock-name: The alarm clock method's name.
|
# @bootindex: option ROM's bootindex
|
||||||
#
|
#
|
||||||
# @next-deadline: The time (in nanoseconds) the next alarm will fire.
|
# Since: 9.0
|
||||||
#
|
|
||||||
# Since: 1.0
|
|
||||||
##
|
##
|
||||||
{ 'type': 'QemuAlarmClock',
|
{ 'struct': 'OptionRomInfo',
|
||||||
'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
|
'data': { 'filename': 'str', '*bootindex': 'int' } }
|
||||||
|
|
||||||
The "type" keyword defines a new QAPI type. Its "data" member contains the
|
The "struct" keyword defines a new QAPI type. Its "data" member
|
||||||
type's members. In this example our members are the "clock-name" and the
|
contains the type's members. In this example our members are
|
||||||
"next-deadline" one, which is optional.
|
"filename" and "bootindex". The latter is optional.
|
||||||
|
|
||||||
Now let's define the query-alarm-clock command::
|
Now let's define the query-option-roms command::
|
||||||
|
|
||||||
##
|
##
|
||||||
# @query-alarm-clock
|
# @query-option-roms:
|
||||||
#
|
#
|
||||||
# Return information about QEMU's alarm clock.
|
# Query information on ROMs loaded into the option ROM space.
|
||||||
#
|
#
|
||||||
# Returns a @QemuAlarmClock instance describing the alarm clock method
|
# Returns: OptionRomInfo
|
||||||
# being currently used by QEMU (this is usually set by the '-clock'
|
|
||||||
# command-line option).
|
|
||||||
#
|
#
|
||||||
# Since: 1.0
|
# Since: 9.0
|
||||||
##
|
##
|
||||||
{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
|
{ 'command': 'query-option-roms',
|
||||||
|
'returns': ['OptionRomInfo'] }
|
||||||
|
|
||||||
Notice the "returns" keyword. As its name suggests, it's used to define the
|
Notice the "returns" keyword. As its name suggests, it's used to define the
|
||||||
data returned by a command.
|
data returned by a command.
|
||||||
|
|
||||||
It's time to implement the qmp_query_alarm_clock() function, you can put it
|
Notice the syntax ['OptionRomInfo']". This should be read as "returns
|
||||||
in the qemu-timer.c file::
|
a list of OptionRomInfo".
|
||||||
|
|
||||||
QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
|
It's time to implement the qmp_query_option_roms() function. Add to
|
||||||
|
monitor/qmp-cmds.c::
|
||||||
|
|
||||||
|
OptionRomInfoList *qmp_query_option_roms(Error **errp)
|
||||||
{
|
{
|
||||||
QemuAlarmClock *clock;
|
OptionRomInfoList *info_list = NULL;
|
||||||
int64_t deadline;
|
OptionRomInfoList **tailp = &info_list;
|
||||||
|
OptionRomInfo *info;
|
||||||
|
|
||||||
clock = g_malloc0(sizeof(*clock));
|
for (int i = 0; i < nb_option_roms; i++) {
|
||||||
|
info = g_malloc0(sizeof(*info));
|
||||||
deadline = qemu_next_alarm_deadline();
|
info->filename = g_strdup(option_rom[i].name);
|
||||||
if (deadline > 0) {
|
info->has_bootindex = option_rom[i].bootindex >= 0;
|
||||||
clock->has_next_deadline = true;
|
if (info->has_bootindex) {
|
||||||
clock->next_deadline = deadline;
|
info->bootindex = option_rom[i].bootindex;
|
||||||
|
}
|
||||||
|
QAPI_LIST_APPEND(tailp, info);
|
||||||
}
|
}
|
||||||
clock->clock_name = g_strdup(alarm_timer->name);
|
|
||||||
|
|
||||||
return clock;
|
return info_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
There are a number of things to be noticed:
|
There are a number of things to be noticed:
|
||||||
|
|
||||||
1. The QemuAlarmClock type is automatically generated by the QAPI framework,
|
1. Type OptionRomInfo is automatically generated by the QAPI framework,
|
||||||
its members correspond to the type's specification in the schema file
|
its members correspond to the type's specification in the schema
|
||||||
2. As specified in the schema file, the function returns a QemuAlarmClock
|
file
|
||||||
instance and takes no arguments (besides the "errp" one, which is mandatory
|
2. Type OptionRomInfoList is also generated. It's a singly linked
|
||||||
for all QMP functions)
|
list.
|
||||||
3. The "clock" variable (which will point to our QAPI type instance) is
|
3. As specified in the schema file, the function returns a
|
||||||
allocated by the regular g_malloc0() function. Note that we chose to
|
OptionRomInfoList, and takes no arguments (besides the "errp" one,
|
||||||
initialize the memory to zero. This is recommended for all QAPI types, as
|
which is mandatory for all QMP functions)
|
||||||
it helps avoiding bad surprises (specially with booleans)
|
4. The returned object is dynamically allocated
|
||||||
4. Remember that "next_deadline" is optional? Non-pointer optional
|
5. All strings are dynamically allocated. This is so because QAPI also
|
||||||
members have a 'has_TYPE_NAME' member that should be properly set
|
generates a function to free its types and it cannot distinguish
|
||||||
|
between dynamically or statically allocated strings
|
||||||
|
6. Remember that "bootindex" is optional? As a non-pointer optional
|
||||||
|
member, it comes with a 'has_bootindex' member that needs to be set
|
||||||
by the implementation, as shown above
|
by the implementation, as shown above
|
||||||
5. Even static strings, such as "alarm_timer->name", should be dynamically
|
|
||||||
allocated by the implementation. This is so because the QAPI also generates
|
|
||||||
a function to free its types and it cannot distinguish between dynamically
|
|
||||||
or statically allocated strings
|
|
||||||
6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c
|
|
||||||
|
|
||||||
Time to test the new command. Build qemu, run it as described in the "Testing"
|
Time to test the new command. Build qemu, run it as described in the "Testing"
|
||||||
section and try this::
|
section and try this::
|
||||||
|
|
||||||
{ "execute": "query-alarm-clock" }
|
{ "execute": "query-option-rom" }
|
||||||
{
|
{
|
||||||
"return": {
|
"return": [
|
||||||
"next-deadline": 2368219,
|
{
|
||||||
"clock-name": "dynticks"
|
"filename": "kvmvapic.bin"
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
The HMP command
|
The HMP command
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Here's the HMP counterpart of the query-alarm-clock command::
|
Here's the HMP counterpart of the query-option-roms command::
|
||||||
|
|
||||||
void hmp_info_alarm_clock(Monitor *mon)
|
void hmp_info_option_roms(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
QemuAlarmClock *clock;
|
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
OptionRomInfoList *info_list, *tail;
|
||||||
|
OptionRomInfo *info;
|
||||||
|
|
||||||
clock = qmp_query_alarm_clock(&err);
|
info_list = qmp_query_option_roms(&err);
|
||||||
if (hmp_handle_error(mon, err)) {
|
if (hmp_handle_error(mon, err)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name);
|
for (tail = info_list; tail; tail = tail->next) {
|
||||||
if (clock->has_next_deadline) {
|
info = tail->value;
|
||||||
monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n",
|
monitor_printf(mon, "%s", info->filename);
|
||||||
clock->next_deadline);
|
if (info->has_bootindex) {
|
||||||
|
monitor_printf(mon, " %" PRId64, info->bootindex);
|
||||||
|
}
|
||||||
|
monitor_printf(mon, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
qapi_free_QemuAlarmClock(clock);
|
qapi_free_OptionRomInfoList(info_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
It's important to notice that hmp_info_alarm_clock() calls
|
It's important to notice that hmp_info_option_roms() calls
|
||||||
qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
|
qapi_free_OptionRomInfoList() to free the data returned by
|
||||||
For user defined types, the QAPI will generate a qapi_free_QAPI_TYPE_NAME()
|
qmp_query_option_roms(). For user defined types, QAPI will generate a
|
||||||
function and that's what you have to use to free the types you define and
|
qapi_free_QAPI_TYPE_NAME() function, and that's what you have to use to
|
||||||
qapi_free_QAPI_TYPE_NAMEList() for list types (explained in the next section).
|
free the types you define and qapi_free_QAPI_TYPE_NAMEList() for list
|
||||||
If the QMP call returns a string, then you should g_free() to free it.
|
types (explained in the next section). If the QMP function returns a
|
||||||
|
string, then you should g_free() to free it.
|
||||||
|
|
||||||
Also note that hmp_info_alarm_clock() performs error handling. That's not
|
Also note that hmp_info_option_roms() performs error handling. That's
|
||||||
strictly required if you're sure the QMP function doesn't return errors, but
|
not strictly required when you're sure the QMP function doesn't return
|
||||||
it's good practice to always check for errors.
|
errors; you could instead pass it &error_abort then.
|
||||||
|
|
||||||
Another important detail is that HMP's "info" commands don't go into the
|
Another important detail is that HMP's "info" commands go into
|
||||||
hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined
|
hmp-commands-info.hx, not hmp-commands.hx. The entry for the "info
|
||||||
in the monitor/misc.c file. The entry for the "info alarmclock" follows::
|
option-roms" follows::
|
||||||
|
|
||||||
{
|
{
|
||||||
.name = "alarmclock",
|
.name = "option-roms",
|
||||||
.args_type = "",
|
.args_type = "",
|
||||||
.params = "",
|
.params = "",
|
||||||
.help = "show information about the alarm clock",
|
.help = "show roms",
|
||||||
.cmd = hmp_info_alarm_clock,
|
.cmd = hmp_info_option_roms,
|
||||||
},
|
},
|
||||||
|
SRST
|
||||||
|
``info option-roms``
|
||||||
|
Show the option ROMs.
|
||||||
|
ERST
|
||||||
|
|
||||||
To test this, run qemu and type "info alarmclock" in the user monitor.
|
To test this, run qemu and type "info option-roms" in the user monitor.
|
||||||
|
|
||||||
|
|
||||||
Returning Lists
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
For this example, we're going to return all available methods for the timer
|
|
||||||
alarm, which is pretty much what the command-line option "-clock ?" does,
|
|
||||||
except that we're also going to inform which method is in use.
|
|
||||||
|
|
||||||
This first step is to define a new type::
|
|
||||||
|
|
||||||
##
|
|
||||||
# @TimerAlarmMethod
|
|
||||||
#
|
|
||||||
# Timer alarm method information.
|
|
||||||
#
|
|
||||||
# @method-name: The method's name.
|
|
||||||
#
|
|
||||||
# @current: true if this alarm method is currently in use, false otherwise
|
|
||||||
#
|
|
||||||
# Since: 1.0
|
|
||||||
##
|
|
||||||
{ 'type': 'TimerAlarmMethod',
|
|
||||||
'data': { 'method-name': 'str', 'current': 'bool' } }
|
|
||||||
|
|
||||||
The command will be called "query-alarm-methods", here is its schema
|
|
||||||
specification::
|
|
||||||
|
|
||||||
##
|
|
||||||
# @query-alarm-methods
|
|
||||||
#
|
|
||||||
# Returns information about available alarm methods.
|
|
||||||
#
|
|
||||||
# Returns: a list of @TimerAlarmMethod for each method
|
|
||||||
#
|
|
||||||
# Since: 1.0
|
|
||||||
##
|
|
||||||
{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
|
|
||||||
|
|
||||||
Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this
|
|
||||||
should be read as "returns a list of TimerAlarmMethod instances".
|
|
||||||
|
|
||||||
The C implementation follows::
|
|
||||||
|
|
||||||
TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
|
|
||||||
{
|
|
||||||
TimerAlarmMethodList *method_list = NULL;
|
|
||||||
const struct qemu_alarm_timer *p;
|
|
||||||
bool current = true;
|
|
||||||
|
|
||||||
for (p = alarm_timers; p->name; p++) {
|
|
||||||
TimerAlarmMethod *value = g_malloc0(*value);
|
|
||||||
value->method_name = g_strdup(p->name);
|
|
||||||
value->current = current;
|
|
||||||
QAPI_LIST_PREPEND(method_list, value);
|
|
||||||
current = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return method_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
The most important difference from the previous examples is the
|
|
||||||
TimerAlarmMethodList type, which is automatically generated by the QAPI from
|
|
||||||
the TimerAlarmMethod type.
|
|
||||||
|
|
||||||
Each list node is represented by a TimerAlarmMethodList instance. We have to
|
|
||||||
allocate it, and that's done inside the for loop: the "info" pointer points to
|
|
||||||
an allocated node. We also have to allocate the node's contents, which is
|
|
||||||
stored in its "value" member. In our example, the "value" member is a pointer
|
|
||||||
to an TimerAlarmMethod instance.
|
|
||||||
|
|
||||||
Notice that the "current" variable is used as "true" only in the first
|
|
||||||
iteration of the loop. That's because the alarm timer method in use is the
|
|
||||||
first element of the alarm_timers array. Also notice that QAPI lists are handled
|
|
||||||
by hand and we return the head of the list.
|
|
||||||
|
|
||||||
Now Build qemu, run it as explained in the "Testing" section and try our new
|
|
||||||
command::
|
|
||||||
|
|
||||||
{ "execute": "query-alarm-methods" }
|
|
||||||
{
|
|
||||||
"return": [
|
|
||||||
{
|
|
||||||
"current": false,
|
|
||||||
"method-name": "unix"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"current": true,
|
|
||||||
"method-name": "dynticks"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
The HMP counterpart is a bit more complex than previous examples because it
|
|
||||||
has to traverse the list, it's shown below for reference::
|
|
||||||
|
|
||||||
void hmp_info_alarm_methods(Monitor *mon)
|
|
||||||
{
|
|
||||||
TimerAlarmMethodList *method_list, *method;
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
method_list = qmp_query_alarm_methods(&err);
|
|
||||||
if (hmp_handle_error(mon, err)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (method = method_list; method; method = method->next) {
|
|
||||||
monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ',
|
|
||||||
method->value->method_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
qapi_free_TimerAlarmMethodList(method_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
Writing a debugging aid returning unstructured text
|
Writing a debugging aid returning unstructured text
|
||||||
---------------------------------------------------
|
---------------------------------------------------
|
||||||
|
|
||||||
As discussed in section `Modelling data in QAPI`_, it is required that
|
As discussed in section `Modelling data in QAPI`_, it is required that
|
||||||
commands expecting machine usage be using fine-grained QAPI data types.
|
commands expecting machine usage be using fine-grained QAPI data types.
|
||||||
The exception to this rule applies when the command is solely intended
|
The exception to this rule applies when the command is solely intended
|
||||||
as a debugging aid and allows for returning unstructured text. This is
|
as a debugging aid and allows for returning unstructured text, such as
|
||||||
commonly needed for query commands that report aspects of QEMU's
|
a query command that report aspects of QEMU's internal state that are
|
||||||
internal state that are useful to human operators.
|
useful only to human operators.
|
||||||
|
|
||||||
In this example we will consider a simplified variant of the HMP
|
In this example we will consider the existing QMP command
|
||||||
command ``info roms``. Following the earlier rules, this command will
|
``x-query-roms`` in qapi/machine.json. It has no parameters and
|
||||||
need to live under the ``x-`` name prefix, so its QMP implementation
|
returns a ``HumanReadableText``::
|
||||||
will be called ``x-query-roms``. It will have no parameters and will
|
|
||||||
return a single text string::
|
|
||||||
|
|
||||||
{ 'struct': 'HumanReadableText',
|
|
||||||
'data': { 'human-readable-text': 'str' } }
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# @x-query-roms:
|
||||||
|
#
|
||||||
|
# Query information on the registered ROMS
|
||||||
|
#
|
||||||
|
# Features:
|
||||||
|
#
|
||||||
|
# @unstable: This command is meant for debugging.
|
||||||
|
#
|
||||||
|
# Returns: registered ROMs
|
||||||
|
#
|
||||||
|
# Since: 6.2
|
||||||
|
##
|
||||||
{ 'command': 'x-query-roms',
|
{ 'command': 'x-query-roms',
|
||||||
'returns': 'HumanReadableText' }
|
'returns': 'HumanReadableText',
|
||||||
|
'features': [ 'unstable' ] }
|
||||||
|
|
||||||
The ``HumanReadableText`` struct is intended to be used for all
|
The ``HumanReadableText`` struct is defined in qapi/common.json as a
|
||||||
commands, under the ``x-`` name prefix that are returning unstructured
|
struct with a string member. It is intended to be used for all
|
||||||
text targeted at humans. It should never be used for commands outside
|
commands that are returning unstructured text targeted at
|
||||||
the ``x-`` name prefix, as those should be using structured QAPI types.
|
humans. These should all have feature 'unstable'. Note that the
|
||||||
|
feature's documentation states why the command is unstable. We
|
||||||
|
commonly use a ``x-`` command name prefix to make lack of stability
|
||||||
|
obvious to human users.
|
||||||
|
|
||||||
Implementing the QMP command
|
Implementing the QMP command
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The QMP implementation will typically involve creating a ``GString``
|
The QMP implementation will typically involve creating a ``GString``
|
||||||
object and printing formatted data into it::
|
object and printing formatted data into it, like this::
|
||||||
|
|
||||||
HumanReadableText *qmp_x_query_roms(Error **errp)
|
HumanReadableText *qmp_x_query_roms(Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -698,6 +595,9 @@ object and printing formatted data into it::
|
||||||
return human_readable_text_from_str(buf);
|
return human_readable_text_from_str(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
The actual implementation emits more information. You can find it in
|
||||||
|
hw/core/loader.c.
|
||||||
|
|
||||||
|
|
||||||
Implementing the HMP command
|
Implementing the HMP command
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -706,7 +606,7 @@ Now that the QMP command is in place, we can also make it available in
|
||||||
the human monitor (HMP) as shown in previous examples. The HMP
|
the human monitor (HMP) as shown in previous examples. The HMP
|
||||||
implementations will all look fairly similar, as all they need do is
|
implementations will all look fairly similar, as all they need do is
|
||||||
invoke the QMP command and then print the resulting text or error
|
invoke the QMP command and then print the resulting text or error
|
||||||
message. Here's the implementation of the "info roms" HMP command::
|
message. Here's an implementation of the "info roms" HMP command::
|
||||||
|
|
||||||
void hmp_info_roms(Monitor *mon, const QDict *qdict)
|
void hmp_info_roms(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
|
@ -746,3 +646,5 @@ field NULL::
|
||||||
.help = "show roms",
|
.help = "show roms",
|
||||||
.cmd_info_hrt = qmp_x_query_roms,
|
.cmd_info_hrt = qmp_x_query_roms,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
This is how the actual HMP command is done.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue