Patchwork [v2,1/3] Add 'query-events' command to QMP to query async events

login
register
mail settings
Submitter Daniel P. Berrange
Date May 21, 2012, 4:59 p.m.
Message ID <1337619593-25823-2-git-send-email-berrange@redhat.com>
Download mbox | patch
Permalink /patch/160463/
State New
Headers show

Comments

Daniel P. Berrange - May 21, 2012, 4:59 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 to do 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: Turn MonitorEvent -> string conversion
  into a lookup from a static table of constant strings.
  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        |  107 +++++++++++++++++++++++-------------------------------
 monitor.h        |    4 ++
 qapi-schema.json |   22 +++++++++++
 qmp-commands.hx  |   37 +++++++++++++++++++
 4 files changed, 108 insertions(+), 62 deletions(-)
Luiz Capitulino - May 22, 2012, 8:47 p.m.
On Mon, 21 May 2012 17:59:51 +0100
"Daniel P. Berrange" <berrange@redhat.com> 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 to do 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: Turn MonitorEvent -> string conversion
>   into a lookup from a static table of constant strings.
>   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>

Looks good to me. As this independent of the other patches I've applied it
to the qmp-next branch, so you don't need to include this if you respin.

> ---
>  monitor.c        |  107 +++++++++++++++++++++++-------------------------------
>  monitor.h        |    4 ++
>  qapi-schema.json |   22 +++++++++++
>  qmp-commands.hx  |   37 +++++++++++++++++++
>  4 files changed, 108 insertions(+), 62 deletions(-)
> 
> diff --git a/monitor.c b/monitor.c
> index 12a6fe2..a3bc2c7 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -422,6 +422,30 @@ static void timestamp_put(QDict *qdict)
>      qdict_put_obj(qdict, "timestamp", obj);
>  }
>  
> +
> +static const char *monitor_event_names[] = {
> +    [QEVENT_SHUTDOWN] = "SHUTDOWN",
> +    [QEVENT_RESET] = "RESET",
> +    [QEVENT_POWERDOWN] = "POWERDOWN",
> +    [QEVENT_STOP] = "STOP",
> +    [QEVENT_RESUME] = "RESUME",
> +    [QEVENT_VNC_CONNECTED] = "VNC_CONNECTED",
> +    [QEVENT_VNC_INITIALIZED] = "VNC_INITIALIZED",
> +    [QEVENT_VNC_DISCONNECTED] = "VNC_DISCONNECTED",
> +    [QEVENT_BLOCK_IO_ERROR] = "BLOCK_IO_ERROR",
> +    [QEVENT_RTC_CHANGE] = "RTC_CHANGE",
> +    [QEVENT_WATCHDOG] = "WATCHDOG",
> +    [QEVENT_SPICE_CONNECTED] = "SPICE_CONNECTED",
> +    [QEVENT_SPICE_INITIALIZED] = "SPICE_INITIALIZED",
> +    [QEVENT_SPICE_DISCONNECTED] = "SPICE_DISCONNECTED",
> +    [QEVENT_BLOCK_JOB_COMPLETED] = "BLOCK_JOB_COMPLETED",
> +    [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
> +    [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
> +    [QEVENT_SUSPEND] = "SUSPEND",
> +    [QEVENT_WAKEUP] = "WAKEUP",
> +};
> +QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
> +
>  /**
>   * monitor_protocol_event(): Generate a Monitor event
>   *
> @@ -435,68 +459,8 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
>  
>      assert(event < QEVENT_MAX);
>  
> -    switch (event) {
> -        case QEVENT_SHUTDOWN:
> -            event_name = "SHUTDOWN";
> -            break;
> -        case QEVENT_RESET:
> -            event_name = "RESET";
> -            break;
> -        case QEVENT_POWERDOWN:
> -            event_name = "POWERDOWN";
> -            break;
> -        case QEVENT_STOP:
> -            event_name = "STOP";
> -            break;
> -        case QEVENT_RESUME:
> -            event_name = "RESUME";
> -            break;
> -        case QEVENT_VNC_CONNECTED:
> -            event_name = "VNC_CONNECTED";
> -            break;
> -        case QEVENT_VNC_INITIALIZED:
> -            event_name = "VNC_INITIALIZED";
> -            break;
> -        case QEVENT_VNC_DISCONNECTED:
> -            event_name = "VNC_DISCONNECTED";
> -            break;
> -        case QEVENT_BLOCK_IO_ERROR:
> -            event_name = "BLOCK_IO_ERROR";
> -            break;
> -        case QEVENT_RTC_CHANGE:
> -            event_name = "RTC_CHANGE";
> -            break;
> -        case QEVENT_WATCHDOG:
> -            event_name = "WATCHDOG";
> -            break;
> -        case QEVENT_SPICE_CONNECTED:
> -            event_name = "SPICE_CONNECTED";
> -            break;
> -        case QEVENT_SPICE_INITIALIZED:
> -            event_name = "SPICE_INITIALIZED";
> -            break;
> -        case QEVENT_SPICE_DISCONNECTED:
> -            event_name = "SPICE_DISCONNECTED";
> -            break;
> -        case QEVENT_BLOCK_JOB_COMPLETED:
> -            event_name = "BLOCK_JOB_COMPLETED";
> -            break;
> -        case QEVENT_BLOCK_JOB_CANCELLED:
> -            event_name = "BLOCK_JOB_CANCELLED";
> -            break;
> -        case QEVENT_DEVICE_TRAY_MOVED:
> -             event_name = "DEVICE_TRAY_MOVED";
> -            break;
> -        case QEVENT_SUSPEND:
> -            event_name = "SUSPEND";
> -            break;
> -        case QEVENT_WAKEUP:
> -            event_name = "WAKEUP";
> -            break;
> -        default:
> -            abort();
> -            break;
> -    }
> +    event_name = monitor_event_names[event];
> +    assert(event_name != NULL);
>  
>      qmp = qdict_new();
>      timestamp_put(qmp);
> @@ -738,6 +702,25 @@ 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 *event_name = monitor_event_names[e];
> +        assert(event_name != NULL);
> +        info = g_malloc0(sizeof(*info));
> +        info->value = g_malloc0(sizeof(*info->value));
> +        info->value->name = g_strdup(event_name);
> +
> +        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/monitor.h b/monitor.h
> index 0d49800..cd1d878 100644
> --- a/monitor.h
> +++ b/monitor.h
> @@ -41,6 +41,10 @@ typedef enum MonitorEvent {
>      QEVENT_DEVICE_TRAY_MOVED,
>      QEVENT_SUSPEND,
>      QEVENT_WAKEUP,
> +
> +    /* Add to 'monitor_event_names' array in monitor.c when
> +     * defining new events here */
> +
>      QEVENT_MAX,
>  } MonitorEvent;
>  
> 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..9c15d3c 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 contains:
> +
> +- "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
>  -------------
>

Patch

diff --git a/monitor.c b/monitor.c
index 12a6fe2..a3bc2c7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -422,6 +422,30 @@  static void timestamp_put(QDict *qdict)
     qdict_put_obj(qdict, "timestamp", obj);
 }
 
+
+static const char *monitor_event_names[] = {
+    [QEVENT_SHUTDOWN] = "SHUTDOWN",
+    [QEVENT_RESET] = "RESET",
+    [QEVENT_POWERDOWN] = "POWERDOWN",
+    [QEVENT_STOP] = "STOP",
+    [QEVENT_RESUME] = "RESUME",
+    [QEVENT_VNC_CONNECTED] = "VNC_CONNECTED",
+    [QEVENT_VNC_INITIALIZED] = "VNC_INITIALIZED",
+    [QEVENT_VNC_DISCONNECTED] = "VNC_DISCONNECTED",
+    [QEVENT_BLOCK_IO_ERROR] = "BLOCK_IO_ERROR",
+    [QEVENT_RTC_CHANGE] = "RTC_CHANGE",
+    [QEVENT_WATCHDOG] = "WATCHDOG",
+    [QEVENT_SPICE_CONNECTED] = "SPICE_CONNECTED",
+    [QEVENT_SPICE_INITIALIZED] = "SPICE_INITIALIZED",
+    [QEVENT_SPICE_DISCONNECTED] = "SPICE_DISCONNECTED",
+    [QEVENT_BLOCK_JOB_COMPLETED] = "BLOCK_JOB_COMPLETED",
+    [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
+    [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
+    [QEVENT_SUSPEND] = "SUSPEND",
+    [QEVENT_WAKEUP] = "WAKEUP",
+};
+QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
+
 /**
  * monitor_protocol_event(): Generate a Monitor event
  *
@@ -435,68 +459,8 @@  void monitor_protocol_event(MonitorEvent event, QObject *data)
 
     assert(event < QEVENT_MAX);
 
-    switch (event) {
-        case QEVENT_SHUTDOWN:
-            event_name = "SHUTDOWN";
-            break;
-        case QEVENT_RESET:
-            event_name = "RESET";
-            break;
-        case QEVENT_POWERDOWN:
-            event_name = "POWERDOWN";
-            break;
-        case QEVENT_STOP:
-            event_name = "STOP";
-            break;
-        case QEVENT_RESUME:
-            event_name = "RESUME";
-            break;
-        case QEVENT_VNC_CONNECTED:
-            event_name = "VNC_CONNECTED";
-            break;
-        case QEVENT_VNC_INITIALIZED:
-            event_name = "VNC_INITIALIZED";
-            break;
-        case QEVENT_VNC_DISCONNECTED:
-            event_name = "VNC_DISCONNECTED";
-            break;
-        case QEVENT_BLOCK_IO_ERROR:
-            event_name = "BLOCK_IO_ERROR";
-            break;
-        case QEVENT_RTC_CHANGE:
-            event_name = "RTC_CHANGE";
-            break;
-        case QEVENT_WATCHDOG:
-            event_name = "WATCHDOG";
-            break;
-        case QEVENT_SPICE_CONNECTED:
-            event_name = "SPICE_CONNECTED";
-            break;
-        case QEVENT_SPICE_INITIALIZED:
-            event_name = "SPICE_INITIALIZED";
-            break;
-        case QEVENT_SPICE_DISCONNECTED:
-            event_name = "SPICE_DISCONNECTED";
-            break;
-        case QEVENT_BLOCK_JOB_COMPLETED:
-            event_name = "BLOCK_JOB_COMPLETED";
-            break;
-        case QEVENT_BLOCK_JOB_CANCELLED:
-            event_name = "BLOCK_JOB_CANCELLED";
-            break;
-        case QEVENT_DEVICE_TRAY_MOVED:
-             event_name = "DEVICE_TRAY_MOVED";
-            break;
-        case QEVENT_SUSPEND:
-            event_name = "SUSPEND";
-            break;
-        case QEVENT_WAKEUP:
-            event_name = "WAKEUP";
-            break;
-        default:
-            abort();
-            break;
-    }
+    event_name = monitor_event_names[event];
+    assert(event_name != NULL);
 
     qmp = qdict_new();
     timestamp_put(qmp);
@@ -738,6 +702,25 @@  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 *event_name = monitor_event_names[e];
+        assert(event_name != NULL);
+        info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->name = g_strdup(event_name);
+
+        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/monitor.h b/monitor.h
index 0d49800..cd1d878 100644
--- a/monitor.h
+++ b/monitor.h
@@ -41,6 +41,10 @@  typedef enum MonitorEvent {
     QEVENT_DEVICE_TRAY_MOVED,
     QEVENT_SUSPEND,
     QEVENT_WAKEUP,
+
+    /* Add to 'monitor_event_names' array in monitor.c when
+     * defining new events here */
+
     QEVENT_MAX,
 } MonitorEvent;
 
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..9c15d3c 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 contains:
+
+- "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
 -------------