From nobody Sat May 18 19:47:57 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1626886280912500.3140915769774; Wed, 21 Jul 2021 09:51:20 -0700 (PDT) Received: from localhost ([::1]:43290 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1m6FRH-0001mc-Oo for importer@patchew.org; Wed, 21 Jul 2021 12:51:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:53832) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1m6FQP-00013H-Rw for qemu-devel@nongnu.org; Wed, 21 Jul 2021 12:50:25 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:53502) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1m6FQM-0002gl-IM for qemu-devel@nongnu.org; Wed, 21 Jul 2021 12:50:25 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-437-RRE_AqxzOQ6J_PczFCP84Q-1; Wed, 21 Jul 2021 12:50:17 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id DEC1C804312 for ; Wed, 21 Jul 2021 16:50:16 +0000 (UTC) Received: from scv.redhat.com (ovpn-119-193.rdu2.redhat.com [10.10.119.193]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3EB7C7EE25; Wed, 21 Jul 2021 16:50:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1626886219; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=ZyZGx1Rq9MXTELOD19yEmrDzRgjrj3ZHOIiXP6vLYMo=; b=Y4JCWaa98AMl3DQrjx220G9Qz+RoQ957WF2s7lBNQT5NIKtKCtFNiGHYhPwk6n+XLGlYJT 5BeAKMTELaaDGw9+SXNJYiljCpnpyFD9RivHooJhkCqyGu7wEryVG2QKFrz42fdje/DUvM ZMp1zBFh+HF3YQ9KPs4ZSDatBNq0eBI= X-MC-Unique: RRE_AqxzOQ6J_PczFCP84Q-1 From: John Snow To: qemu-devel@nongnu.org Subject: [PATCH] docs: convert writing-qmp-commands.txt to writing-qmp-commands.rst Date: Wed, 21 Jul 2021 12:50:15 -0400 Message-Id: <20210721165015.2180311-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=216.205.24.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.459, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Snow , Markus Armbruster Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1626886282202100001 Content-Type: text/plain; charset="utf-8" This does about the bare minimum, converting section headers to ReST ones and adding an indent for code blocks. Signed-off-by: John Snow Reviewed-by: Connor Kuehl --- docs/devel/index.rst | 1 + ...-commands.txt =3D> writing-qmp-commands.rst} | 581 +++++++++--------- 2 files changed, 304 insertions(+), 278 deletions(-) rename docs/devel/{writing-qmp-commands.txt =3D> writing-qmp-commands.rst}= (61%) diff --git a/docs/devel/index.rst b/docs/devel/index.rst index 153979caf4b..331004ad072 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -42,3 +42,4 @@ modifying QEMU's source code. multi-process ebpf_rss vfio-migration + writing-qmp-commands diff --git a/docs/devel/writing-qmp-commands.txt b/docs/devel/writing-qmp-c= ommands.rst similarity index 61% rename from docs/devel/writing-qmp-commands.txt rename to docs/devel/writing-qmp-commands.rst index b1e31d56c0f..6a10a06c483 100644 --- a/docs/devel/writing-qmp-commands.txt +++ b/docs/devel/writing-qmp-commands.rst @@ -1,4 +1,5 @@ -=3D How to write QMP commands using the QAPI framework =3D +How to write QMP commands using the QAPI framework +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D =20 This document is a step-by-step guide on how to write new QMP commands usi= ng the QAPI framework. It also shows how to implement new style HMP commands. @@ -10,7 +11,9 @@ For an in-depth introduction to the QAPI framework, pleas= e refer to docs/devel/qapi-code-gen.txt. For documentation about the QMP protocol, start with docs/interop/qmp-intro.txt. =20 -=3D=3D Overview =3D=3D + +Overview +-------- =20 Generally speaking, the following steps should be taken in order to write a new QMP command. @@ -31,55 +34,59 @@ new QMP command. The following sections will demonstrate each of the steps above. We will s= tart very simple and get more complex as we progress. =20 -=3D=3D=3D Testing =3D=3D=3D + +Testing +------- =20 For all the examples in the next sections, the test setup is the same and = is shown here. =20 -First, QEMU should be started like this: +First, QEMU should be started like this:: =20 -# qemu-system-TARGET [...] \ - -chardev socket,id=3Dqmp,port=3D4444,host=3Dlocalhost,server=3Don \ - -mon chardev=3Dqmp,mode=3Dcontrol,pretty=3Don + # qemu-system-TARGET [...] \ + -chardev socket,id=3Dqmp,port=3D4444,host=3Dlocalhost,server=3Don \ + -mon chardev=3Dqmp,mode=3Dcontrol,pretty=3Don =20 -Then, in a different terminal: +Then, in a different terminal:: =20 -$ telnet localhost 4444 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. -{ - "QMP": { - "version": { - "qemu": { - "micro": 50,=20 - "minor": 15,=20 - "major": 0 - },=20 - "package": "" - },=20 - "capabilities": [ - ] - } -} + $ telnet localhost 4444 + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + { + "QMP": { + "version": { + "qemu": { + "micro": 50, + "minor": 15, + "major": 0 + }, + "package": "" + }, + "capabilities": [ + ] + } + } =20 The above output is the QMP server saying you're connected. The server is -actually in capabilities negotiation mode. To enter in command mode type: +actually in capabilities negotiation mode. To enter in command mode type:: =20 -{ "execute": "qmp_capabilities" } + { "execute": "qmp_capabilities" } =20 -Then the server should respond: +Then the server should respond:: =20 -{ - "return": { - } -} + { + "return": { + } + } =20 Which is QMP's way of saying "the latest command executed OK and didn't re= turn any data". Now you're ready to enter the QMP example commands as explained= in the following sections. =20 -=3D=3D Writing a command that doesn't return data =3D=3D + +Writing a command that doesn't return data +------------------------------------------ =20 That's the most simple QMP command that can be written. Usually, this kind= of command carries some meaningful action in QEMU but here it will just print @@ -90,9 +97,9 @@ return any data. =20 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 -the bottom: +the bottom:: =20 -{ 'command': 'hello-world' } + { 'command': 'hello-world' } =20 The "command" keyword defines a new QMP command. It's an JSON object. All schema entries are JSON objects. The line above will instruct the QAPI to @@ -102,19 +109,19 @@ protocol data. The next step is to write the "hello-world" implementation. As explained earlier, it's preferable for commands to live in QEMU subsystems. But "hello-world" doesn't pertain to any, so we put its implementation in -monitor/qmp-cmds.c: +monitor/qmp-cmds.c:: =20 -void qmp_hello_world(Error **errp) -{ - printf("Hello, world!\n"); -} + void qmp_hello_world(Error **errp) + { + printf("Hello, world!\n"); + } =20 There are a few things to be noticed: =20 -1. QMP command implementation functions must be prefixed with "qmp_" +1. QMP command implementation functions must be prefixed with "qmp\_" 2. qmp_hello_world() returns void, this is in accordance with the fact tha= t the command doesn't return any data -3. It takes an "Error **" argument. This is required. Later we will see ho= w to +3. It takes an "Error \*\*" argument. This is required. Later we will see = how to return errors and take additional arguments. The Error argument should = not be touched if the command doesn't return errors 4. We won't add the function's prototype. That's automatically done by the= QAPI @@ -122,23 +129,25 @@ There are a few things to be noticed: because it's the easiest way to demonstrate a QMP command =20 You're done. Now build qemu, run it as suggested in the "Testing" section, -and then type the following QMP command: +and then type the following QMP command:: =20 -{ "execute": "hello-world" } + { "execute": "hello-world" } =20 Then check the terminal running qemu and look for the "Hello, world" strin= g. If you don't see it then something went wrong. =20 -=3D=3D=3D Arguments =3D=3D=3D + +Arguments +~~~~~~~~~ =20 Let's add an argument called "message" to our "hello-world" command. The n= ew 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. =20 The first change we have to do is to modify the command specification in t= he -schema file to the following: +schema file to the following:: =20 -{ 'command': 'hello-world', 'data': { '*message': 'str' } } + { 'command': 'hello-world', 'data': { '*message': 'str' } } =20 Notice the new 'data' member in the schema. It's an JSON object whose each element is an argument to the command in question. Also notice the asteris= k, @@ -147,80 +156,82 @@ for mandatory arguments). Finally, 'str' is the argum= ent's type, which stands for "string". The QAPI also supports integers, booleans, enumeratio= ns and user defined types. =20 -Now, let's update our C implementation in monitor/qmp-cmds.c: +Now, let's update our C implementation in monitor/qmp-cmds.c:: =20 -void qmp_hello_world(bool has_message, const char *message, Error **errp) -{ - if (has_message) { - printf("%s\n", message); - } else { - printf("Hello, world\n"); - } -} + void qmp_hello_world(bool has_message, const char *message, Error **errp) + { + if (has_message) { + printf("%s\n", message); + } else { + printf("Hello, world\n"); + } + } =20 There are two important details to be noticed: =20 -1. All optional arguments are accompanied by a 'has_' boolean, which is set +1. All optional arguments are accompanied by a 'has\_' boolean, which is s= et if the optional argument is present or false otherwise 2. The C implementation signature must follow the schema's argument orderi= ng, which is defined by the "data" member =20 Time to test our new version of the "hello-world" command. Build qemu, run= it as -described in the "Testing" section and then send two commands: +described in the "Testing" section and then send two commands:: =20 -{ "execute": "hello-world" } -{ - "return": { - } -} + { "execute": "hello-world" } + { + "return": { + } + } =20 -{ "execute": "hello-world", "arguments": { "message": "We love qemu" } } -{ - "return": { - } -} + { "execute": "hello-world", "arguments": { "message": "We love qemu" } } + { + "return": { + } + } =20 You should see "Hello, world" and "We love qemu" in the terminal running q= emu, if you don't see these strings, then something went wrong. =20 -=3D=3D=3D Errors =3D=3D=3D + +Errors +~~~~~~ =20 QMP commands should use the error interface exported by the error.h header file. Basically, most errors are set by calling the error_setg() function. =20 Let's say we don't accept the string "message" to contain the word "love".= If -it does contain it, we want the "hello-world" command to return an error: +it does contain it, we want the "hello-world" command to return an error:: =20 -void qmp_hello_world(bool has_message, const char *message, Error **errp) -{ - if (has_message) { - if (strstr(message, "love")) { - error_setg(errp, "the word 'love' is not allowed"); - return; - } - printf("%s\n", message); - } else { - printf("Hello, world\n"); - } -} + void qmp_hello_world(bool has_message, const char *message, Error **errp) + { + if (has_message) { + if (strstr(message, "love")) { + error_setg(errp, "the word 'love' is not allowed"); + return; + } + printf("%s\n", message); + } else { + printf("Hello, world\n"); + } + } =20 The first argument to the error_setg() function is the Error pointer to pointer, which is passed to all QMP functions. The next argument is a h= uman description of the error, this is a free-form printf-like string. =20 Let's test the example above. Build qemu, run it as defined in the "Testin= g" -section, and then issue the following command: +section, and then issue the following command:: =20 -{ "execute": "hello-world", "arguments": { "message": "all you need is lov= e" } } + { "execute": "hello-world", "arguments": { "message": "all you need is lo= ve" } } =20 -The QMP server's response should be: +The QMP server's response should be:: =20 -{ - "error": { - "class": "GenericError", - "desc": "the word 'love' is not allowed" - } -} + { + "error": { + "class": "GenericError", + "desc": "the word 'love' is not allowed" + } + } =20 Note that error_setg() produces a "GenericError" class. In general, all QMP errors should have that error class. There are two exceptions @@ -234,34 +245,38 @@ to this rule: 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. =20 -=3D=3D=3D Command Documentation =3D=3D=3D + +Command Documentation +~~~~~~~~~~~~~~~~~~~~~ =20 There's only one step missing to make "hello-world"'s implementation compl= ete, and that's its documentation in the schema file. =20 There are many examples of such documentation in the schema file already, = but -here goes "hello-world"'s new entry for qapi/misc.json: +here goes "hello-world"'s new entry for qapi/misc.json:: =20 -## -# @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: -## -{ 'command': 'hello-world', 'data': { '*message': 'str' } } + ## + # @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: + ## + { 'command': 'hello-world', 'data': { '*message': 'str' } } =20 Please, note that the "Returns" clause is optional if a command doesn't re= turn any data nor any errors. =20 -=3D=3D=3D Implementing the HMP command =3D=3D=3D + +Implementing the HMP command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =20 Now that the QMP command is in place, we can also make it available in the= human monitor (HMP). @@ -270,20 +285,20 @@ With the introduction of the QAPI, HMP commands make = QMP calls. Most of the time HMP commands are simple wrappers. All HMP commands implementation exi= st in the monitor/hmp-cmds.c file. =20 -Here's the implementation of the "hello-world" HMP command: +Here's the implementation of the "hello-world" HMP command:: =20 -void hmp_hello_world(Monitor *mon, const QDict *qdict) -{ - const char *message =3D qdict_get_try_str(qdict, "message"); - Error *err =3D NULL; + void hmp_hello_world(Monitor *mon, const QDict *qdict) + { + const char *message =3D qdict_get_try_str(qdict, "message"); + Error *err =3D NULL; =20 - qmp_hello_world(!!message, message, &err); - if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - error_free(err); - return; - } -} + qmp_hello_world(!!message, message, &err); + if (err) { + monitor_printf(mon, "%s\n", error_get_pretty(err)); + error_free(err); + return; + } + } =20 Also, you have to add the function's prototype to the hmp.h file. =20 @@ -299,7 +314,7 @@ There are three important points to be noticed: QMP call =20 There's one last step to actually make the command available to monitor us= ers, -we should add it to the hmp-commands.hx file: +we should add it to the hmp-commands.hx file:: =20 { .name =3D "hello-world", @@ -309,11 +324,13 @@ we should add it to the hmp-commands.hx file: .cmd =3D hmp_hello_world, }, =20 -STEXI -@item hello_world @var{message} -@findex hello_world -Print message to the standard output -ETEXI +:: + + STEXI + @item hello_world @var{message} + @findex hello_world + Print message to the standard output + ETEXI =20 To test this you have to open a user monitor and issue the "hello-world" command. It might be instructive to check the command's documentation with @@ -322,7 +339,9 @@ HMP's "help" command. Please, check the "-monitor" command-line option to know how to open a user monitor. =20 -=3D=3D Writing a command that returns data =3D=3D + +Writing a command that returns data +----------------------------------- =20 A QMP command is capable of returning any data the QAPI supports like inte= gers, strings, booleans, enumerations and user defined types. @@ -330,7 +349,9 @@ strings, booleans, enumerations and user defined types. In this section we will focus on user defined types. Please, check the QAPI documentation for information about the other types. =20 -=3D=3D=3D User Defined Types =3D=3D=3D + +User Defined Types +~~~~~~~~~~~~~~~~~~ =20 FIXME This example needs to be redone after commit 6d32717 =20 @@ -344,63 +365,63 @@ returned as a string, the latter is an integer in nan= oseconds (which is not very useful in practice, as the timer has probably already fired when the information reaches the client). =20 -The best way to return that data is to create a new QAPI type, as shown be= low: +The best way to return that data is to create a new QAPI type, as shown be= low:: =20 -## -# @QemuAlarmClock -# -# QEMU alarm clock information. -# -# @clock-name: The alarm clock method's name. -# -# @next-deadline: The time (in nanoseconds) the next alarm will fire. -# -# Since: 1.0 -## -{ 'type': 'QemuAlarmClock', - 'data': { 'clock-name': 'str', '*next-deadline': 'int' } } + ## + # @QemuAlarmClock + # + # QEMU alarm clock information. + # + # @clock-name: The alarm clock method's name. + # + # @next-deadline: The time (in nanoseconds) the next alarm will fire. + # + # Since: 1.0 + ## + { 'type': 'QemuAlarmClock', + 'data': { 'clock-name': 'str', '*next-deadline': 'int' } } =20 The "type" keyword defines a new QAPI type. Its "data" member contains the type's members. In this example our members are the "clock-name" and the "next-deadline" one, which is optional. =20 -Now let's define the query-alarm-clock command: +Now let's define the query-alarm-clock command:: =20 -## -# @query-alarm-clock -# -# Return information about QEMU's alarm clock. -# -# Returns a @QemuAlarmClock instance describing the alarm clock method -# being currently used by QEMU (this is usually set by the '-clock' -# command-line option). -# -# Since: 1.0 -## -{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' } + ## + # @query-alarm-clock + # + # Return information about QEMU's alarm clock. + # + # Returns a @QemuAlarmClock instance describing the alarm clock method + # being currently used by QEMU (this is usually set by the '-clock' + # command-line option). + # + # Since: 1.0 + ## + { 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' } =20 Notice the "returns" keyword. As its name suggests, it's used to define the data returned by a command. =20 It's time to implement the qmp_query_alarm_clock() function, you can put it -in the qemu-timer.c file: +in the qemu-timer.c file:: =20 -QemuAlarmClock *qmp_query_alarm_clock(Error **errp) -{ - QemuAlarmClock *clock; - int64_t deadline; + QemuAlarmClock *qmp_query_alarm_clock(Error **errp) + { + QemuAlarmClock *clock; + int64_t deadline; =20 - clock =3D g_malloc0(sizeof(*clock)); + clock =3D g_malloc0(sizeof(*clock)); =20 - deadline =3D qemu_next_alarm_deadline(); - if (deadline > 0) { - clock->has_next_deadline =3D true; - clock->next_deadline =3D deadline; - } - clock->clock_name =3D g_strdup(alarm_timer->name); + deadline =3D qemu_next_alarm_deadline(); + if (deadline > 0) { + clock->has_next_deadline =3D true; + clock->next_deadline =3D deadline; + } + clock->clock_name =3D g_strdup(alarm_timer->name); =20 - return clock; -} + return clock; + } =20 There are a number of things to be noticed: =20 @@ -423,40 +444,42 @@ There are a number of things to be noticed: 6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c =20 Time to test the new command. Build qemu, run it as described in the "Test= ing" -section and try this: - -{ "execute": "query-alarm-clock" } -{ - "return": { - "next-deadline": 2368219, - "clock-name": "dynticks" - } -} - -=3D=3D=3D=3D The HMP command =3D=3D=3D=3D - -Here's the HMP counterpart of the query-alarm-clock command: - -void hmp_info_alarm_clock(Monitor *mon) -{ - QemuAlarmClock *clock; - Error *err =3D NULL; - - clock =3D qmp_query_alarm_clock(&err); - if (err) { - monitor_printf(mon, "Could not query alarm clock information\n"); - error_free(err); - return; - } - - monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_= name); - if (clock->has_next_deadline) { - monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanosecon= ds\n", - clock->next_deadline); - } - - qapi_free_QemuAlarmClock(clock);=20 -} +section and try this:: + + { "execute": "query-alarm-clock" } + { + "return": { + "next-deadline": 2368219, + "clock-name": "dynticks" + } + } + + +The HMP command +~~~~~~~~~~~~~~~ + +Here's the HMP counterpart of the query-alarm-clock command:: + + void hmp_info_alarm_clock(Monitor *mon) + { + QemuAlarmClock *clock; + Error *err =3D NULL; + + clock =3D qmp_query_alarm_clock(&err); + if (err) { + monitor_printf(mon, "Could not query alarm clock information\n"); + error_free(err); + return; + } + + monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock= _name); + if (clock->has_next_deadline) { + monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseco= nds\n", + clock->next_deadline); + } + + qapi_free_QemuAlarmClock(clock); + } =20 It's important to notice that hmp_info_alarm_clock() calls qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_cl= ock(). @@ -471,7 +494,7 @@ it's good practice to always check for errors. =20 Another important detail is that HMP's "info" commands don't go into the hmp-commands.hx. Instead, they go into the info_cmds[] table, which is def= ined -in the monitor/misc.c file. The entry for the "info alarmclock" follows: +in the monitor/misc.c file. The entry for the "info alarmclock" follows:: =20 { .name =3D "alarmclock", @@ -483,63 +506,65 @@ in the monitor/misc.c file. The entry for the "info a= larmclock" follows: =20 To test this, run qemu and type "info alarmclock" in the user monitor. =20 -=3D=3D=3D Returning Lists =3D=3D=3D + +Returning Lists +~~~~~~~~~~~~~~~ =20 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. =20 -This first step is to define a new type: +This first step is to define a new type:: =20 -## -# @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' } } + ## + # @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' } } =20 The command will be called "query-alarm-methods", here is its schema -specification: +specification:: =20 -## -# @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'] } + ## + # @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'] } =20 Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", t= his should be read as "returns a list of TimerAlarmMethod instances". =20 -The C implementation follows: +The C implementation follows:: =20 -TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp) -{ - TimerAlarmMethodList *method_list =3D NULL; - const struct qemu_alarm_timer *p; - bool current =3D true; + TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp) + { + TimerAlarmMethodList *method_list =3D NULL; + const struct qemu_alarm_timer *p; + bool current =3D true; =20 - for (p =3D alarm_timers; p->name; p++) { - TimerAlarmMethod *value =3D g_malloc0(*value); - value->method_name =3D g_strdup(p->name); - value->current =3D current; - QAPI_LIST_PREPEND(method_list, value); - current =3D false; - } + for (p =3D alarm_timers; p->name; p++) { + TimerAlarmMethod *value =3D g_malloc0(*value); + value->method_name =3D g_strdup(p->name); + value->current =3D current; + QAPI_LIST_PREPEND(method_list, value); + current =3D false; + } =20 - return method_list; -} + return method_list; + } =20 The most important difference from the previous examples is the TimerAlarmMethodList type, which is automatically generated by the QAPI fr= om @@ -557,41 +582,41 @@ first element of the alarm_timers array. Also notice = that QAPI lists are handled by hand and we return the head of the list. =20 Now Build qemu, run it as explained in the "Testing" section and try our n= ew -command: +command:: =20 -{ "execute": "query-alarm-methods" } -{ - "return": [ - { - "current": false,=20 - "method-name": "unix" - },=20 - { - "current": true,=20 - "method-name": "dynticks" - } - ] -} + { "execute": "query-alarm-methods" } + { + "return": [ + { + "current": false, + "method-name": "unix" + }, + { + "current": true, + "method-name": "dynticks" + } + ] + } =20 The HMP counterpart is a bit more complex than previous examples because it -has to traverse the list, it's shown below for reference: +has to traverse the list, it's shown below for reference:: =20 -void hmp_info_alarm_methods(Monitor *mon) -{ - TimerAlarmMethodList *method_list, *method; - Error *err =3D NULL; + void hmp_info_alarm_methods(Monitor *mon) + { + TimerAlarmMethodList *method_list, *method; + Error *err =3D NULL; =20 - method_list =3D qmp_query_alarm_methods(&err); - if (err) { - monitor_printf(mon, "Could not query alarm methods\n"); - error_free(err); - return; - } + method_list =3D qmp_query_alarm_methods(&err); + if (err) { + monitor_printf(mon, "Could not query alarm methods\n"); + error_free(err); + return; + } =20 - for (method =3D method_list; method; method =3D method->next) { - monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ', - method->value->method_name); - } + for (method =3D method_list; method; method =3D method->next) { + monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ', + method->value->method_name); + } =20 - qapi_free_TimerAlarmMethodList(method_list); -} + qapi_free_TimerAlarmMethodList(method_list); + } --=20 2.31.1