Patchwork Add 'query-events' command to QMP to query async events

login
register
mail settings
Submitter Daniel P. Berrange
Date May 16, 2012, 12:55 p.m.
Message ID <1337172904-20508-1-git-send-email-berrange@redhat.com>
Download mbox | patch
Permalink /patch/159622/
State New
Headers show

Comments

Daniel P. Berrange - May 16, 2012, 12:55 p.m.
From: "Daniel P. Berrange" <berrange@redhat.com>

Sometimes it is neccessary for an application to determine
whether a particular QMP event is available, so they can
decide whether to use compatibility code instead. This
introduces a new 'query-events' command to QMP todo just
that

 { "execute": "query-events" }
 {"return": [{"name": "WAKEUP"},
             {"name": "SUSPEND"},
             {"name": "DEVICE_TRAY_MOVED"},
             {"name": "BLOCK_JOB_CANCELLED"},
             {"name": "BLOCK_JOB_COMPLETED"},
             ...snip...
             {"name": "SHUTDOWN"}]}

* monitor.c: Split out MonitorEvent -> string conversion
  into monitor_protocol_event_name() API. Add impl of
  qmp_query_events monitor command handler
* qapi-schema.json, qmp-commands.hx: Define contract of
  query-events command

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 monitor.c        |   93 ++++++++++++++++++++++++++++++++++-------------------
 qapi-schema.json |   22 +++++++++++++
 qmp-commands.hx  |   37 +++++++++++++++++++++
 3 files changed, 119 insertions(+), 33 deletions(-)
Eric Blake - May 16, 2012, 4:04 p.m.
On 05/16/2012 06:55 AM, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange@redhat.com>
> 
> Sometimes it is neccessary for an application to determine
> whether a particular QMP event is available, so they can
> decide whether to use compatibility code instead. This
> introduces a new 'query-events' command to QMP todo just

s/todo/to do/

> that
> 
>  { "execute": "query-events" }
>  {"return": [{"name": "WAKEUP"},
>              {"name": "SUSPEND"},
>              {"name": "DEVICE_TRAY_MOVED"},
>              {"name": "BLOCK_JOB_CANCELLED"},
>              {"name": "BLOCK_JOB_COMPLETED"},
>              ...snip...
>              {"name": "SHUTDOWN"}]}
> 
> * monitor.c: Split out MonitorEvent -> string conversion
>   into monitor_protocol_event_name() API. Add impl of
>   qmp_query_events monitor command handler
> * qapi-schema.json, qmp-commands.hx: Define contract of
>   query-events command

Definitely useful for libvirt.


> +static const char *monitor_protocol_event_name(MonitorEvent event)
> +{
>      switch (event) {
>          case QEVENT_SHUTDOWN:
> -            event_name = "SHUTDOWN";
> +            return "SHUTDOWN";
>              break;

These 'break' statements are now unreachable; does this matter in qemu
coding style?


> +query-events
> +--------------
> +
> +List QMP available events.
> +
> +Each event is represented by a json-object, the returned value is a json-array
> +of all events.
> +
> +Each json-object contain:

s/contain/contains/
Anthony Liguori - May 16, 2012, 4:18 p.m.
On 05/16/2012 11:04 AM, Eric Blake wrote:
> On 05/16/2012 06:55 AM, Daniel P. Berrange wrote:
>> From: "Daniel P. Berrange"<berrange@redhat.com>
>>
>> Sometimes it is neccessary for an application to determine
>> whether a particular QMP event is available, so they can
>> decide whether to use compatibility code instead. This
>> introduces a new 'query-events' command to QMP todo just
>
> s/todo/to do/
>
>> that
>>
>>   { "execute": "query-events" }
>>   {"return": [{"name": "WAKEUP"},
>>               {"name": "SUSPEND"},
>>               {"name": "DEVICE_TRAY_MOVED"},
>>               {"name": "BLOCK_JOB_CANCELLED"},
>>               {"name": "BLOCK_JOB_COMPLETED"},
>>               ...snip...
>>               {"name": "SHUTDOWN"}]}
>>
>> * monitor.c: Split out MonitorEvent ->  string conversion
>>    into monitor_protocol_event_name() API. Add impl of
>>    qmp_query_events monitor command handler
>> * qapi-schema.json, qmp-commands.hx: Define contract of
>>    query-events command
>
> Definitely useful for libvirt.
>
>
>> +static const char *monitor_protocol_event_name(MonitorEvent event)
>> +{
>>       switch (event) {
>>           case QEVENT_SHUTDOWN:
>> -            event_name = "SHUTDOWN";
>> +            return "SHUTDOWN";
>>               break;
>
> These 'break' statements are now unreachable; does this matter in qemu
> coding style?

Seems like we should just take the opportunity to kill off the function entirely 
and replace it with a table:

static const char *monitor_event_names[] = {
  [QEVENT_SHUTDOWN] = "SHUTDOWN",
  ...
};

Regards,

Anthony Liguori
Daniel P. Berrange - May 16, 2012, 4:20 p.m.
On Wed, May 16, 2012 at 11:18:22AM -0500, Anthony Liguori wrote:
> On 05/16/2012 11:04 AM, Eric Blake wrote:
> >On 05/16/2012 06:55 AM, Daniel P. Berrange wrote:
> >>From: "Daniel P. Berrange"<berrange@redhat.com>
> >>
> >>Sometimes it is neccessary for an application to determine
> >>whether a particular QMP event is available, so they can
> >>decide whether to use compatibility code instead. This
> >>introduces a new 'query-events' command to QMP todo just
> >
> >s/todo/to do/
> >
> >>that
> >>
> >>  { "execute": "query-events" }
> >>  {"return": [{"name": "WAKEUP"},
> >>              {"name": "SUSPEND"},
> >>              {"name": "DEVICE_TRAY_MOVED"},
> >>              {"name": "BLOCK_JOB_CANCELLED"},
> >>              {"name": "BLOCK_JOB_COMPLETED"},
> >>              ...snip...
> >>              {"name": "SHUTDOWN"}]}
> >>
> >>* monitor.c: Split out MonitorEvent ->  string conversion
> >>   into monitor_protocol_event_name() API. Add impl of
> >>   qmp_query_events monitor command handler
> >>* qapi-schema.json, qmp-commands.hx: Define contract of
> >>   query-events command
> >
> >Definitely useful for libvirt.
> >
> >
> >>+static const char *monitor_protocol_event_name(MonitorEvent event)
> >>+{
> >>      switch (event) {
> >>          case QEVENT_SHUTDOWN:
> >>-            event_name = "SHUTDOWN";
> >>+            return "SHUTDOWN";
> >>              break;
> >
> >These 'break' statements are now unreachable; does this matter in qemu
> >coding style?
> 
> Seems like we should just take the opportunity to kill off the
> function entirely and replace it with a table:
> 
> static const char *monitor_event_names[] = {
>  [QEVENT_SHUTDOWN] = "SHUTDOWN",
>  ...
> };

That sounds good to me, I'll update the patch accordingly.

Regards,
Daniel
Luiz Capitulino - May 16, 2012, 4:45 p.m.
On Wed, 16 May 2012 11:18:22 -0500
Anthony Liguori <anthony@codemonkey.ws> wrote:

> On 05/16/2012 11:04 AM, Eric Blake wrote:
> > On 05/16/2012 06:55 AM, Daniel P. Berrange wrote:
> >> From: "Daniel P. Berrange"<berrange@redhat.com>
> >>
> >> Sometimes it is neccessary for an application to determine
> >> whether a particular QMP event is available, so they can
> >> decide whether to use compatibility code instead. This
> >> introduces a new 'query-events' command to QMP todo just
> >
> > s/todo/to do/
> >
> >> that
> >>
> >>   { "execute": "query-events" }
> >>   {"return": [{"name": "WAKEUP"},
> >>               {"name": "SUSPEND"},
> >>               {"name": "DEVICE_TRAY_MOVED"},
> >>               {"name": "BLOCK_JOB_CANCELLED"},
> >>               {"name": "BLOCK_JOB_COMPLETED"},
> >>               ...snip...
> >>               {"name": "SHUTDOWN"}]}
> >>
> >> * monitor.c: Split out MonitorEvent ->  string conversion
> >>    into monitor_protocol_event_name() API. Add impl of
> >>    qmp_query_events monitor command handler
> >> * qapi-schema.json, qmp-commands.hx: Define contract of
> >>    query-events command
> >
> > Definitely useful for libvirt.
> >
> >
> >> +static const char *monitor_protocol_event_name(MonitorEvent event)
> >> +{
> >>       switch (event) {
> >>           case QEVENT_SHUTDOWN:
> >> -            event_name = "SHUTDOWN";
> >> +            return "SHUTDOWN";
> >>               break;
> >
> > These 'break' statements are now unreachable; does this matter in qemu
> > coding style?
> 
> Seems like we should just take the opportunity to kill off the function entirely 
> and replace it with a table:
> 
> static const char *monitor_event_names[] = {
>   [QEVENT_SHUTDOWN] = "SHUTDOWN",
>   ...
> };

Yes, that's really better.

Btw, the ideal way of having this would be to add the event type to the
qapi and then add schema introspection.

As I'm not sure I can guarantee that for 1.2, I'm ok with this command.

Anthony, I'm assuming you're ok too.

Patch

diff --git a/monitor.c b/monitor.c
index ef59cd9..73ecf21 100644
--- a/monitor.c
+++ b/monitor.c
@@ -422,84 +422,93 @@  static void timestamp_put(QDict *qdict)
     qdict_put_obj(qdict, "timestamp", obj);
 }
 
-/**
- * monitor_protocol_event(): Generate a Monitor event
- *
- * Event-specific data can be emitted through the (optional) 'data' parameter.
- */
-void monitor_protocol_event(MonitorEvent event, QObject *data)
-{
-    QDict *qmp;
-    const char *event_name;
-    Monitor *mon;
-
-    assert(event < QEVENT_MAX);
 
+static const char *monitor_protocol_event_name(MonitorEvent event)
+{
     switch (event) {
         case QEVENT_SHUTDOWN:
-            event_name = "SHUTDOWN";
+            return "SHUTDOWN";
             break;
         case QEVENT_RESET:
-            event_name = "RESET";
+            return "RESET";
             break;
         case QEVENT_POWERDOWN:
-            event_name = "POWERDOWN";
+            return "POWERDOWN";
             break;
         case QEVENT_STOP:
-            event_name = "STOP";
+            return "STOP";
             break;
         case QEVENT_RESUME:
-            event_name = "RESUME";
+            return "RESUME";
             break;
         case QEVENT_VNC_CONNECTED:
-            event_name = "VNC_CONNECTED";
+            return "VNC_CONNECTED";
             break;
         case QEVENT_VNC_INITIALIZED:
-            event_name = "VNC_INITIALIZED";
+            return "VNC_INITIALIZED";
             break;
         case QEVENT_VNC_DISCONNECTED:
-            event_name = "VNC_DISCONNECTED";
+            return "VNC_DISCONNECTED";
             break;
         case QEVENT_BLOCK_IO_ERROR:
-            event_name = "BLOCK_IO_ERROR";
+            return "BLOCK_IO_ERROR";
             break;
         case QEVENT_RTC_CHANGE:
-            event_name = "RTC_CHANGE";
+            return "RTC_CHANGE";
             break;
         case QEVENT_WATCHDOG:
-            event_name = "WATCHDOG";
+            return "WATCHDOG";
             break;
         case QEVENT_SPICE_CONNECTED:
-            event_name = "SPICE_CONNECTED";
+            return "SPICE_CONNECTED";
             break;
         case QEVENT_SPICE_INITIALIZED:
-            event_name = "SPICE_INITIALIZED";
+            return "SPICE_INITIALIZED";
             break;
         case QEVENT_SPICE_DISCONNECTED:
-            event_name = "SPICE_DISCONNECTED";
+            return "SPICE_DISCONNECTED";
             break;
         case QEVENT_BLOCK_JOB_COMPLETED:
-            event_name = "BLOCK_JOB_COMPLETED";
+            return "BLOCK_JOB_COMPLETED";
             break;
         case QEVENT_BLOCK_JOB_CANCELLED:
-            event_name = "BLOCK_JOB_CANCELLED";
+            return "BLOCK_JOB_CANCELLED";
             break;
         case QEVENT_DEVICE_TRAY_MOVED:
-             event_name = "DEVICE_TRAY_MOVED";
+             return "DEVICE_TRAY_MOVED";
             break;
         case QEVENT_SUSPEND:
-            event_name = "SUSPEND";
+            return "SUSPEND";
             break;
         case QEVENT_WAKEUP:
-            event_name = "WAKEUP";
+            return "WAKEUP";
             break;
         case QEVENT_BALLOON_CHANGE:
-            event_name = "BALLOON_CHANGE";
+            return "BALLOON_CHANGE";
             break;
         default:
-            abort();
+            return NULL;
             break;
     }
+}
+
+/**
+ * monitor_protocol_event(): Generate a Monitor event
+ *
+ * Event-specific data can be emitted through the (optional) 'data' parameter.
+ */
+void monitor_protocol_event(MonitorEvent event, QObject *data)
+{
+    QDict *qmp;
+    const char *event_name;
+    Monitor *mon;
+
+    assert(event < QEVENT_MAX);
+
+    event_name = monitor_protocol_event_name(event);
+    if (event_name == NULL) {
+        abort();
+    }
 
     qmp = qdict_new();
     timestamp_put(qmp);
@@ -741,6 +750,24 @@  CommandInfoList *qmp_query_commands(Error **errp)
     return cmd_list;
 }
 
+EventInfoList *qmp_query_events(Error **errp)
+{
+    EventInfoList *info, *ev_list = NULL;
+    MonitorEvent e;
+
+    for (e = 0 ; e < QEVENT_MAX ; e++) {
+        const char *evname = monitor_protocol_event_name(e);
+        info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->name = g_strdup(evname);
+
+        info->next = ev_list;
+        ev_list = info;
+    }
+
+    return ev_list;
+}
+
 /* set the current CPU defined by the user */
 int monitor_set_cpu(int cpu_index)
 {
diff --git a/qapi-schema.json b/qapi-schema.json
index 2ca7195..94aa0ae 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -228,6 +228,28 @@ 
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
 ##
+# @EventInfo:
+#
+# Information about a QMP event
+#
+# @name: The event name
+#
+# Since: 1.2.0
+##
+{ 'type': 'EventInfo', 'data': {'name': 'str'} }
+
+##
+# @query-events:
+#
+# Return a list of supported QMP events by this server
+#
+# Returns: A list of @EventInfo for all supported events
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-events', 'returns': ['EventInfo'] }
+
+##
 # @MigrationStats
 #
 # Detailed migration status.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index db980fa..604ebfa 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1179,6 +1179,43 @@  EQMP
     },
 
 SQMP
+query-events
+--------------
+
+List QMP available events.
+
+Each event is represented by a json-object, the returned value is a json-array
+of all events.
+
+Each json-object contain:
+
+- "name": event's name (json-string)
+
+Example:
+
+-> { "execute": "query-events" }
+<- {
+      "return":[
+         {
+            "name":"SHUTDOWN"
+         },
+         {
+            "name":"RESET"
+         }
+      ]
+   }
+
+Note: This example has been shortened as the real response is too long.
+
+EQMP
+
+    {
+        .name       = "query-events",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_events,
+    },
+
+SQMP
 query-chardev
 -------------