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

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>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
Daniel P. Berrange 2012-05-21 17:59:51 +01:00 committed by Luiz Capitulino
parent 5f96415527
commit 4860853d60
4 changed files with 108 additions and 62 deletions

107
monitor.c
View file

@ -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)
{

View file

@ -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;

View file

@ -227,6 +227,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
#

View file

@ -1208,6 +1208,43 @@ EQMP
.mhandler.cmd_new = qmp_marshal_input_query_commands,
},
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
-------------