Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging

* remotes/qmp-unstable/queue/qmp: (43 commits)
  monitor: protect event emission
  monitor: protect outbuf and mux_out with mutex
  qemu-char: make writes thread-safe
  qemu-char: move pty_chr_update_read_handler around
  qemu-char: do not call chr_write directly
  qemu-char: introduce qemu_chr_alloc
  qapi event: clean up
  qapi event: convert QUORUM events
  qapi event: convert GUEST_PANICKED
  qapi event: convert BALLOON_CHANGE
  qmp: convert ACPI_DEVICE_OST event
  qapi event: convert SPICE events
  qapi event: convert VNC events
  qapi event: convert NIC_RX_FILTER_CHANGED
  qapi event: convert other BLOCK_JOB events
  qapi event: convert BLOCK_IMAGE_CORRUPTED
  qapi event: convert BLOCK_IO_ERROR and BLOCK_JOB_ERROR
  qapi event: convert DEVICE_TRAY_MOVED
  qapi event: convert DEVICE_DELETED
  qapi event: convert WATCHDOG
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-06-24 13:06:13 +01:00
commit 089a39486f
75 changed files with 2053 additions and 1319 deletions

View File

@ -45,8 +45,8 @@ endif
endif
GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
GENERATED_HEADERS += trace/generated-events.h
GENERATED_SOURCES += trace/generated-events.c
@ -202,7 +202,7 @@ Makefile: $(version-obj-y) $(version-lobj-y)
# Build libraries
libqemustub.a: $(stub-obj-y)
libqemuutil.a: $(util-obj-y) qapi-types.o qapi-visit.o
libqemuutil.a: $(util-obj-y) qapi-types.o qapi-visit.o qapi-event.o
block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL
util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
@ -246,18 +246,27 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \
" GEN $@")
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
$(SRC_PATH)/qapi-event.json
qapi-types.c qapi-types.h :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
$(gen-out-type) -o "." -b -i $<, \
" GEN $@")
qapi-visit.c qapi-visit.h :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
$(gen-out-type) -o "." -b -i $<, \
" GEN $@")
qapi-event.c qapi-event.h :\
$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
$(gen-out-type) -o "." -b -i $<, \
" GEN $@")
qmp-commands.h qmp-marshal.c :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
$(gen-out-type) -o "." -m -i $<, \
" GEN $@")

View File

@ -12,7 +12,7 @@ block-obj-y += main-loop.o iohandler.o qemu-timer.o
block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y += block/
block-obj-y += qapi-types.o qapi-visit.o
block-obj-y += qapi-types.o qapi-visit.o qapi-event.o
block-obj-y += qemu-io-cmds.o
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o

View File

@ -574,7 +574,7 @@ CharDriverState *chr_baum_init(void)
int tty;
baum = g_malloc0(sizeof(BaumDriverState));
baum->chr = chr = g_malloc0(sizeof(CharDriverState));
baum->chr = chr = qemu_chr_alloc();
chr->opaque = baum;
chr->chr_write = baum_write;

View File

@ -67,7 +67,7 @@ CharDriverState *qemu_chr_open_msmouse(void)
{
CharDriverState *chr;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
chr->chr_write = msmouse_chr_write;
chr->chr_close = msmouse_chr_close;
chr->explicit_be_open = true;

View File

@ -81,19 +81,6 @@ static int qemu_balloon_status(BalloonInfo *info)
return 1;
}
void qemu_balloon_changed(int64_t actual)
{
QObject *data;
data = qobject_from_jsonf("{ 'actual': %" PRId64 " }",
actual);
monitor_protocol_event(QEVENT_BALLOON_CHANGE, data);
qobject_decref(data);
}
BalloonInfo *qmp_query_balloon(Error **errp)
{
BalloonInfo *info;

73
block.c
View File

@ -24,7 +24,6 @@
#include "config-host.h"
#include "qemu-common.h"
#include "trace.h"
#include "monitor/monitor.h"
#include "block/block_int.h"
#include "block/blockjob.h"
#include "qemu/module.h"
@ -35,6 +34,7 @@
#include "block/qapi.h"
#include "qmp-commands.h"
#include "qemu/timer.h"
#include "qapi-event.h"
#ifdef CONFIG_BSD
#include <sys/types.h>
@ -2132,47 +2132,6 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
bs->dev_opaque = opaque;
}
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
enum MonitorEvent ev,
BlockErrorAction action, bool is_read)
{
QObject *data;
const char *action_str;
switch (action) {
case BDRV_ACTION_REPORT:
action_str = "report";
break;
case BDRV_ACTION_IGNORE:
action_str = "ignore";
break;
case BDRV_ACTION_STOP:
action_str = "stop";
break;
default:
abort();
}
data = qobject_from_jsonf("{ 'device': %s, 'action': %s, 'operation': %s }",
bdrv->device_name,
action_str,
is_read ? "read" : "write");
monitor_protocol_event(ev, data);
qobject_decref(data);
}
static void bdrv_emit_qmp_eject_event(BlockDriverState *bs, bool ejected)
{
QObject *data;
data = qobject_from_jsonf("{ 'device': %s, 'tray-open': %i }",
bdrv_get_device_name(bs), ejected);
monitor_protocol_event(QEVENT_DEVICE_TRAY_MOVED, data);
qobject_decref(data);
}
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
{
if (bs->dev_ops && bs->dev_ops->change_media_cb) {
@ -2180,11 +2139,13 @@ static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
bs->dev_ops->change_media_cb(bs->dev_opaque, load);
if (tray_was_closed) {
/* tray open */
bdrv_emit_qmp_eject_event(bs, true);
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
true, &error_abort);
}
if (load) {
/* tray close */
bdrv_emit_qmp_eject_event(bs, false);
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
false, &error_abort);
}
}
}
@ -3606,13 +3567,14 @@ BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int e
switch (on_err) {
case BLOCKDEV_ON_ERROR_ENOSPC:
return (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
return (error == ENOSPC) ?
BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_STOP:
return BDRV_ACTION_STOP;
return BLOCK_ERROR_ACTION_STOP;
case BLOCKDEV_ON_ERROR_REPORT:
return BDRV_ACTION_REPORT;
return BLOCK_ERROR_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_IGNORE:
return BDRV_ACTION_IGNORE;
return BLOCK_ERROR_ACTION_IGNORE;
default:
abort();
}
@ -3627,7 +3589,7 @@ void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
{
assert(error >= 0);
if (action == BDRV_ACTION_STOP) {
if (action == BLOCK_ERROR_ACTION_STOP) {
/* First set the iostatus, so that "info block" returns an iostatus
* that matches the events raised so far (an additional error iostatus
* is fine, but not a lost one).
@ -3643,10 +3605,16 @@ void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
* also ensures that the STOP/RESUME pair of events is emitted.
*/
qemu_system_vmstop_request_prepare();
bdrv_emit_qmp_error_event(bs, QEVENT_BLOCK_IO_ERROR, action, is_read);
qapi_event_send_block_io_error(bdrv_get_device_name(bs),
is_read ? IO_OPERATION_TYPE_READ :
IO_OPERATION_TYPE_WRITE,
action, &error_abort);
qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
} else {
bdrv_emit_qmp_error_event(bs, QEVENT_BLOCK_IO_ERROR, action, is_read);
qapi_event_send_block_io_error(bdrv_get_device_name(bs),
is_read ? IO_OPERATION_TYPE_READ :
IO_OPERATION_TYPE_WRITE,
action, &error_abort);
}
}
@ -5216,7 +5184,8 @@ void bdrv_eject(BlockDriverState *bs, bool eject_flag)
}
if (bs->device_name[0] != '\0') {
bdrv_emit_qmp_eject_event(bs, eject_flag);
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
eject_flag, &error_abort);
}
}

View File

@ -325,7 +325,7 @@ static void coroutine_fn backup_run(void *opaque)
/* Depending on error action, fail now or retry cluster */
BlockErrorAction action =
backup_error_action(job, error_is_read, -ret);
if (action == BDRV_ACTION_REPORT) {
if (action == BLOCK_ERROR_ACTION_REPORT) {
break;
} else {
start--;

View File

@ -118,7 +118,7 @@ static void mirror_write_complete(void *opaque, int ret)
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
action = mirror_error_action(s, false, -ret);
if (action == BDRV_ACTION_REPORT && s->ret >= 0) {
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
s->ret = ret;
}
}
@ -135,7 +135,7 @@ static void mirror_read_complete(void *opaque, int ret)
bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
action = mirror_error_action(s, true, -ret);
if (action == BDRV_ACTION_REPORT && s->ret >= 0) {
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
s->ret = ret;
}
@ -415,7 +415,8 @@ static void coroutine_fn mirror_run(void *opaque)
trace_mirror_before_flush(s);
ret = bdrv_flush(s->target);
if (ret < 0) {
if (mirror_error_action(s, false, -ret) == BDRV_ACTION_REPORT) {
if (mirror_error_action(s, false, -ret) ==
BLOCK_ERROR_ACTION_REPORT) {
goto immediate_exit;
}
} else {
@ -426,7 +427,7 @@ static void coroutine_fn mirror_run(void *opaque)
*/
s->common.offset = end * BDRV_SECTOR_SIZE;
if (!s->synced) {
block_job_ready(&s->common);
block_job_event_ready(&s->common);
s->synced = true;
}

View File

@ -27,6 +27,7 @@
#include "block/qcow2.h"
#include "qemu/range.h"
#include "qapi/qmp/types.h"
#include "qapi-event.h"
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
@ -1807,7 +1808,6 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
} else if (ret > 0) {
int metadata_ol_bitnr = ffs(ret) - 1;
char *message;
QObject *data;
assert(metadata_ol_bitnr < QCOW2_OL_MAX_BITNR);
@ -1816,12 +1816,14 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
metadata_ol_names[metadata_ol_bitnr]);
message = g_strdup_printf("Prevented %s overwrite",
metadata_ol_names[metadata_ol_bitnr]);
data = qobject_from_jsonf("{ 'device': %s, 'msg': %s, 'offset': %"
PRId64 ", 'size': %" PRId64 " }", bs->device_name, message,
offset, size);
monitor_protocol_event(QEVENT_BLOCK_IMAGE_CORRUPTED, data);
qapi_event_send_block_image_corrupted(bdrv_get_device_name(bs),
message,
true,
offset,
true,
size,
&error_abort);
g_free(message);
qobject_decref(data);
qcow2_mark_corrupt(bs);
bs->drv = NULL; /* make BDS unusable */

View File

@ -17,6 +17,7 @@
#include <gnutls/crypto.h>
#include "block/block_int.h"
#include "qapi/qmp/qjson.h"
#include "qapi-event.h"
#define HASH_LENGTH 32
@ -198,32 +199,22 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
{
QObject *data;
assert(node_name);
data = qobject_from_jsonf("{ 'node-name': %s"
", 'sector-num': %" PRId64
", 'sectors-count': %d }",
node_name, acb->sector_num, acb->nb_sectors);
const char *msg = NULL;
if (ret < 0) {
QDict *dict = qobject_to_qdict(data);
qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
msg = strerror(-ret);
}
monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data);
qobject_decref(data);
qapi_event_send_quorum_report_bad(!!msg, msg, node_name,
acb->sector_num, acb->nb_sectors, &error_abort);
}
static void quorum_report_failure(QuorumAIOCB *acb)
{
QObject *data;
const char *reference = acb->common.bs->device_name[0] ?
acb->common.bs->device_name :
acb->common.bs->node_name;
data = qobject_from_jsonf("{ 'reference': %s"
", 'sector-num': %" PRId64
", 'sectors-count': %d }",
reference, acb->sector_num, acb->nb_sectors);
monitor_protocol_event(QEVENT_QUORUM_FAILURE, data);
qobject_decref(data);
qapi_event_send_quorum_failure(reference, acb->sector_num,
acb->nb_sectors, &error_abort);
}
static int quorum_vote_error(QuorumAIOCB *acb);

View File

@ -159,14 +159,14 @@ wait:
BlockErrorAction action =
block_job_error_action(&s->common, s->common.bs, s->on_error,
true, -ret);
if (action == BDRV_ACTION_STOP) {
if (action == BLOCK_ERROR_ACTION_STOP) {
n = 0;
continue;
}
if (error == 0) {
error = ret;
}
if (action == BDRV_ACTION_REPORT) {
if (action == BLOCK_ERROR_ACTION_REPORT) {
break;
}
}

View File

@ -1847,23 +1847,21 @@ void qmp_block_resize(bool has_device, const char *device,
static void block_job_cb(void *opaque, int ret)
{
BlockDriverState *bs = opaque;
QObject *obj;
const char *msg = NULL;
trace_block_job_cb(bs, bs->job, ret);
assert(bs->job);
obj = qobject_from_block_job(bs->job);
if (ret < 0) {
QDict *dict = qobject_to_qdict(obj);
qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
msg = strerror(-ret);
}
if (block_job_is_cancelled(bs->job)) {
monitor_protocol_event(QEVENT_BLOCK_JOB_CANCELLED, obj);
block_job_event_cancelled(bs->job);
} else {
monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
block_job_event_completed(bs->job, msg);
}
qobject_decref(obj);
bdrv_put_ref_bh_schedule(bs);
}

View File

@ -26,7 +26,6 @@
#include "config-host.h"
#include "qemu-common.h"
#include "trace.h"
#include "monitor/monitor.h"
#include "block/block.h"
#include "block/blockjob.h"
#include "block/block_int.h"
@ -34,6 +33,7 @@
#include "block/coroutine.h"
#include "qmp-commands.h"
#include "qemu/timer.h"
#include "qapi-event.h"
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
@ -232,26 +232,31 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
}
}
QObject *qobject_from_block_job(BlockJob *job)
void block_job_event_cancelled(BlockJob *job)
{
return qobject_from_jsonf("{ 'type': %s,"
"'device': %s,"
"'len': %" PRId64 ","
"'offset': %" PRId64 ","
"'speed': %" PRId64 " }",
BlockJobType_lookup[job->driver->job_type],
bdrv_get_device_name(job->bs),
job->len,
job->offset,
job->speed);
qapi_event_send_block_job_cancelled(job->driver->job_type,
bdrv_get_device_name(job->bs),
job->len,
job->offset,
job->speed,
&error_abort);
}
void block_job_ready(BlockJob *job)
void block_job_event_completed(BlockJob *job, const char *msg)
{
QObject *data = qobject_from_block_job(job);
monitor_protocol_event(QEVENT_BLOCK_JOB_READY, data);
qobject_decref(data);
qapi_event_send_block_job_completed(job->driver->job_type,
bdrv_get_device_name(job->bs),
job->len,
job->offset,
job->speed,
!!msg,
msg,
&error_abort);
}
void block_job_event_ready(BlockJob *job)
{
qapi_event_send_block_job_ready(bdrv_get_device_name(job->bs), &error_abort);
}
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
@ -262,22 +267,26 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
switch (on_err) {
case BLOCKDEV_ON_ERROR_ENOSPC:
action = (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
action = (error == ENOSPC) ?
BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
break;
case BLOCKDEV_ON_ERROR_STOP:
action = BDRV_ACTION_STOP;
action = BLOCK_ERROR_ACTION_STOP;
break;
case BLOCKDEV_ON_ERROR_REPORT:
action = BDRV_ACTION_REPORT;
action = BLOCK_ERROR_ACTION_REPORT;
break;
case BLOCKDEV_ON_ERROR_IGNORE:
action = BDRV_ACTION_IGNORE;
action = BLOCK_ERROR_ACTION_IGNORE;
break;
default:
abort();
}
bdrv_emit_qmp_error_event(job->bs, QEVENT_BLOCK_JOB_ERROR, action, is_read);
if (action == BDRV_ACTION_STOP) {
qapi_event_send_block_job_error(bdrv_get_device_name(bs),
is_read ? IO_OPERATION_TYPE_READ :
IO_OPERATION_TYPE_WRITE,
action, &error_abort);
if (action == BLOCK_ERROR_ACTION_STOP) {
block_job_pause(job);
block_job_iostatus_set_err(job, error);
if (bs != job->bs) {

4
cpus.c
View File

@ -26,6 +26,7 @@
#include "config-host.h"
#include "monitor/monitor.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/sysemu.h"
#include "exec/gdbstub.h"
#include "sysemu/dma.h"
@ -38,6 +39,7 @@
#include "qemu/main-loop.h"
#include "qemu/bitmap.h"
#include "qemu/seqlock.h"
#include "qapi-event.h"
#ifndef _WIN32
#include "qemu/compatfd.h"
@ -530,7 +532,7 @@ static int do_vm_stop(RunState state)
pause_all_vcpus();
runstate_set(state);
vm_state_notify(0, state);
monitor_protocol_event(QEVENT_STOP, NULL);
qapi_event_send_stop(&error_abort);
}
bdrv_drain_all();

View File

@ -215,6 +215,24 @@ An example command is:
'data': { 'arg1': 'str', '*arg2': 'str' },
'returns': 'str' }
=== Events ===
Events are defined with the keyword 'event'. When 'data' is also specified,
additional info will be carried on. Finally there will be C API generated
in qapi-event.h; when called by QEMU code, a message with timestamp will
be emitted on the wire. If timestamp is -1, it means failure to retrieve host
time.
An example event is:
{ 'event': 'EVENT_C',
'data': { '*a': 'int', 'b': 'str' } }
Resulting in this JSON object:
{ "event": "EVENT_C",
"data": { "b": "test string" },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
== Code generation ==

View File

@ -1,551 +0,0 @@
QEMU Machine Protocol Events
============================
ACPI_DEVICE_OST
---------------
Emitted when guest executes ACPI _OST method.
- data: ACPIOSTInfo type as described in qapi-schema.json
{ "event": "ACPI_DEVICE_OST",
"data": { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0 } }
BALLOON_CHANGE
--------------
Emitted when the guest changes the actual BALLOON level. This
value is equivalent to the 'actual' field return by the
'query-balloon' command
Data:
- "actual": actual level of the guest memory balloon in bytes (json-number)
Example:
{ "event": "BALLOON_CHANGE",
"data": { "actual": 944766976 },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
BLOCK_IMAGE_CORRUPTED
---------------------
Emitted when a disk image is being marked corrupt.
Data:
- "device": Device name (json-string)
- "msg": Informative message (e.g., reason for the corruption) (json-string)
- "offset": If the corruption resulted from an image access, this is the access
offset into the image (json-int)
- "size": If the corruption resulted from an image access, this is the access
size (json-int)
Example:
{ "event": "BLOCK_IMAGE_CORRUPTED",
"data": { "device": "ide0-hd0",
"msg": "Prevented active L1 table overwrite", "offset": 196608,
"size": 65536 },
"timestamp": { "seconds": 1378126126, "microseconds": 966463 } }
BLOCK_IO_ERROR
--------------
Emitted when a disk I/O error occurs.
Data:
- "device": device name (json-string)
- "operation": I/O operation (json-string, "read" or "write")
- "action": action that has been taken, it's one of the following (json-string):
"ignore": error has been ignored
"report": error has been reported to the device
"stop": the VM is going to stop because of the error
Example:
{ "event": "BLOCK_IO_ERROR",
"data": { "device": "ide0-hd1",
"operation": "write",
"action": "stop" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
Note: If action is "stop", a STOP event will eventually follow the
BLOCK_IO_ERROR event.
BLOCK_JOB_CANCELLED
-------------------
Emitted when a block job has been cancelled.
Data:
- "type": Job type (json-string; "stream" for image streaming
"commit" for block commit)
- "device": Device name (json-string)
- "len": Maximum progress value (json-int)
- "offset": Current progress value (json-int)
On success this is equal to len.
On failure this is less than len.
- "speed": Rate limit, bytes per second (json-int)
Example:
{ "event": "BLOCK_JOB_CANCELLED",
"data": { "type": "stream", "device": "virtio-disk0",
"len": 10737418240, "offset": 134217728,
"speed": 0 },
"timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
BLOCK_JOB_COMPLETED
-------------------
Emitted when a block job has completed.
Data:
- "type": Job type (json-string; "stream" for image streaming
"commit" for block commit)
- "device": Device name (json-string)
- "len": Maximum progress value (json-int)
- "offset": Current progress value (json-int)
On success this is equal to len.
On failure this is less than len.
- "speed": Rate limit, bytes per second (json-int)
- "error": Error message (json-string, optional)
Only present on failure. This field contains a human-readable
error message. There are no semantics other than that streaming
has failed and clients should not try to interpret the error
string.
Example:
{ "event": "BLOCK_JOB_COMPLETED",
"data": { "type": "stream", "device": "virtio-disk0",
"len": 10737418240, "offset": 10737418240,
"speed": 0 },
"timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
BLOCK_JOB_ERROR
---------------
Emitted when a block job encounters an error.
Data:
- "device": device name (json-string)
- "operation": I/O operation (json-string, "read" or "write")
- "action": action that has been taken, it's one of the following (json-string):
"ignore": error has been ignored, the job may fail later
"report": error will be reported and the job canceled
"stop": error caused job to be paused
Example:
{ "event": "BLOCK_JOB_ERROR",
"data": { "device": "ide0-hd1",
"operation": "write",
"action": "stop" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
BLOCK_JOB_READY
---------------
Emitted when a block job is ready to complete.
Data:
- "device": device name (json-string)
Example:
{ "event": "BLOCK_JOB_READY",
"data": { "device": "ide0-hd1" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
event.
DEVICE_DELETED
--------------
Emitted whenever the device removal completion is acknowledged
by the guest.
At this point, it's safe to reuse the specified device ID.
Device removal can be initiated by the guest or by HMP/QMP commands.
Data:
- "device": device name (json-string, optional)
- "path": device path (json-string)
{ "event": "DEVICE_DELETED",
"data": { "device": "virtio-net-pci-0",
"path": "/machine/peripheral/virtio-net-pci-0" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
DEVICE_TRAY_MOVED
-----------------
It's emitted whenever the tray of a removable device is moved by the guest
or by HMP/QMP commands.
Data:
- "device": device name (json-string)
- "tray-open": true if the tray has been opened or false if it has been closed
(json-bool)
{ "event": "DEVICE_TRAY_MOVED",
"data": { "device": "ide1-cd0",
"tray-open": true
},
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
GUEST_PANICKED
--------------
Emitted when guest OS panic is detected.
Data:
- "action": Action that has been taken (json-string, currently always "pause").
Example:
{ "event": "GUEST_PANICKED",
"data": { "action": "pause" } }
NIC_RX_FILTER_CHANGED
---------------------
The event is emitted once until the query command is executed,
the first event will always be emitted.
Data:
- "name": net client name (json-string)
- "path": device path (json-string)
{ "event": "NIC_RX_FILTER_CHANGED",
"data": { "name": "vnet0",
"path": "/machine/peripheral/vnet0/virtio-backend" },
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
}
QUORUM_FAILURE
--------------
Emitted by the Quorum block driver if it fails to establish a quorum.
Data:
- "reference": device name if defined else node name.
- "sector-num": Number of the first sector of the failed read operation.
- "sector-count": Failed read operation sector count.
Example:
{ "event": "QUORUM_FAILURE",
"data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
QUORUM_REPORT_BAD
-----------------
Emitted to report a corruption of a Quorum file.
Data:
- "error": Error message (json-string, optional)
Only present on failure. This field contains a human-readable
error message. There are no semantics other than that the
block layer reported an error and clients should not try to
interpret the error string.
- "node-name": The graph node name of the block driver state.
- "sector-num": Number of the first sector of the failed read operation.
- "sector-count": Failed read operation sector count.
Example:
{ "event": "QUORUM_REPORT_BAD",
"data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
RESET
-----
Emitted when the Virtual Machine is reseted.
Data: None.
Example:
{ "event": "RESET",
"timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
RESUME
------
Emitted when the Virtual Machine resumes execution.
Data: None.
Example:
{ "event": "RESUME",
"timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
RTC_CHANGE
----------
Emitted when the guest changes the RTC time.
Data:
- "offset": Offset between base RTC clock (as specified by -rtc base), and
new RTC clock value (json-number)
Example:
{ "event": "RTC_CHANGE",
"data": { "offset": 78 },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
SHUTDOWN
--------
Emitted when the Virtual Machine is powered down.
Data: None.
Example:
{ "event": "SHUTDOWN",
"timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
Note: If the command-line option "-no-shutdown" has been specified, a STOP
event will eventually follow the SHUTDOWN event.
SPICE_CONNECTED, SPICE_DISCONNECTED
-----------------------------------
Emitted when a SPICE client connects or disconnects.
Data:
- "server": Server information (json-object)
- "host": IP address (json-string)
- "port": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "client": Client information (json-object)
- "host": IP address (json-string)
- "port": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
Example:
{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
"event": "SPICE_CONNECTED",
"data": {
"server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
"client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
}}
SPICE_INITIALIZED
-----------------
Emitted after initial handshake and authentication takes place (if any)
and the SPICE channel is up'n'running
Data:
- "server": Server information (json-object)
- "host": IP address (json-string)
- "port": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "auth": authentication method (json-string, optional)
- "client": Client information (json-object)
- "host": IP address (json-string)
- "port": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "connection-id": spice connection id. All channels with the same id
belong to the same spice session (json-int)
- "channel-type": channel type. "1" is the main control channel, filter for
this one if you want track spice sessions only (json-int)
- "channel-id": channel id. Usually "0", might be different needed when
multiple channels of the same type exist, such as multiple
display channels in a multihead setup (json-int)
- "tls": whevener the channel is encrypted (json-bool)
Example:
{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
"event": "SPICE_INITIALIZED",
"data": {"server": {"auth": "spice", "port": "5921",
"family": "ipv4", "host": "127.0.0.1"},
"client": {"port": "49004", "family": "ipv4", "channel-type": 3,
"connection-id": 1804289383, "host": "127.0.0.1",
"channel-id": 0, "tls": true}
}}
STOP
----
Emitted when the Virtual Machine is stopped.
Data: None.
Example:
{ "event": "STOP",
"timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
SUSPEND
-------
Emitted when guest enters S3 state.
Data: None.
Example:
{ "event": "SUSPEND",
"timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
SUSPEND_DISK
------------
Emitted when the guest makes a request to enter S4 state.
Data: None.
Example:
{ "event": "SUSPEND_DISK",
"timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
Note: QEMU shuts down when entering S4 state.
VNC_CONNECTED
-------------
Emitted when a VNC client establishes a connection.
Data:
- "server": Server information (json-object)
- "host": IP address (json-string)
- "service": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "auth": authentication method (json-string, optional)
- "client": Client information (json-object)
- "host": IP address (json-string)
- "service": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
Example:
{ "event": "VNC_CONNECTED",
"data": {
"server": { "auth": "sasl", "family": "ipv4",
"service": "5901", "host": "0.0.0.0" },
"client": { "family": "ipv4", "service": "58425",
"host": "127.0.0.1" } },
"timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
Note: This event is emitted before any authentication takes place, thus
the authentication ID is not provided.
VNC_DISCONNECTED
----------------
Emitted when the connection is closed.
Data:
- "server": Server information (json-object)
- "host": IP address (json-string)
- "service": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "auth": authentication method (json-string, optional)
- "client": Client information (json-object)
- "host": IP address (json-string)
- "service": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "x509_dname": TLS dname (json-string, optional)
- "sasl_username": SASL username (json-string, optional)
Example:
{ "event": "VNC_DISCONNECTED",
"data": {
"server": { "auth": "sasl", "family": "ipv4",
"service": "5901", "host": "0.0.0.0" },
"client": { "family": "ipv4", "service": "58425",
"host": "127.0.0.1", "sasl_username": "luiz" } },
"timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
VNC_INITIALIZED
---------------
Emitted after authentication takes place (if any) and the VNC session is
made active.
Data:
- "server": Server information (json-object)
- "host": IP address (json-string)
- "service": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "auth": authentication method (json-string, optional)
- "client": Client information (json-object)
- "host": IP address (json-string)
- "service": port number (json-string)
- "family": address family (json-string, "ipv4" or "ipv6")
- "x509_dname": TLS dname (json-string, optional)
- "sasl_username": SASL username (json-string, optional)
Example:
{ "event": "VNC_INITIALIZED",
"data": {
"server": { "auth": "sasl", "family": "ipv4",
"service": "5901", "host": "0.0.0.0"},
"client": { "family": "ipv4", "service": "46089",
"host": "127.0.0.1", "sasl_username": "luiz" } },
"timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
WAKEUP
------
Emitted when the guest has woken up from S3 and is running.
Data: None.
Example:
{ "event": "WAKEUP",
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
WATCHDOG
--------
Emitted when the watchdog device's timer is expired.
Data:
- "action": Action that has been taken, it's one of the following (json-string):
"reset", "shutdown", "poweroff", "pause", "debug", or "none"
Example:
{ "event": "WATCHDOG",
"data": { "action": "reset" },
"timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.

View File

@ -55,7 +55,7 @@ these four paragraphs for those parts of this code that are retained.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
static inline void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
{
uint32_t z;
@ -81,7 +81,7 @@ INLINE void shift32RightJamming(uint32_t a, int_fast16_t count, uint32_t *zPtr)
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
static inline void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
{
uint64_t z;
@ -115,7 +115,7 @@ INLINE void shift64RightJamming(uint64_t a, int_fast16_t count, uint64_t *zPtr)
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
static inline void
shift64ExtraRightJamming(
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
{
@ -152,7 +152,7 @@ INLINE void
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
shift128Right(
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
{
@ -187,7 +187,7 @@ INLINE void
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
shift128RightJamming(
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
{
@ -238,7 +238,7 @@ INLINE void
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
static inline void
shift128ExtraRightJamming(
uint64_t a0,
uint64_t a1,
@ -296,7 +296,7 @@ INLINE void
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
shortShift128Left(
uint64_t a0, uint64_t a1, int_fast16_t count, uint64_t *z0Ptr, uint64_t *z1Ptr)
{
@ -315,7 +315,7 @@ INLINE void
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
shortShift192Left(
uint64_t a0,
uint64_t a1,
@ -350,7 +350,7 @@ INLINE void
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
add128(
uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
{
@ -370,7 +370,7 @@ INLINE void
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
add192(
uint64_t a0,
uint64_t a1,
@ -408,7 +408,7 @@ INLINE void
| `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
sub128(
uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
{
@ -426,7 +426,7 @@ INLINE void
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
sub192(
uint64_t a0,
uint64_t a1,
@ -462,7 +462,7 @@ INLINE void
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
static inline void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
{
uint32_t aHigh, aLow, bHigh, bLow;
uint64_t z0, zMiddleA, zMiddleB, z1;
@ -492,7 +492,7 @@ INLINE void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr
| `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
mul128By64To192(
uint64_t a0,
uint64_t a1,
@ -520,7 +520,7 @@ INLINE void
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
static inline void
mul128To256(
uint64_t a0,
uint64_t a1,
@ -702,7 +702,7 @@ static int8 countLeadingZeros64( uint64_t a )
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
static inline flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
@ -715,7 +715,7 @@ INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
static inline flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
@ -728,7 +728,7 @@ INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
| returns 0.
*----------------------------------------------------------------------------*/
INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
static inline flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
@ -741,7 +741,7 @@ INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
static inline flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );

View File

@ -66,7 +66,7 @@ these four paragraphs for those parts of this code that are retained.
| Returns the fraction bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE uint32_t extractFloat16Frac(float16 a)
static inline uint32_t extractFloat16Frac(float16 a)
{
return float16_val(a) & 0x3ff;
}
@ -75,7 +75,7 @@ INLINE uint32_t extractFloat16Frac(float16 a)
| Returns the exponent bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE int_fast16_t extractFloat16Exp(float16 a)
static inline int_fast16_t extractFloat16Exp(float16 a)
{
return (float16_val(a) >> 10) & 0x1f;
}
@ -84,7 +84,7 @@ INLINE int_fast16_t extractFloat16Exp(float16 a)
| Returns the sign bit of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE flag extractFloat16Sign(float16 a)
static inline flag extractFloat16Sign(float16 a)
{
return float16_val(a)>>15;
}
@ -255,7 +255,7 @@ static int64 roundAndPackUint64(flag zSign, uint64_t absZ0,
| Returns the fraction bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE uint32_t extractFloat32Frac( float32 a )
static inline uint32_t extractFloat32Frac( float32 a )
{
return float32_val(a) & 0x007FFFFF;
@ -266,7 +266,7 @@ INLINE uint32_t extractFloat32Frac( float32 a )
| Returns the exponent bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE int_fast16_t extractFloat32Exp(float32 a)
static inline int_fast16_t extractFloat32Exp(float32 a)
{
return ( float32_val(a)>>23 ) & 0xFF;
@ -277,7 +277,7 @@ INLINE int_fast16_t extractFloat32Exp(float32 a)
| Returns the sign bit of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE flag extractFloat32Sign( float32 a )
static inline flag extractFloat32Sign( float32 a )
{
return float32_val(a)>>31;
@ -328,7 +328,7 @@ static void
| significand.
*----------------------------------------------------------------------------*/
INLINE float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig)
static inline float32 packFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig)
{
return make_float32(
@ -440,7 +440,7 @@ static float32
| Returns the fraction bits of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE uint64_t extractFloat64Frac( float64 a )
static inline uint64_t extractFloat64Frac( float64 a )
{
return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF );
@ -451,7 +451,7 @@ INLINE uint64_t extractFloat64Frac( float64 a )
| Returns the exponent bits of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE int_fast16_t extractFloat64Exp(float64 a)
static inline int_fast16_t extractFloat64Exp(float64 a)
{
return ( float64_val(a)>>52 ) & 0x7FF;
@ -462,7 +462,7 @@ INLINE int_fast16_t extractFloat64Exp(float64 a)
| Returns the sign bit of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE flag extractFloat64Sign( float64 a )
static inline flag extractFloat64Sign( float64 a )
{
return float64_val(a)>>63;
@ -513,7 +513,7 @@ static void
| significand.
*----------------------------------------------------------------------------*/
INLINE float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig)
static inline float64 packFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig)
{
return make_float64(
@ -625,7 +625,7 @@ static float64
| value `a'.
*----------------------------------------------------------------------------*/
INLINE uint64_t extractFloatx80Frac( floatx80 a )
static inline uint64_t extractFloatx80Frac( floatx80 a )
{
return a.low;
@ -637,7 +637,7 @@ INLINE uint64_t extractFloatx80Frac( floatx80 a )
| value `a'.
*----------------------------------------------------------------------------*/
INLINE int32 extractFloatx80Exp( floatx80 a )
static inline int32 extractFloatx80Exp( floatx80 a )
{
return a.high & 0x7FFF;
@ -649,7 +649,7 @@ INLINE int32 extractFloatx80Exp( floatx80 a )
| `a'.
*----------------------------------------------------------------------------*/
INLINE flag extractFloatx80Sign( floatx80 a )
static inline flag extractFloatx80Sign( floatx80 a )
{
return a.high>>15;
@ -679,7 +679,7 @@ static void
| extended double-precision floating-point value, returning the result.
*----------------------------------------------------------------------------*/
INLINE floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig )
static inline floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig )
{
floatx80 z;
@ -921,7 +921,7 @@ static floatx80
| floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE uint64_t extractFloat128Frac1( float128 a )
static inline uint64_t extractFloat128Frac1( float128 a )
{
return a.low;
@ -933,7 +933,7 @@ INLINE uint64_t extractFloat128Frac1( float128 a )
| floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE uint64_t extractFloat128Frac0( float128 a )
static inline uint64_t extractFloat128Frac0( float128 a )
{
return a.high & LIT64( 0x0000FFFFFFFFFFFF );
@ -945,7 +945,7 @@ INLINE uint64_t extractFloat128Frac0( float128 a )
| `a'.
*----------------------------------------------------------------------------*/
INLINE int32 extractFloat128Exp( float128 a )
static inline int32 extractFloat128Exp( float128 a )
{
return ( a.high>>48 ) & 0x7FFF;
@ -956,7 +956,7 @@ INLINE int32 extractFloat128Exp( float128 a )
| Returns the sign bit of the quadruple-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
INLINE flag extractFloat128Sign( float128 a )
static inline flag extractFloat128Sign( float128 a )
{
return a.high>>63;
@ -1017,7 +1017,7 @@ static void
| significand.
*----------------------------------------------------------------------------*/
INLINE float128
static inline float128
packFloat128( flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 )
{
float128 z;
@ -7088,7 +7088,7 @@ uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
}
#define COMPARE(s, nan_exp) \
INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
static inline int float ## s ## _compare_internal( float ## s a, float ## s b, \
int is_quiet STATUS_PARAM ) \
{ \
flag aSign, bSign; \
@ -7140,7 +7140,7 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
COMPARE(32, 0xff)
COMPARE(64, 0x7ff)
INLINE int floatx80_compare_internal( floatx80 a, floatx80 b,
static inline int floatx80_compare_internal( floatx80 a, floatx80 b,
int is_quiet STATUS_PARAM )
{
flag aSign, bSign;
@ -7186,7 +7186,7 @@ int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
return floatx80_compare_internal(a, b, 1 STATUS_VAR);
}
INLINE int float128_compare_internal( float128 a, float128 b,
static inline int float128_compare_internal( float128 a, float128 b,
int is_quiet STATUS_PARAM )
{
flag aSign, bSign;
@ -7242,7 +7242,7 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
* semantics provided by many CPUs which predate that specification.
*/
#define MINMAX(s) \
INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b, \
static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
int ismin, int isieee STATUS_PARAM) \
{ \
flag aSign, bSign; \

5
hmp.c
View File

@ -465,7 +465,8 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
for (client = info->clients; client; client = client->next) {
monitor_printf(mon, "Client:\n");
monitor_printf(mon, " address: %s:%s\n",
client->value->host, client->value->service);
client->value->base->host,
client->value->base->service);
monitor_printf(mon, " x509_dname: %s\n",
client->value->x509_dname ?
client->value->x509_dname : "none");
@ -513,7 +514,7 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict)
for (chan = info->channels; chan; chan = chan->next) {
monitor_printf(mon, "Channel:\n");
monitor_printf(mon, " address: %s:%s%s\n",
chan->value->host, chan->value->port,
chan->value->base->host, chan->value->base->port,
chan->value->tls ? " [tls]" : "");
monitor_printf(mon, " session: %" PRId64 "\n",
chan->value->connection_id);

View File

@ -22,11 +22,11 @@
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/acpi/acpi.h"
#include "monitor/monitor.h"
#include "qemu/config-file.h"
#include "qapi/opts-visitor.h"
#include "qapi/dealloc-visitor.h"
#include "qapi-visit.h"
#include "qapi-event.h"
struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */
@ -550,7 +550,7 @@ static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
break;
default:
if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */
monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL);
qapi_event_send_suspend_disk(&error_abort);
qemu_system_shutdown_request();
}
break;

View File

@ -3,10 +3,7 @@
#include "hw/mem/pc-dimm.h"
#include "hw/boards.h"
#include "trace.h"
#include "qapi-visit.h"
#include "monitor/monitor.h"
#include "qapi/dealloc-visitor.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi-event.h"
static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
{
@ -39,29 +36,6 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list)
}
}
static void acpi_memory_ost_mon_event(const MemHotplugState *mem_st)
{
Visitor *v;
QObject *out_info;
QapiDeallocVisitor *md;
QmpOutputVisitor *mo = qmp_output_visitor_new();
MemStatus *mdev = &mem_st->devs[mem_st->selector];
ACPIOSTInfo *info = acpi_memory_device_status(mem_st->selector, mdev);
v = qmp_output_get_visitor(mo);
visit_type_ACPIOSTInfo(v, &info, "unused", NULL);
out_info = qmp_output_get_qobject(mo);
monitor_protocol_event(QEVENT_ACPI_OST, out_info);
qobject_decref(out_info);
qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
visit_type_ACPIOSTInfo(v, &info, "unused", NULL);
qapi_dealloc_visitor_cleanup(md);
}
static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
unsigned int size)
{
@ -115,6 +89,7 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
{
MemHotplugState *mem_st = opaque;
MemStatus *mdev;
ACPIOSTInfo *info;
if (!mem_st->dev_count) {
return;
@ -147,7 +122,10 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
mdev->ost_status = data;
trace_mhp_acpi_write_ost_status(mem_st->selector, mdev->ost_status);
/* TODO: implement memory removal on guest signal */
acpi_memory_ost_mon_event(mem_st);
info = acpi_memory_device_status(mem_st->selector, mdev);
qapi_event_send_acpi_device_ost(info, &error_abort);
qapi_free_ACPIOSTInfo(info);
break;
case 0x14:
mdev = &mem_st->devs[mem_st->selector];

View File

@ -30,7 +30,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#define INLINE static inline
#define HAS_YM3812 1
#include <stdio.h>
@ -247,7 +246,7 @@ static INT32 feedback2; /* connect for SLOT 2 */
/* --------------------- subroutines --------------------- */
INLINE int Limit( int val, int max, int min ) {
static inline int Limit( int val, int max, int min ) {
if ( val > max )
val = max;
else if ( val < min )
@ -257,7 +256,7 @@ INLINE int Limit( int val, int max, int min ) {
}
/* status set and IRQ handling */
INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
{
/* set status flag */
OPL->status |= flag;
@ -273,7 +272,7 @@ INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
}
/* status reset and IRQ handling */
INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
{
/* reset status flag */
OPL->status &=~flag;
@ -289,7 +288,7 @@ INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
}
/* IRQ mask set */
INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
{
OPL->statusmask = flag;
/* IRQ handling check */
@ -298,7 +297,7 @@ INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
}
/* ----- key on ----- */
INLINE void OPL_KEYON(OPL_SLOT *SLOT)
static inline void OPL_KEYON(OPL_SLOT *SLOT)
{
/* sin wave restart */
SLOT->Cnt = 0;
@ -309,7 +308,7 @@ INLINE void OPL_KEYON(OPL_SLOT *SLOT)
SLOT->eve = EG_AED;
}
/* ----- key off ----- */
INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
static inline void OPL_KEYOFF(OPL_SLOT *SLOT)
{
if( SLOT->evm > ENV_MOD_RR)
{
@ -325,7 +324,7 @@ INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
/* return : envelope output */
INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
{
/* calcrate envelope generator */
if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
@ -371,7 +370,7 @@ static void set_algorithm( OPL_CH *CH)
}
/* ---------- frequency counter for operater update ---------- */
INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
{
int ksr;
@ -391,7 +390,7 @@ INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
}
/* set multi,am,vib,EG-TYP,KSR,mul */
INLINE void set_mul(FM_OPL *OPL,int slot,int v)
static inline void set_mul(FM_OPL *OPL,int slot,int v)
{
OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -405,7 +404,7 @@ INLINE void set_mul(FM_OPL *OPL,int slot,int v)
}
/* set ksl & tl */
INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v)
{
OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -421,7 +420,7 @@ INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
}
/* set attack rate & decay rate */
INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
static inline void set_ar_dr(FM_OPL *OPL,int slot,int v)
{
OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -438,7 +437,7 @@ INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
}
/* set sustain level & release rate */
INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
{
OPL_CH *CH = &OPL->P_CH[slot/2];
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
@ -455,7 +454,7 @@ INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
/* operator output calcrator */
#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
/* ---------- calcrate one of channel ---------- */
INLINE void OPL_CALC_CH( OPL_CH *CH )
static inline void OPL_CALC_CH( OPL_CH *CH )
{
UINT32 env_out;
OPL_SLOT *SLOT;
@ -500,7 +499,7 @@ INLINE void OPL_CALC_CH( OPL_CH *CH )
/* ---------- calcrate rhythm block ---------- */
#define WHITE_NOISE_db 6.0
INLINE void OPL_CALC_RH( OPL_CH *CH )
static inline void OPL_CALC_RH( OPL_CH *CH )
{
UINT32 env_tam,env_sd,env_top,env_hh;
int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
@ -716,7 +715,7 @@ static void OPLCloseTable( void )
}
/* CSM Key Control */
INLINE void CSMKeyControll(OPL_CH *CH)
static inline void CSMKeyControll(OPL_CH *CH)
{
OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
OPL_SLOT *slot2 = &CH->SLOT[SLOT2];

View File

@ -56,17 +56,17 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error);
VirtIOBlock *s = req->dev;
if (action == BDRV_ACTION_STOP) {
if (action == BLOCK_ERROR_ACTION_STOP) {
req->next = s->rq;
s->rq = req;
} else if (action == BDRV_ACTION_REPORT) {
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
bdrv_acct_done(s->bs, &req->acct);
g_free(req);
}
bdrv_error_action(s->bs, action, is_read, error);
return action != BDRV_ACTION_IGNORE;
return action != BLOCK_ERROR_ACTION_IGNORE;
}
static void virtio_blk_rw_complete(void *opaque, int ret)

View File

@ -32,9 +32,9 @@
#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
#include "hw/hotplug.h"
#include "hw/boards.h"
#include "qapi-event.h"
int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@ -972,7 +972,6 @@ static void device_unparent(Object *obj)
{
DeviceState *dev = DEVICE(obj);
BusState *bus;
QObject *event_data;
bool have_realized = dev->realized;
if (dev->realized) {
@ -992,14 +991,7 @@ static void device_unparent(Object *obj)
if (have_realized) {
gchar *path = object_get_canonical_path(OBJECT(dev));
if (dev->id) {
event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
dev->id, path);
} else {
event_data = qobject_from_jsonf("{ 'path': %s }", path);
}
monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
qobject_decref(event_data);
qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort);
g_free(path);
}
}

View File

@ -596,10 +596,10 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
bool is_read = (op & BM_STATUS_RETRY_READ) != 0;
BlockErrorAction action = bdrv_get_error_action(s->bs, is_read, error);
if (action == BDRV_ACTION_STOP) {
if (action == BLOCK_ERROR_ACTION_STOP) {
s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
s->bus->error_status = op;
} else if (action == BDRV_ACTION_REPORT) {
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
if (op & BM_STATUS_DMA_RETRY) {
dma_buf_commit(s);
ide_dma_error(s);
@ -608,7 +608,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
}
}
bdrv_error_action(s->bs, action, is_read, error);
return action != BDRV_ACTION_IGNORE;
return action != BLOCK_ERROR_ACTION_IGNORE;
}
void ide_dma_cb(void *opaque, int ret)

View File

@ -14,12 +14,12 @@
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/i386/pc.h"
#include "qapi-event.h"
/* The bit of supported pv event */
#define PVPANIC_F_PANICKED 0
@ -31,15 +31,6 @@
#define ISA_PVPANIC_DEVICE(obj) \
OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE)
static void panicked_mon_event(const char *action)
{
QObject *data;
data = qobject_from_jsonf("{ 'action': %s }", action);
monitor_protocol_event(QEVENT_GUEST_PANICKED, data);
qobject_decref(data);
}
static void handle_event(int event)
{
static bool logged;
@ -50,7 +41,7 @@ static void handle_event(int event)
}
if (event & PVPANIC_PANICKED) {
panicked_mon_event("pause");
qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
vm_stop(RUN_STATE_GUEST_PANICKED);
return;
}

View File

@ -22,7 +22,7 @@
#include "net/vhost_net.h"
#include "hw/virtio/virtio-bus.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
#include "qapi-event.h"
#define VIRTIO_NET_VM_VERSION 11
@ -199,19 +199,12 @@ static void virtio_net_set_link_status(NetClientState *nc)
static void rxfilter_notify(NetClientState *nc)
{
QObject *event_data;
VirtIONet *n = qemu_get_nic_opaque(nc);
if (nc->rxfilter_notify_enabled) {
gchar *path = object_get_canonical_path(OBJECT(n->qdev));
if (n->netclient_name) {
event_data = qobject_from_jsonf("{ 'name': %s, 'path': %s }",
n->netclient_name, path);
} else {
event_data = qobject_from_jsonf("{ 'path': %s }", path);
}
monitor_protocol_event(QEVENT_NIC_RX_FILTER_CHANGED, event_data);
qobject_decref(event_data);
qapi_event_send_nic_rx_filter_changed(!!n->netclient_name,
n->netclient_name, path, &error_abort);
g_free(path);
/* disable event notification to avoid events flooding */

View File

@ -32,6 +32,7 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "qapi-event.h"
#include <libfdt.h>
@ -93,7 +94,7 @@ static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
tm.tm_sec = rtas_ld(args, 5);
/* Just generate a monitor event for the change */
rtc_change_mon_event(&tm);
qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort);
spapr->rtc_offset = qemu_timedate_diff(&tm);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);

View File

@ -419,7 +419,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
BlockErrorAction action = bdrv_get_error_action(s->qdev.conf.bs, is_read, error);
if (action == BDRV_ACTION_REPORT) {
if (action == BLOCK_ERROR_ACTION_REPORT) {
switch (error) {
case ENOMEDIUM:
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
@ -439,10 +439,10 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
}
}
bdrv_error_action(s->qdev.conf.bs, action, is_read, error);
if (action == BDRV_ACTION_STOP) {
if (action == BLOCK_ERROR_ACTION_STOP) {
scsi_req_retry(&r->req);
}
return action != BDRV_ACTION_IGNORE;
return action != BLOCK_ERROR_ACTION_IGNORE;
}
static void scsi_write_complete(void * opaque, int ret)

View File

@ -26,6 +26,7 @@
#include "sysemu/sysemu.h"
#include "hw/timer/mc146818rtc.h"
#include "qapi/visitor.h"
#include "qapi-event.h"
#ifdef TARGET_I386
#include "hw/i386/apic.h"
@ -530,7 +531,7 @@ static void rtc_set_time(RTCState *s)
s->base_rtc = mktimegm(&tm);
s->last_update = qemu_clock_get_ns(rtc_clock);
rtc_change_mon_event(&tm);
qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort);
}
static void rtc_set_cmos(RTCState *s, const struct tm *tm)

View File

@ -24,6 +24,7 @@
#include "sysemu/kvm.h"
#include "exec/address-spaces.h"
#include "qapi/visitor.h"
#include "qapi-event.h"
#if defined(__linux__)
#include <sys/mman.h>
@ -289,8 +290,9 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
memcpy(&config, config_data, sizeof(struct virtio_balloon_config));
dev->actual = le32_to_cpu(config.actual);
if (dev->actual != oldactual) {
qemu_balloon_changed(ram_size -
((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
qapi_event_send_balloon_change(ram_size -
((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT),
&error_abort);
}
}

View File

@ -24,9 +24,9 @@
#include "qemu/config-file.h"
#include "qemu/queue.h"
#include "qapi/qmp/types.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "sysemu/watchdog.h"
#include "qapi-event.h"
/* Possible values for action parameter. */
#define WDT_RESET 1 /* Hard reset. */
@ -101,15 +101,6 @@ int select_watchdog_action(const char *p)
return 0;
}
static void watchdog_mon_event(const char *action)
{
QObject *data;
data = qobject_from_jsonf("{ 'action': %s }", action);
monitor_protocol_event(QEVENT_WATCHDOG, data);
qobject_decref(data);
}
/* This actually performs the "action" once a watchdog has expired,
* ie. reboot, shutdown, exit, etc.
*/
@ -117,31 +108,31 @@ void watchdog_perform_action(void)
{
switch(watchdog_action) {
case WDT_RESET: /* same as 'system_reset' in monitor */
watchdog_mon_event("reset");
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_RESET, &error_abort);
qemu_system_reset_request();
break;
case WDT_SHUTDOWN: /* same as 'system_powerdown' in monitor */
watchdog_mon_event("shutdown");
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_SHUTDOWN, &error_abort);
qemu_system_powerdown_request();
break;
case WDT_POWEROFF: /* same as 'quit' command in monitor */
watchdog_mon_event("poweroff");
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_POWEROFF, &error_abort);
exit(0);
case WDT_PAUSE: /* same as 'stop' command in monitor */
watchdog_mon_event("pause");
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_PAUSE, &error_abort);
vm_stop(RUN_STATE_WATCHDOG);
break;
case WDT_DEBUG:
watchdog_mon_event("debug");
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_DEBUG, &error_abort);
fprintf(stderr, "watchdog: timer fired\n");
break;
case WDT_NONE:
watchdog_mon_event("none");
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_NONE, &error_abort);
break;
}
}

View File

@ -150,10 +150,6 @@ typedef enum {
#define BDRV_BLOCK_ALLOCATED 0x10
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
typedef enum {
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
} BlockErrorAction;
typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
typedef struct BDRVReopenState {

View File

@ -425,9 +425,6 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
#ifdef _WIN32
int is_windows_drive(const char *filename);
#endif
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
enum MonitorEvent ev,
BlockErrorAction action, bool is_read);
/**
* stream_start:

View File

@ -217,12 +217,21 @@ void block_job_pause(BlockJob *job);
void block_job_resume(BlockJob *job);
/**
* qobject_from_block_job:
* block_job_event_cancle:
* @job: The job whose information is requested.
*
* Return a QDict corresponding to @job's query-block-jobs entry.
* Send a BLOCK_JOB_CANCELLED event for the specified job.
*/
QObject *qobject_from_block_job(BlockJob *job);
void block_job_event_cancelled(BlockJob *job);
/**
* block_job_ready:
* @job: The job which is now ready to complete.
* @msg: Error message. Only present on failure.
*
* Send a BLOCK_JOB_COMPLETED event for the specified job.
*/
void block_job_event_completed(BlockJob *job, const char *msg);
/**
* block_job_ready:
@ -230,7 +239,7 @@ QObject *qobject_from_block_job(BlockJob *job);
*
* Send a BLOCK_JOB_READY event for the specified job.
*/
void block_job_ready(BlockJob *job);
void block_job_event_ready(BlockJob *job);
/**
* block_job_is_paused:

View File

@ -63,7 +63,6 @@ typedef uint64_t uint64;
typedef int64_t int64;
#define LIT64( a ) a##LL
#define INLINE static inline
#define STATUS_PARAM , float_status *status
#define STATUS(field) status->field
@ -181,59 +180,59 @@ typedef struct float_status {
flag default_nan_mode;
} float_status;
INLINE void set_float_detect_tininess(int val STATUS_PARAM)
static inline void set_float_detect_tininess(int val STATUS_PARAM)
{
STATUS(float_detect_tininess) = val;
}
INLINE void set_float_rounding_mode(int val STATUS_PARAM)
static inline void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
}
INLINE void set_float_exception_flags(int val STATUS_PARAM)
static inline void set_float_exception_flags(int val STATUS_PARAM)
{
STATUS(float_exception_flags) = val;
}
INLINE void set_floatx80_rounding_precision(int val STATUS_PARAM)
static inline void set_floatx80_rounding_precision(int val STATUS_PARAM)
{
STATUS(floatx80_rounding_precision) = val;
}
INLINE void set_flush_to_zero(flag val STATUS_PARAM)
static inline void set_flush_to_zero(flag val STATUS_PARAM)
{
STATUS(flush_to_zero) = val;
}
INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM)
static inline void set_flush_inputs_to_zero(flag val STATUS_PARAM)
{
STATUS(flush_inputs_to_zero) = val;
}
INLINE void set_default_nan_mode(flag val STATUS_PARAM)
static inline void set_default_nan_mode(flag val STATUS_PARAM)
{
STATUS(default_nan_mode) = val;
}
INLINE int get_float_detect_tininess(float_status *status)
static inline int get_float_detect_tininess(float_status *status)
{
return STATUS(float_detect_tininess);
}
INLINE int get_float_rounding_mode(float_status *status)
static inline int get_float_rounding_mode(float_status *status)
{
return STATUS(float_rounding_mode);
}
INLINE int get_float_exception_flags(float_status *status)
static inline int get_float_exception_flags(float_status *status)
{
return STATUS(float_exception_flags);
}
INLINE int get_floatx80_rounding_precision(float_status *status)
static inline int get_floatx80_rounding_precision(float_status *status)
{
return STATUS(floatx80_rounding_precision);
}
INLINE flag get_flush_to_zero(float_status *status)
static inline flag get_flush_to_zero(float_status *status)
{
return STATUS(flush_to_zero);
}
INLINE flag get_flush_inputs_to_zero(float_status *status)
static inline flag get_flush_inputs_to_zero(float_status *status)
{
return STATUS(flush_inputs_to_zero);
}
INLINE flag get_default_nan_mode(float_status *status)
static inline flag get_default_nan_mode(float_status *status)
{
return STATUS(default_nan_mode);
}
@ -284,22 +283,22 @@ float128 int64_to_float128(int64_t STATUS_PARAM);
float128 uint64_to_float128(uint64_t STATUS_PARAM);
/* We provide the int16 versions for symmetry of API with float-to-int */
INLINE float32 int16_to_float32(int16_t v STATUS_PARAM)
static inline float32 int16_to_float32(int16_t v STATUS_PARAM)
{
return int32_to_float32(v STATUS_VAR);
}
INLINE float32 uint16_to_float32(uint16_t v STATUS_PARAM)
static inline float32 uint16_to_float32(uint16_t v STATUS_PARAM)
{
return uint32_to_float32(v STATUS_VAR);
}
INLINE float64 int16_to_float64(int16_t v STATUS_PARAM)
static inline float64 int16_to_float64(int16_t v STATUS_PARAM)
{
return int32_to_float64(v STATUS_VAR);
}
INLINE float64 uint16_to_float64(uint16_t v STATUS_PARAM)
static inline float64 uint16_to_float64(uint16_t v STATUS_PARAM)
{
return uint32_to_float64(v STATUS_VAR);
}
@ -319,7 +318,7 @@ int float16_is_quiet_nan( float16 );
int float16_is_signaling_nan( float16 );
float16 float16_maybe_silence_nan( float16 );
INLINE int float16_is_any_nan(float16 a)
static inline int float16_is_any_nan(float16 a)
{
return ((float16_val(a) & ~0x8000) > 0x7c00);
}
@ -380,7 +379,7 @@ int float32_is_signaling_nan( float32 );
float32 float32_maybe_silence_nan( float32 );
float32 float32_scalbn( float32, int STATUS_PARAM );
INLINE float32 float32_abs(float32 a)
static inline float32 float32_abs(float32 a)
{
/* Note that abs does *not* handle NaN specially, nor does
* it flush denormal inputs to zero.
@ -388,7 +387,7 @@ INLINE float32 float32_abs(float32 a)
return make_float32(float32_val(a) & 0x7fffffff);
}
INLINE float32 float32_chs(float32 a)
static inline float32 float32_chs(float32 a)
{
/* Note that chs does *not* handle NaN specially, nor does
* it flush denormal inputs to zero.
@ -396,32 +395,32 @@ INLINE float32 float32_chs(float32 a)
return make_float32(float32_val(a) ^ 0x80000000);
}
INLINE int float32_is_infinity(float32 a)
static inline int float32_is_infinity(float32 a)
{
return (float32_val(a) & 0x7fffffff) == 0x7f800000;
}
INLINE int float32_is_neg(float32 a)
static inline int float32_is_neg(float32 a)
{
return float32_val(a) >> 31;
}
INLINE int float32_is_zero(float32 a)
static inline int float32_is_zero(float32 a)
{
return (float32_val(a) & 0x7fffffff) == 0;
}
INLINE int float32_is_any_nan(float32 a)
static inline int float32_is_any_nan(float32 a)
{
return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL);
}
INLINE int float32_is_zero_or_denormal(float32 a)
static inline int float32_is_zero_or_denormal(float32 a)
{
return (float32_val(a) & 0x7f800000) == 0;
}
INLINE float32 float32_set_sign(float32 a, int sign)
static inline float32 float32_set_sign(float32 a, int sign)
{
return make_float32((float32_val(a) & 0x7fffffff) | (sign << 31));
}
@ -490,7 +489,7 @@ int float64_is_signaling_nan( float64 );
float64 float64_maybe_silence_nan( float64 );
float64 float64_scalbn( float64, int STATUS_PARAM );
INLINE float64 float64_abs(float64 a)
static inline float64 float64_abs(float64 a)
{
/* Note that abs does *not* handle NaN specially, nor does
* it flush denormal inputs to zero.
@ -498,7 +497,7 @@ INLINE float64 float64_abs(float64 a)
return make_float64(float64_val(a) & 0x7fffffffffffffffLL);
}
INLINE float64 float64_chs(float64 a)
static inline float64 float64_chs(float64 a)
{
/* Note that chs does *not* handle NaN specially, nor does
* it flush denormal inputs to zero.
@ -506,32 +505,32 @@ INLINE float64 float64_chs(float64 a)
return make_float64(float64_val(a) ^ 0x8000000000000000LL);
}
INLINE int float64_is_infinity(float64 a)
static inline int float64_is_infinity(float64 a)
{
return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL;
}
INLINE int float64_is_neg(float64 a)
static inline int float64_is_neg(float64 a)
{
return float64_val(a) >> 63;
}
INLINE int float64_is_zero(float64 a)
static inline int float64_is_zero(float64 a)
{
return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
}
INLINE int float64_is_any_nan(float64 a)
static inline int float64_is_any_nan(float64 a)
{
return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL);
}
INLINE int float64_is_zero_or_denormal(float64 a)
static inline int float64_is_zero_or_denormal(float64 a)
{
return (float64_val(a) & 0x7ff0000000000000LL) == 0;
}
INLINE float64 float64_set_sign(float64 a, int sign)
static inline float64 float64_set_sign(float64 a, int sign)
{
return make_float64((float64_val(a) & 0x7fffffffffffffffULL)
| ((int64_t)sign << 63));
@ -585,39 +584,39 @@ int floatx80_is_signaling_nan( floatx80 );
floatx80 floatx80_maybe_silence_nan( floatx80 );
floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM );
INLINE floatx80 floatx80_abs(floatx80 a)
static inline floatx80 floatx80_abs(floatx80 a)
{
a.high &= 0x7fff;
return a;
}
INLINE floatx80 floatx80_chs(floatx80 a)
static inline floatx80 floatx80_chs(floatx80 a)
{
a.high ^= 0x8000;
return a;
}
INLINE int floatx80_is_infinity(floatx80 a)
static inline int floatx80_is_infinity(floatx80 a)
{
return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL;
}
INLINE int floatx80_is_neg(floatx80 a)
static inline int floatx80_is_neg(floatx80 a)
{
return a.high >> 15;
}
INLINE int floatx80_is_zero(floatx80 a)
static inline int floatx80_is_zero(floatx80 a)
{
return (a.high & 0x7fff) == 0 && a.low == 0;
}
INLINE int floatx80_is_zero_or_denormal(floatx80 a)
static inline int floatx80_is_zero_or_denormal(floatx80 a)
{
return (a.high & 0x7fff) == 0;
}
INLINE int floatx80_is_any_nan(floatx80 a)
static inline int floatx80_is_any_nan(floatx80 a)
{
return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
}
@ -670,39 +669,39 @@ int float128_is_signaling_nan( float128 );
float128 float128_maybe_silence_nan( float128 );
float128 float128_scalbn( float128, int STATUS_PARAM );
INLINE float128 float128_abs(float128 a)
static inline float128 float128_abs(float128 a)
{
a.high &= 0x7fffffffffffffffLL;
return a;
}
INLINE float128 float128_chs(float128 a)
static inline float128 float128_chs(float128 a)
{
a.high ^= 0x8000000000000000LL;
return a;
}
INLINE int float128_is_infinity(float128 a)
static inline int float128_is_infinity(float128 a)
{
return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0;
}
INLINE int float128_is_neg(float128 a)
static inline int float128_is_neg(float128 a)
{
return a.high >> 63;
}
INLINE int float128_is_zero(float128 a)
static inline int float128_is_zero(float128 a)
{
return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
}
INLINE int float128_is_zero_or_denormal(float128 a)
static inline int float128_is_zero_or_denormal(float128 a)
{
return (a.high & 0x7fff000000000000LL) == 0;
}
INLINE int float128_is_any_nan(float128 a)
static inline int float128_is_any_nan(float128 a)
{
return ((a.high >> 48) & 0x7fff) == 0x7fff &&
((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0));

View File

@ -19,49 +19,8 @@ extern Monitor *default_mon;
/* flags for monitor commands */
#define MONITOR_CMD_ASYNC 0x0001
/* QMP events */
typedef enum MonitorEvent {
QEVENT_SHUTDOWN,
QEVENT_RESET,
QEVENT_POWERDOWN,
QEVENT_STOP,
QEVENT_RESUME,
QEVENT_VNC_CONNECTED,
QEVENT_VNC_INITIALIZED,
QEVENT_VNC_DISCONNECTED,
QEVENT_BLOCK_IO_ERROR,
QEVENT_RTC_CHANGE,
QEVENT_WATCHDOG,
QEVENT_SPICE_CONNECTED,
QEVENT_SPICE_INITIALIZED,
QEVENT_SPICE_DISCONNECTED,
QEVENT_BLOCK_JOB_COMPLETED,
QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_BLOCK_JOB_ERROR,
QEVENT_BLOCK_JOB_READY,
QEVENT_DEVICE_DELETED,
QEVENT_DEVICE_TRAY_MOVED,
QEVENT_NIC_RX_FILTER_CHANGED,
QEVENT_SUSPEND,
QEVENT_SUSPEND_DISK,
QEVENT_WAKEUP,
QEVENT_BALLOON_CHANGE,
QEVENT_SPICE_MIGRATE_COMPLETED,
QEVENT_GUEST_PANICKED,
QEVENT_BLOCK_IMAGE_CORRUPTED,
QEVENT_QUORUM_FAILURE,
QEVENT_QUORUM_REPORT_BAD,
QEVENT_ACPI_OST,
/* Add to 'monitor_event_names' array in monitor.c when
* defining new events here */
QEVENT_MAX,
} MonitorEvent;
int monitor_cur_is_qmp(void);
void monitor_protocol_event(MonitorEvent event, QObject *data);
void monitor_init(CharDriverState *chr, int flags);
int monitor_suspend(Monitor *mon);

27
include/qapi/qmp-event.h Normal file
View File

@ -0,0 +1,27 @@
/*
* QMP Event related
*
* Copyright (c) 2014 Wenchao Xia
*
* Authors:
* Wenchao Xia <wenchaoqemu@gmail.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#ifndef QMP_EVENT_H
#define QMP_EVENT_H
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
typedef void (*QMPEventFuncEmit)(unsigned event, QDict *dict, Error **errp);
void qmp_event_set_func_emit(QMPEventFuncEmit emit);
QMPEventFuncEmit qmp_event_get_func_emit(void);
QDict *qmp_event_build_dict(const char *event_name);
#endif

View File

@ -29,6 +29,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
#include "qemu/option.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qapi-types.h"
extern QemuOptsList socket_optslist;
@ -60,7 +61,7 @@ int inet_nonblocking_connect(const char *str,
void *opaque, Error **errp);
int inet_dgram_opts(QemuOpts *opts, Error **errp);
const char *inet_strfamily(int family);
NetworkAddressFamily inet_netfamily(int family);
int unix_listen_opts(QemuOpts *opts, Error **errp);
int unix_listen(const char *path, char *ostr, int olen, Error **errp);

View File

@ -24,6 +24,4 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque);
void qemu_remove_balloon_handler(void *opaque);
void qemu_balloon_changed(int64_t actual);
#endif

View File

@ -54,6 +54,7 @@ typedef struct {
typedef void IOEventHandler(void *opaque, int event);
struct CharDriverState {
QemuMutex chr_write_lock;
void (*init)(struct CharDriverState *s);
int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
int (*chr_sync_read)(struct CharDriverState *s,
@ -88,6 +89,15 @@ struct CharDriverState {
QTAILQ_ENTRY(CharDriverState) next;
};
/**
* @qemu_chr_alloc:
*
* Allocate and initialize a new CharDriverState.
*
* Returns: a newly allocated CharDriverState.
*/
CharDriverState *qemu_chr_alloc(void);
/**
* @qemu_chr_new_from_opts:
*
@ -155,6 +165,7 @@ void qemu_chr_fe_event(CharDriverState *s, int event);
* @qemu_chr_fe_printf:
*
* Write to a character backend using a printf style interface.
* This function is thread-safe.
*
* @fmt see #printf
*/
@ -167,8 +178,9 @@ int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
/**
* @qemu_chr_fe_write:
*
* Write data to a character backend from the front end. This function will
* send data from the front end to the back end.
* Write data to a character backend from the front end. This function
* will send data from the front end to the back end. This function
* is thread-safe.
*
* @buf the data
* @len the number of bytes to send
@ -183,7 +195,7 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len);
* Write data to a character backend from the front end. This function will
* send data from the front end to the back end. Unlike @qemu_chr_fe_write,
* this function will block if the back end cannot consume all of the data
* attempted to be written.
* attempted to be written. This function is thread-safe.
*
* @buf the data
* @len the number of bytes to send
@ -207,7 +219,7 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len);
/**
* @qemu_chr_fe_ioctl:
*
* Issue a device specific ioctl to a backend.
* Issue a device specific ioctl to a backend. This function is thread-safe.
*
* @cmd see CHR_IOCTL_*
* @arg the data associated with @cmd

View File

@ -26,6 +26,8 @@
#ifndef QEMU_OS_POSIX_H
#define QEMU_OS_POSIX_H
#include <sys/time.h>
void os_set_line_buffering(void);
void os_set_proc_name(const char *s);
void os_setup_signal_handling(void);

View File

@ -202,8 +202,6 @@ void do_usb_add(Monitor *mon, const QDict *qdict);
void do_usb_del(Monitor *mon, const QDict *qdict);
void usb_info(Monitor *mon, const QDict *qdict);
void rtc_change_mon_event(struct tm *tm);
void add_boot_device_path(int32_t bootindex, DeviceState *dev,
const char *suffix);
char *get_boot_devices_list(size_t *size, bool ignore_suffixes);

227
monitor.c
View File

@ -71,6 +71,8 @@
#include "hmp.h"
#include "qemu/thread.h"
#include "block/qapi.h"
#include "qapi/qmp-event.h"
#include "qapi-event.h"
/* for pic/irq_info */
#if defined(TARGET_SPARC)
@ -179,23 +181,28 @@ typedef struct MonitorControl {
* throttling is calculated globally, rather than per-Monitor
* instance.
*/
typedef struct MonitorEventState {
MonitorEvent event; /* Event being tracked */
int64_t rate; /* Period over which to throttle. 0 to disable */
int64_t last; /* Time at which event was last emitted */
typedef struct MonitorQAPIEventState {
QAPIEvent event; /* Event being tracked */
int64_t rate; /* Minimum time (in ns) between two events */
int64_t last; /* QEMU_CLOCK_REALTIME value at last emission */
QEMUTimer *timer; /* Timer for handling delayed events */
QObject *data; /* Event pending delayed dispatch */
} MonitorEventState;
} MonitorQAPIEventState;
struct Monitor {
CharDriverState *chr;
int mux_out;
int reset_seen;
int flags;
int suspend_cnt;
bool skip_flush;
QemuMutex out_lock;
QString *outbuf;
guint watch;
guint out_watch;
/* Read under either BQL or out_lock, written with BQL+out_lock. */
int mux_out;
ReadLineState *rs;
MonitorControl *mc;
CPUState *mon_cpu;
@ -210,6 +217,9 @@ struct Monitor {
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
/* Protects mon_list, monitor_event_state. */
static QemuMutex monitor_lock;
static QLIST_HEAD(mon_list, Monitor) mon_list;
static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets;
static int mon_refcount;
@ -268,17 +278,22 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
}
}
static void monitor_flush_locked(Monitor *mon);
static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
Monitor *mon = opaque;
mon->watch = 0;
monitor_flush(mon);
qemu_mutex_lock(&mon->out_lock);
mon->out_watch = 0;
monitor_flush_locked(mon);
qemu_mutex_unlock(&mon->out_lock);
return FALSE;
}
void monitor_flush(Monitor *mon)
/* Called with mon->out_lock held. */
static void monitor_flush_locked(Monitor *mon)
{
int rc;
size_t len;
@ -305,18 +320,26 @@ void monitor_flush(Monitor *mon)
QDECREF(mon->outbuf);
mon->outbuf = tmp;
}
if (mon->watch == 0) {
mon->watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT,
monitor_unblocked, mon);
if (mon->out_watch == 0) {
mon->out_watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT,
monitor_unblocked, mon);
}
}
}
void monitor_flush(Monitor *mon)
{
qemu_mutex_lock(&mon->out_lock);
monitor_flush_locked(mon);
qemu_mutex_unlock(&mon->out_lock);
}
/* flush at every end of line */
static void monitor_puts(Monitor *mon, const char *str)
{
char c;
qemu_mutex_lock(&mon->out_lock);
for(;;) {
c = *str++;
if (c == '\0')
@ -326,9 +349,10 @@ static void monitor_puts(Monitor *mon, const char *str)
}
qstring_append_chr(mon->outbuf, c);
if (c == '\n') {
monitor_flush(mon);
monitor_flush_locked(mon);
}
}
qemu_mutex_unlock(&mon->out_lock);
}
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
@ -439,66 +463,14 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
QDECREF(qmp);
}
static void timestamp_put(QDict *qdict)
{
int err;
QObject *obj;
qemu_timeval tv;
err = qemu_gettimeofday(&tv);
if (err < 0)
return;
obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
"'microseconds': %" PRId64 " }",
(int64_t) tv.tv_sec, (int64_t) tv.tv_usec);
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_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
[QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
[QEVENT_NIC_RX_FILTER_CHANGED] = "NIC_RX_FILTER_CHANGED",
[QEVENT_SUSPEND] = "SUSPEND",
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
[QEVENT_WAKEUP] = "WAKEUP",
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
[QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
[QEVENT_GUEST_PANICKED] = "GUEST_PANICKED",
[QEVENT_BLOCK_IMAGE_CORRUPTED] = "BLOCK_IMAGE_CORRUPTED",
[QEVENT_QUORUM_FAILURE] = "QUORUM_FAILURE",
[QEVENT_QUORUM_REPORT_BAD] = "QUORUM_REPORT_BAD",
[QEVENT_ACPI_OST] = "ACPI_DEVICE_OST",
};
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
static MonitorEventState monitor_event_state[QEVENT_MAX];
static MonitorQAPIEventState monitor_qapi_event_state[QAPI_EVENT_MAX];
/*
* Emits the event to every monitor instance
* Emits the event to every monitor instance, @event is only used for trace
* Called with monitor_lock held.
*/
static void
monitor_protocol_event_emit(MonitorEvent event,
QObject *data)
static void monitor_qapi_event_emit(QAPIEvent event, QObject *data)
{
Monitor *mon;
@ -510,20 +482,18 @@ monitor_protocol_event_emit(MonitorEvent event,
}
}
/*
* Queue a new event for emission to Monitor instances,
* applying any rate limiting if required.
*/
static void
monitor_protocol_event_queue(MonitorEvent event,
QObject *data)
monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp)
{
MonitorEventState *evstate;
MonitorQAPIEventState *evstate;
assert(event < QAPI_EVENT_MAX);
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
assert(event < QEVENT_MAX);
evstate = &(monitor_event_state[event]);
evstate = &(monitor_qapi_event_state[event]);
trace_monitor_protocol_event_queue(event,
data,
evstate->rate,
@ -531,8 +501,9 @@ monitor_protocol_event_queue(MonitorEvent event,
now);
/* Rate limit of 0 indicates no throttling */
qemu_mutex_lock(&monitor_lock);
if (!evstate->rate) {
monitor_protocol_event_emit(event, data);
monitor_qapi_event_emit(event, QOBJECT(data));
evstate->last = now;
} else {
int64_t delta = now - evstate->last;
@ -548,39 +519,39 @@ monitor_protocol_event_queue(MonitorEvent event,
int64_t then = evstate->last + evstate->rate;
timer_mod_ns(evstate->timer, then);
}
evstate->data = data;
evstate->data = QOBJECT(data);
qobject_incref(evstate->data);
} else {
monitor_protocol_event_emit(event, data);
monitor_qapi_event_emit(event, QOBJECT(data));
evstate->last = now;
}
}
qemu_mutex_unlock(&monitor_lock);
}
/*
* The callback invoked by QemuTimer when a delayed
* event is ready to be emitted
*/
static void monitor_protocol_event_handler(void *opaque)
static void monitor_qapi_event_handler(void *opaque)
{
MonitorEventState *evstate = opaque;
MonitorQAPIEventState *evstate = opaque;
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
trace_monitor_protocol_event_handler(evstate->event,
evstate->data,
evstate->last,
now);
qemu_mutex_lock(&monitor_lock);
if (evstate->data) {
monitor_protocol_event_emit(evstate->event, evstate->data);
monitor_qapi_event_emit(evstate->event, evstate->data);
qobject_decref(evstate->data);
evstate->data = NULL;
}
evstate->last = now;
qemu_mutex_unlock(&monitor_lock);
}
/*
* @event: the event ID to be limited
* @rate: the rate limit in milliseconds
@ -590,65 +561,35 @@ static void monitor_protocol_event_handler(void *opaque)
* milliseconds
*/
static void
monitor_protocol_event_throttle(MonitorEvent event,
int64_t rate)
monitor_qapi_event_throttle(QAPIEvent event, int64_t rate)
{
MonitorEventState *evstate;
assert(event < QEVENT_MAX);
MonitorQAPIEventState *evstate;
assert(event < QAPI_EVENT_MAX);
evstate = &(monitor_event_state[event]);
evstate = &(monitor_qapi_event_state[event]);
trace_monitor_protocol_event_throttle(event, rate);
evstate->event = event;
evstate->rate = rate * SCALE_MS;
evstate->timer = timer_new(QEMU_CLOCK_REALTIME,
SCALE_MS,
monitor_protocol_event_handler,
evstate);
evstate->last = 0;
evstate->data = NULL;
evstate->timer = timer_new(QEMU_CLOCK_REALTIME,
SCALE_MS,
monitor_qapi_event_handler,
evstate);
}
/* Global, one-time initializer to configure the rate limiting
* and initialize state */
static void monitor_protocol_event_init(void)
static void monitor_qapi_event_init(void)
{
/* Limit RTC & BALLOON events to 1 per second */
monitor_protocol_event_throttle(QEVENT_RTC_CHANGE, 1000);
monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000);
monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000);
/* Limit guest-triggerable events to 1 per second */
monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000);
monitor_qapi_event_throttle(QAPI_EVENT_WATCHDOG, 1000);
monitor_qapi_event_throttle(QAPI_EVENT_BALLOON_CHANGE, 1000);
/* limit the rate of quorum events to avoid hammering the management */
monitor_protocol_event_throttle(QEVENT_QUORUM_REPORT_BAD, 1000);
monitor_protocol_event_throttle(QEVENT_QUORUM_FAILURE, 1000);
}
monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_REPORT_BAD, 1000);
monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_FAILURE, 1000);
/**
* 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;
assert(event < QEVENT_MAX);
event_name = monitor_event_names[event];
assert(event_name != NULL);
qmp = qdict_new();
timestamp_put(qmp);
qdict_put(qmp, "event", qstring_from_str(event_name));
if (data) {
qobject_incref(data);
qdict_put_obj(qmp, "data", data);
}
trace_monitor_protocol_event(event, event_name, qmp);
monitor_protocol_event_queue(event, QOBJECT(qmp));
QDECREF(qmp);
qmp_event_set_func_emit(monitor_qapi_event_queue);
}
static int do_qmp_capabilities(Monitor *mon, const QDict *params,
@ -667,6 +608,7 @@ static void handle_user_command(Monitor *mon, const char *cmdline);
static void monitor_data_init(Monitor *mon)
{
memset(mon, 0, sizeof(Monitor));
qemu_mutex_init(&mon->out_lock);
mon->outbuf = qstring_new();
/* Use *mon_cmds by default. */
mon->cmd_table = mon_cmds;
@ -675,6 +617,7 @@ static void monitor_data_init(Monitor *mon)
static void monitor_data_destroy(Monitor *mon)
{
QDECREF(mon->outbuf);
qemu_mutex_destroy(&mon->out_lock);
}
char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
@ -702,11 +645,13 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
handle_user_command(&hmp, command_line);
cur_mon = old_mon;
qemu_mutex_lock(&hmp.out_lock);
if (qstring_get_length(hmp.outbuf) > 0) {
output = g_strdup(qstring_get_str(hmp.outbuf));
} else {
output = g_strdup("");
}
qemu_mutex_unlock(&hmp.out_lock);
out:
monitor_data_destroy(&hmp);
@ -1045,10 +990,10 @@ CommandInfoList *qmp_query_commands(Error **errp)
EventInfoList *qmp_query_events(Error **errp)
{
EventInfoList *info, *ev_list = NULL;
MonitorEvent e;
QAPIEvent e;
for (e = 0 ; e < QEVENT_MAX ; e++) {
const char *event_name = monitor_event_names[e];
for (e = 0 ; e < QAPI_EVENT_MAX ; e++) {
const char *event_name = QAPIEvent_lookup[e];
assert(event_name != NULL);
info = g_malloc0(sizeof(*info));
info->value = g_malloc0(sizeof(*info->value));
@ -5266,7 +5211,9 @@ static void monitor_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_MUX_IN:
qemu_mutex_lock(&mon->out_lock);
mon->mux_out = 0;
qemu_mutex_unlock(&mon->out_lock);
if (mon->reset_seen) {
readline_restart(mon->rs);
monitor_resume(mon);
@ -5286,7 +5233,9 @@ static void monitor_event(void *opaque, int event)
} else {
mon->suspend_cnt++;
}
qemu_mutex_lock(&mon->out_lock);
mon->mux_out = 1;
qemu_mutex_unlock(&mon->out_lock);
break;
case CHR_EVENT_OPENED:
@ -5351,13 +5300,18 @@ static void monitor_readline_flush(void *opaque)
monitor_flush(opaque);
}
static void __attribute__((constructor)) monitor_lock_init(void)
{
qemu_mutex_init(&monitor_lock);
}
void monitor_init(CharDriverState *chr, int flags)
{
static int is_first_init = 1;
Monitor *mon;
if (is_first_init) {
monitor_protocol_event_init();
monitor_qapi_event_init();
sortcmdlist();
is_first_init = 0;
}
@ -5388,7 +5342,10 @@ void monitor_init(CharDriverState *chr, int flags)
monitor_event, mon);
}
qemu_mutex_lock(&monitor_lock);
QLIST_INSERT_HEAD(&mon_list, mon, entry);
qemu_mutex_unlock(&monitor_lock);
if (!default_mon || (flags & MONITOR_IS_DEFAULT))
default_mon = mon;
}

318
qapi-event.json Normal file
View File

@ -0,0 +1,318 @@
##
# @SHUTDOWN
#
# Emitted when the virtual machine has shutdown, possibly indicating that QEMU
# is about about to exit.
#
# Note: If the command-line option "-no-shutdown" has been specified, qemu will
# not exit, and a STOP event will eventually follow the SHUTDOWN event
#
# Since: 0.12.0
##
{ 'event': 'SHUTDOWN' }
##
# @POWERDOWN
#
# Emitted when the virtual machine is powered down through the power control
# system, such as via ACPI.
#
# Since: 0.12.0
##
{ 'event': 'POWERDOWN' }
##
# @RESET
#
# Emitted when the virtual machine is reset
#
# Since: 0.12.0
##
{ 'event': 'RESET' }
##
# @STOP
#
# Emitted when the virtual machine is stopped
#
# Since: 0.12.0
##
{ 'event': 'STOP' }
##
# @RESUME
#
# Emitted when the virtual machine resumes execution
#
# Since: 0.12.0
##
{ 'event': 'RESUME' }
##
# @SUSPEND
#
# Emitted when guest enters a hardware suspension state, for example, S3 state,
# which is sometimes called standby state
#
# Since: 1.1
##
{ 'event': 'SUSPEND' }
##
# @SUSPEND_DISK
#
# Emitted when guest enters a hardware suspension state with data saved on
# disk, for example, S4 state, which is sometimes called hibernate state
#
# Note: QEMU shuts down (similar to event @SHUTDOWN) when entering this state
#
# Since: 1.2
##
{ 'event': 'SUSPEND_DISK' }
##
# @WAKEUP
#
# Emitted when the guest has woken up from suspend state and is running
#
# Since: 1.1
##
{ 'event': 'WAKEUP' }
##
# @RTC_CHANGE
#
# Emitted when the guest changes the RTC time.
#
# @offset: offset between base RTC clock (as specified by -rtc base), and
# new RTC clock value
#
# Since: 0.13.0
##
{ 'event': 'RTC_CHANGE',
'data': { 'offset': 'int' } }
##
# @WATCHDOG
#
# Emitted when the watchdog device's timer is expired
#
# @action: action that has been taken
#
# Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
# followed respectively by the RESET, SHUTDOWN, or STOP events
#
# Since: 0.13.0
##
{ 'event': 'WATCHDOG',
'data': { 'action': 'WatchdogExpirationAction' } }
##
# @DEVICE_DELETED
#
# Emitted whenever the device removal completion is acknowledged by the guest.
# At this point, it's safe to reuse the specified device ID. Device removal can
# be initiated by the guest or by HMP/QMP commands.
#
# @device: #optional, device name
#
# @path: device path
#
# Since: 1.5
##
{ 'event': 'DEVICE_DELETED',
'data': { '*device': 'str', 'path': 'str' } }
##
# @NIC_RX_FILTER_CHANGED
#
# Emitted once until the 'query-rx-filter' command is executed, the first event
# will always be emitted
#
# @name: #optional, net client name
#
# @path: device path
#
# Since: 1.6
##
{ 'event': 'NIC_RX_FILTER_CHANGED',
'data': { '*name': 'str', 'path': 'str' } }
##
# @VNC_CONNECTED
#
# Emitted when a VNC client establishes a connection
#
# @server: server information
#
# @client: client information
#
# Note: This event is emitted before any authentication takes place, thus
# the authentication ID is not provided
#
# Since: 0.13.0
##
{ 'event': 'VNC_CONNECTED',
'data': { 'server': 'VncServerInfo',
'client': 'VncBasicInfo' } }
##
# @VNC_INITIALIZED
#
# Emitted after authentication takes place (if any) and the VNC session is
# made active
#
# @server: server information
#
# @client: client information
#
# Since: 0.13.0
##
{ 'event': 'VNC_INITIALIZED',
'data': { 'server': 'VncServerInfo',
'client': 'VncClientInfo' } }
##
# @VNC_DISCONNECTED
#
# Emitted when the connection is closed
#
# @server: server information
#
# @client: client information
#
# Since: 0.13.0
##
{ 'event': 'VNC_DISCONNECTED',
'data': { 'server': 'VncServerInfo',
'client': 'VncClientInfo' } }
##
# @SPICE_CONNECTED
#
# Emitted when a SPICE client establishes a connection
#
# @server: server information
#
# @client: client information
#
# Since: 0.14.0
##
{ 'event': 'SPICE_CONNECTED',
'data': { 'server': 'SpiceBasicInfo',
'client': 'SpiceBasicInfo' } }
##
# @SPICE_INITIALIZED
#
# Emitted after initial handshake and authentication takes place (if any)
# and the SPICE channel is up and running
#
# @server: server information
#
# @client: client information
#
# Since: 0.14.0
##
{ 'event': 'SPICE_INITIALIZED',
'data': { 'server': 'SpiceServerInfo',
'client': 'SpiceChannel' } }
##
# @SPICE_DISCONNECTED
#
# Emitted when the SPICE connection is closed
#
# @server: server information
#
# @client: client information
#
# Since: 0.14.0
##
{ 'event': 'SPICE_DISCONNECTED',
'data': { 'server': 'SpiceBasicInfo',
'client': 'SpiceBasicInfo' } }
##
# @SPICE_MIGRATE_COMPLETED
#
# Emitted when SPICE migration has completed
#
# Since: 1.3
##
{ 'event': 'SPICE_MIGRATE_COMPLETED' }
##
# @ACPI_DEVICE_OST
#
# Emitted when guest executes ACPI _OST method.
#
# Since: 2.1
#
# @info: ACPIOSTInfo type as described in qapi-schema.json
##
{ 'event': 'ACPI_DEVICE_OST',
'data': { 'info': 'ACPIOSTInfo' } }
##
# @BALLOON_CHANGE
#
# Emitted when the guest changes the actual BALLOON level. This value is
# equivalent to the @actual field return by the 'query-balloon' command
#
# @actual: actual level of the guest memory balloon in bytes
#
# Since: 1.2
##
{ 'event': 'BALLOON_CHANGE',
'data': { 'actual': 'int' } }
##
# @GUEST_PANICKED
#
# Emitted when guest OS panic is detected
#
# @action: action that has been taken, currently always "pause"
#
# Since: 1.5
##
{ 'event': 'GUEST_PANICKED',
'data': { 'action': 'GuestPanicAction' } }
##
# @QUORUM_FAILURE
#
# Emitted by the Quorum block driver if it fails to establish a quorum
#
# @reference: device name if defined else node name
#
# @sector-num: number of the first sector of the failed read operation
#
# @sector-count: failed read operation sector count
#
# Since: 2.0
##
{ 'event': 'QUORUM_FAILURE',
'data': { 'reference': 'str', 'sector-num': 'int', 'sector-count': 'int' } }
##
# @QUORUM_REPORT_BAD
#
# Emitted to report a corruption of a Quorum file
#
# @error: #optional, error message. Only present on failure. This field
# contains a human-readable error message. There are no semantics other
# than that the block layer reported an error and clients should not
# try to interpret the error string.
#
# @node-name: the graph node name of the block driver state
#
# @sector-num: number of the first sector of the failed read operation
#
# @sector-count: failed read operation sector count
#
# Since: 2.0
##
{ 'event': 'QUORUM_REPORT_BAD',
'data': { '*error': 'str', 'node-name': 'str',
'sector-num': 'int', 'sector-count': 'int' } }

View File

@ -629,23 +629,61 @@
##
{ 'command': 'query-iothreads', 'returns': ['IOThreadInfo'] }
##
# @NetworkAddressFamily
#
# The network address family
#
# @ipv4: IPV4 family
#
# @ipv6: IPV6 family
#
# @unix: unix socket
#
# @unknown: otherwise
#
# Since: 2.1
##
{ 'enum': 'NetworkAddressFamily',
'data': [ 'ipv4', 'ipv6', 'unix', 'unknown' ] }
##
# @VncBasicInfo
#
# The basic information for vnc network connection
#
# @host: IP address
#
# @service: The service name of vnc port. This may depend on the host system's
# service database so symbolic names should not be relied on.
#
# @family: address family
#
# Since: 2.1
##
{ 'type': 'VncBasicInfo',
'data': { 'host': 'str',
'service': 'str',
'family': 'NetworkAddressFamily' } }
##
# @VncServerInfo
#
# The network connection information for server
#
# @auth: #optional, authentication method
#
# Since: 2.1
##
{ 'type': 'VncServerInfo',
'base': 'VncBasicInfo',
'data': { '*auth': 'str' } }
##
# @VncClientInfo:
#
# Information about a connected VNC client.
#
# @host: The host name of the client. QEMU tries to resolve this to a DNS name
# when possible.
#
# @family: 'ipv6' if the client is connected via IPv6 and TCP
# 'ipv4' if the client is connected via IPv4 and TCP
# 'unix' if the client is connected via a unix domain socket
# 'unknown' otherwise
#
# @service: The service name of the client's port. This may depends on the
# host system's service database so symbolic names should not be
# relied on.
#
# @x509_dname: #optional If x509 authentication is in use, the Distinguished
# Name of the client.
#
@ -655,8 +693,8 @@
# Since: 0.14.0
##
{ 'type': 'VncClientInfo',
'data': {'host': 'str', 'family': 'str', 'service': 'str',
'*x509_dname': 'str', '*sasl_username': 'str'} }
'base': 'VncBasicInfo',
'data': { '*x509_dname' : 'str', '*sasl_username': 'str' } }
##
# @VncInfo:
@ -695,7 +733,8 @@
# Since: 0.14.0
##
{ 'type': 'VncInfo',
'data': {'enabled': 'bool', '*host': 'str', '*family': 'str',
'data': {'enabled': 'bool', '*host': 'str',
'*family': 'NetworkAddressFamily',
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
##
@ -709,21 +748,42 @@
##
{ 'command': 'query-vnc', 'returns': 'VncInfo' }
##
# @SpiceBasicInfo
#
# The basic information for SPICE network connection
#
# @host: IP address
#
# @port: port number
#
# @family: address family
#
# Since: 2.1
##
{ 'type': 'SpiceBasicInfo',
'data': { 'host': 'str',
'port': 'str',
'family': 'NetworkAddressFamily' } }
##
# @SpiceServerInfo
#
# Information about a SPICE server
#
# @auth: #optional, authentication method
#
# Since: 2.1
##
{ 'type': 'SpiceServerInfo',
'base': 'SpiceBasicInfo',
'data': { '*auth': 'str' } }
##
# @SpiceChannel
#
# Information about a SPICE client channel.
#
# @host: The host name of the client. QEMU tries to resolve this to a DNS name
# when possible.
#
# @family: 'ipv6' if the client is connected via IPv6 and TCP
# 'ipv4' if the client is connected via IPv4 and TCP
# 'unix' if the client is connected via a unix domain socket
# 'unknown' otherwise
#
# @port: The client's port number.
#
# @connection-id: SPICE connection id number. All channels with the same id
# belong to the same SPICE session.
#
@ -740,8 +800,8 @@
# Since: 0.14.0
##
{ 'type': 'SpiceChannel',
'data': {'host': 'str', 'family': 'str', 'port': 'str',
'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
'base': 'SpiceBasicInfo',
'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
'tls': 'bool'} }
##
@ -3288,3 +3348,55 @@
# Since: 2.1
##
{ 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
##
# @WatchdogExpirationAction
#
# An enumeration of the actions taken when the watchdog device's timer is
# expired
#
# @reset: system resets
#
# @shutdown: system shutdown, note that it is similar to @powerdown, which
# tries to set to system status and notify guest
#
# @poweroff: system poweroff, the emulator program exits
#
# @pause: system pauses, similar to @stop
#
# @debug: system enters debug state
#
# @none: nothing is done
#
# Since: 2.1
##
{ 'enum': 'WatchdogExpirationAction',
'data': [ 'reset', 'shutdown', 'poweroff', 'pause', 'debug', 'none' ] }
##
# @IoOperationType
#
# An enumeration of the I/O operation types
#
# @read: read operation
#
# @write: write operation
#
# Since: 2.1
##
{ 'enum': 'IoOperationType',
'data': [ 'read', 'write' ] }
##
# @GuestPanicAction
#
# An enumeration of the actions taken when guest OS panic is detected
#
# @pause: system pauses
#
# Since: 2.1
##
{ 'enum': 'GuestPanicAction',
'data': [ 'pause' ] }
{ 'include': 'qapi-event.json' }

View File

@ -3,3 +3,4 @@ util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
util-obj-y += string-input-visitor.o string-output-visitor.o
util-obj-y += opts-visitor.o
util-obj-y += qmp-event.o

View File

@ -1410,3 +1410,153 @@
##
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
##
# @BlockErrorAction
#
# An enumeration of action that has been taken when a DISK I/O occurs
#
# @ignore: error has been ignored
#
# @report: error has been reported to the device
#
# @stop: error caused VM to be stopped
#
# Since: 2.1
##
{ 'enum': 'BlockErrorAction',
'data': [ 'ignore', 'report', 'stop' ] }
##
# @BLOCK_IMAGE_CORRUPTED
#
# Emitted when a disk image is being marked corrupt
#
# @device: device name
#
# @msg: informative message for human consumption, such as the kind of
# corruption being detected
#
# @offset: #optional, if the corruption resulted from an image access, this is
# the access offset into the image
#
# @size: #optional, if the corruption resulted from an image access, this is
# the access size
#
# Since: 1.7
##
{ 'event': 'BLOCK_IMAGE_CORRUPTED',
'data': { 'device' : 'str',
'msg' : 'str',
'*offset': 'int',
'*size' : 'int' } }
##
# @BLOCK_IO_ERROR
#
# Emitted when a disk I/O error occurs
#
# @device: device name
#
# @operation: I/O operation
#
# @action: action that has been taken
#
# Note: If action is "stop", a STOP event will eventually follow the
# BLOCK_IO_ERROR event
#
# Since: 0.13.0
##
{ 'event': 'BLOCK_IO_ERROR',
'data': { 'device': 'str', 'operation': 'IoOperationType',
'action': 'BlockErrorAction' } }
##
# @BLOCK_JOB_COMPLETED
#
# Emitted when a block job has completed
#
# @type: job type
#
# @device: device name
#
# @len: maximum progress value
#
# @offset: current progress value. On success this is equal to len.
# On failure this is less than len
#
# @speed: rate limit, bytes per second
#
# @error: #optional, error message. Only present on failure. This field
# contains a human-readable error message. There are no semantics
# other than that streaming has failed and clients should not try to
# interpret the error string
#
# Since: 1.1
##
{ 'event': 'BLOCK_JOB_COMPLETED',
'data': { 'type' : 'BlockJobType',
'device': 'str',
'len' : 'int',
'offset': 'int',
'speed' : 'int',
'*error': 'str' } }
##
# @BLOCK_JOB_CANCELLED
#
# Emitted when a block job has been cancelled
#
# @type: job type
#
# @device: device name
#
# @len: maximum progress value
#
# @offset: current progress value. On success this is equal to len.
# On failure this is less than len
#
# @speed: rate limit, bytes per second
#
# Since: 1.1
##
{ 'event': 'BLOCK_JOB_CANCELLED',
'data': { 'type' : 'BlockJobType',
'device': 'str',
'len' : 'int',
'offset': 'int',
'speed' : 'int' } }
##
# @BLOCK_JOB_ERROR
#
# Emitted when a block job encounters an error
#
# @device: device name
#
# @operation: I/O operation
#
# @action: action that has been taken
#
# Since: 1.3
##
{ 'event': 'BLOCK_JOB_ERROR',
'data': { 'device' : 'str',
'operation': 'IoOperationType',
'action' : 'BlockdevOnError' } }
##
# @BLOCK_JOB_READY
#
# Emitted when a block job is ready to complete
#
# @device: device name
#
# Note: The "ready to complete" status is always reset by a @BLOCK_JOB_ERROR
# event
#
# Since: 1.3
##
{ 'event': 'BLOCK_JOB_READY',
'data': { 'device': 'str' } }

View File

@ -164,3 +164,17 @@
##
{ 'command': 'nbd-server-stop' }
##
# @DEVICE_TRAY_MOVED
#
# Emitted whenever the tray of a removable device is moved by the guest or by
# HMP/QMP commands
#
# @device: device name
#
# @tray-open: true if the tray has been opened or false if it has been closed
#
# Since: 1.1
##
{ 'event': 'DEVICE_TRAY_MOVED',
'data': { 'device': 'str', 'tray-open': 'bool' } }

74
qapi/qmp-event.c Normal file
View File

@ -0,0 +1,74 @@
/*
* QMP Event related
*
* Copyright (c) 2014 Wenchao Xia
*
* Authors:
* Wenchao Xia <wenchaoqemu@gmail.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include <inttypes.h>
#include "qemu-common.h"
#include "qapi/qmp-event.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qjson.h"
#ifdef _WIN32
#include "sysemu/os-win32.h"
#endif
#ifdef CONFIG_POSIX
#include "sysemu/os-posix.h"
#endif
static QMPEventFuncEmit qmp_emit;
void qmp_event_set_func_emit(QMPEventFuncEmit emit)
{
qmp_emit = emit;
}
QMPEventFuncEmit qmp_event_get_func_emit(void)
{
return qmp_emit;
}
static void timestamp_put(QDict *qdict)
{
int err;
QObject *obj;
qemu_timeval tv;
int64_t sec, usec;
err = qemu_gettimeofday(&tv);
if (err < 0) {
/* Put -1 to indicate failure of getting host time */
sec = -1;
usec = -1;
} else {
sec = tv.tv_sec;
usec = tv.tv_usec;
}
obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
"'microseconds': %" PRId64 " }",
sec, usec);
qdict_put_obj(qdict, "timestamp", obj);
}
/*
* Build a QDict, then fill event name and time stamp, caller should free the
* QDict after usage.
*/
QDict *qmp_event_build_dict(const char *event_name)
{
QDict *dict = qdict_new();
qdict_put(dict, "event", qstring_from_str(event_name));
timestamp_put(dict);
return dict;
}

View File

@ -91,6 +91,12 @@
static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
QTAILQ_HEAD_INITIALIZER(chardevs);
CharDriverState *qemu_chr_alloc(void)
{
CharDriverState *chr = g_malloc0(sizeof(CharDriverState));
return chr;
}
void qemu_chr_be_event(CharDriverState *s, int event)
{
/* Keep track if the char device is open */
@ -115,7 +121,12 @@ void qemu_chr_be_generic_open(CharDriverState *s)
int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
{
return s->chr_write(s, buf, len);
int ret;
qemu_mutex_lock(&s->chr_write_lock);
ret = s->chr_write(s, buf, len);
qemu_mutex_unlock(&s->chr_write_lock);
return ret;
}
int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
@ -123,6 +134,7 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
int offset = 0;
int res;
qemu_mutex_lock(&s->chr_write_lock);
while (offset < len) {
do {
res = s->chr_write(s, buf + offset, len - offset);
@ -131,17 +143,17 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
}
} while (res == -1 && errno == EAGAIN);
if (res == 0) {
if (res <= 0) {
break;
}
if (res < 0) {
return res;
}
offset += res;
}
qemu_mutex_unlock(&s->chr_write_lock);
if (res < 0) {
return res;
}
return offset;
}
@ -282,7 +294,7 @@ static CharDriverState *qemu_chr_open_null(void)
{
CharDriverState *chr;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
chr->chr_write = null_chr_write;
chr->explicit_be_open = true;
return chr;
@ -309,17 +321,20 @@ typedef struct {
int prod[MAX_MUX];
int cons[MAX_MUX];
int timestamps;
/* Protected by the CharDriverState chr_write_lock. */
int linestart;
int64_t timestamps_start;
} MuxDriver;
/* Called with chr_write_lock held. */
static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
MuxDriver *d = chr->opaque;
int ret;
if (!d->timestamps) {
ret = d->drv->chr_write(d->drv, buf, len);
ret = qemu_chr_fe_write(d->drv, buf, len);
} else {
int i;
@ -341,10 +356,10 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
(secs / 60) % 60,
secs % 60,
(int)(ti % 1000));
d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
qemu_chr_fe_write(d->drv, (uint8_t *)buf1, strlen(buf1));
d->linestart = 0;
}
ret += d->drv->chr_write(d->drv, buf+i, 1);
ret += qemu_chr_fe_write(d->drv, buf+i, 1);
if (buf[i] == '\n') {
d->linestart = 1;
}
@ -379,13 +394,13 @@ static void mux_print_help(CharDriverState *chr)
"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
term_escape_char);
}
chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
qemu_chr_fe_write(chr, (uint8_t *)cbuf, strlen(cbuf));
for (i = 0; mux_help[i] != NULL; i++) {
for (j=0; mux_help[i][j] != '\0'; j++) {
if (mux_help[i][j] == '%')
chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
qemu_chr_fe_write(chr, (uint8_t *)ebuf, strlen(ebuf));
else
chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
qemu_chr_fe_write(chr, (uint8_t *)&mux_help[i][j], 1);
}
}
}
@ -410,7 +425,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
case 'x':
{
const char *term = "QEMU: Terminated\n\r";
chr->chr_write(chr,(uint8_t *)term,strlen(term));
qemu_chr_fe_write(chr, (uint8_t *)term, strlen(term));
exit(0);
break;
}
@ -570,7 +585,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
CharDriverState *chr;
MuxDriver *d;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
d = g_malloc0(sizeof(MuxDriver));
chr->opaque = d;
@ -859,6 +874,7 @@ typedef struct FDCharDriver {
QTAILQ_ENTRY(FDCharDriver) node;
} FDCharDriver;
/* Called with chr_write_lock held. */
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
FDCharDriver *s = chr->opaque;
@ -945,7 +961,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
CharDriverState *chr;
FDCharDriver *s;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(FDCharDriver));
s->fd_in = io_channel_from_fd(fd_in);
s->fd_out = io_channel_from_fd(fd_out);
@ -1058,12 +1074,14 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
typedef struct {
GIOChannel *fd;
int connected;
int read_bytes;
/* Protected by the CharDriverState chr_write_lock. */
int connected;
guint timer_tag;
} PtyCharDriver;
static void pty_chr_update_read_handler(CharDriverState *chr);
static void pty_chr_update_read_handler_locked(CharDriverState *chr);
static void pty_chr_state(CharDriverState *chr, int connected);
static gboolean pty_chr_timer(gpointer opaque)
@ -1071,14 +1089,17 @@ static gboolean pty_chr_timer(gpointer opaque)
struct CharDriverState *chr = opaque;
PtyCharDriver *s = chr->opaque;
qemu_mutex_lock(&chr->chr_write_lock);
s->timer_tag = 0;
if (!s->connected) {
/* Next poll ... */
pty_chr_update_read_handler(chr);
pty_chr_update_read_handler_locked(chr);
}
qemu_mutex_unlock(&chr->chr_write_lock);
return FALSE;
}
/* Called with chr_write_lock held. */
static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
{
PtyCharDriver *s = chr->opaque;
@ -1095,13 +1116,38 @@ static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
}
}
/* Called with chr_write_lock held. */
static void pty_chr_update_read_handler_locked(CharDriverState *chr)
{
PtyCharDriver *s = chr->opaque;
GPollFD pfd;
pfd.fd = g_io_channel_unix_get_fd(s->fd);
pfd.events = G_IO_OUT;
pfd.revents = 0;
g_poll(&pfd, 1, 0);
if (pfd.revents & G_IO_HUP) {
pty_chr_state(chr, 0);
} else {
pty_chr_state(chr, 1);
}
}
static void pty_chr_update_read_handler(CharDriverState *chr)
{
qemu_mutex_lock(&chr->chr_write_lock);
pty_chr_update_read_handler_locked(chr);
qemu_mutex_unlock(&chr->chr_write_lock);
}
/* Called with chr_write_lock held. */
static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
PtyCharDriver *s = chr->opaque;
if (!s->connected) {
/* guest sends data, check for (re-)connect */
pty_chr_update_read_handler(chr);
pty_chr_update_read_handler_locked(chr);
return 0;
}
return io_channel_send(s->fd, buf, len);
@ -1147,22 +1193,7 @@ static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
return TRUE;
}
static void pty_chr_update_read_handler(CharDriverState *chr)
{
PtyCharDriver *s = chr->opaque;
GPollFD pfd;
pfd.fd = g_io_channel_unix_get_fd(s->fd);
pfd.events = G_IO_OUT;
pfd.revents = 0;
g_poll(&pfd, 1, 0);
if (pfd.revents & G_IO_HUP) {
pty_chr_state(chr, 0);
} else {
pty_chr_state(chr, 1);
}
}
/* Called with chr_write_lock held. */
static void pty_chr_state(CharDriverState *chr, int connected)
{
PtyCharDriver *s = chr->opaque;
@ -1222,7 +1253,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
close(slave_fd);
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
chr->filename = g_strdup_printf("pty:%s", pty_name);
ret->pty = g_strdup(pty_name);
@ -1584,7 +1615,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd)
drv->fd = fd;
drv->mode = IEEE1284_MODE_COMPAT;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
chr->chr_write = null_chr_write;
chr->chr_ioctl = pp_ioctl;
chr->chr_close = pp_close;
@ -1639,7 +1670,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd)
{
CharDriverState *chr;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
chr->opaque = (void *)(intptr_t)fd;
chr->chr_write = null_chr_write;
chr->chr_ioctl = pp_ioctl;
@ -1653,9 +1684,12 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd)
typedef struct {
int max_size;
HANDLE hcom, hrecv, hsend;
OVERLAPPED orecv, osend;
OVERLAPPED orecv;
BOOL fpipe;
DWORD len;
/* Protected by the CharDriverState chr_write_lock. */
OVERLAPPED osend;
} WinCharState;
typedef struct {
@ -1765,6 +1799,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename)
return -1;
}
/* Called with chr_write_lock held. */
static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
{
WinCharState *s = chr->opaque;
@ -1863,7 +1898,7 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename)
CharDriverState *chr;
WinCharState *s;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(WinCharState));
chr->opaque = s;
chr->chr_write = win_chr_write;
@ -1962,7 +1997,7 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts)
CharDriverState *chr;
WinCharState *s;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(WinCharState));
chr->opaque = s;
chr->chr_write = win_chr_write;
@ -1981,7 +2016,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
CharDriverState *chr;
WinCharState *s;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(WinCharState));
s->hcom = fd_out;
chr->opaque = s;
@ -2137,7 +2172,7 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
DWORD dwMode;
int is_console = 0;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
stdio = g_malloc0(sizeof(WinStdioCharState));
stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
@ -2207,6 +2242,7 @@ typedef struct {
int max_size;
} NetCharDriver;
/* Called with chr_write_lock held. */
static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
NetCharDriver *s = chr->opaque;
@ -2299,7 +2335,7 @@ static CharDriverState *qemu_chr_open_udp_fd(int fd)
CharDriverState *chr = NULL;
NetCharDriver *s = NULL;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(NetCharDriver));
s->fd = fd;
@ -2397,6 +2433,7 @@ static int unix_send_msgfds(CharDriverState *chr, const uint8_t *buf, int len)
}
#endif
/* Called with chr_write_lock held. */
static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
TCPCharDriver *s = chr->opaque;
@ -2857,7 +2894,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
return NULL;
}
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(TCPCharDriver));
s->connected = 0;
@ -3001,6 +3038,7 @@ static size_t ringbuf_count(const CharDriverState *chr)
return d->prod - d->cons;
}
/* Called with chr_write_lock held. */
static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
RingBufCharDriver *d = chr->opaque;
@ -3025,9 +3063,11 @@ static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
RingBufCharDriver *d = chr->opaque;
int i;
qemu_mutex_lock(&chr->chr_write_lock);
for (i = 0; i < len && d->cons != d->prod; i++) {
buf[i] = d->cbuf[d->cons++ & (d->size - 1)];
}
qemu_mutex_unlock(&chr->chr_write_lock);
return i;
}
@ -3047,7 +3087,7 @@ static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts,
CharDriverState *chr;
RingBufCharDriver *d;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
d = g_malloc(sizeof(*d));
d->size = opts->has_size ? opts->size : 65536;

View File

@ -138,8 +138,8 @@ static const uint8_t json_lexer[][256] = {
['n'] = IN_SQ_STRING,
['r'] = IN_SQ_STRING,
['t'] = IN_SQ_STRING,
['/'] = IN_DQ_STRING,
['\\'] = IN_DQ_STRING,
['/'] = IN_SQ_STRING,
['\\'] = IN_SQ_STRING,
['\''] = IN_SQ_STRING,
['\"'] = IN_SQ_STRING,
['u'] = IN_SQ_UCODE0,

View File

@ -29,9 +29,7 @@ def type_visitor(name):
def generate_command_decl(name, args, ret_type):
arglist=""
for argname, argtype, optional, structured in parse_args(args):
argtype = c_type(argtype)
if argtype == "char *":
argtype = "const char *"
argtype = c_type(argtype, is_param=True)
if optional:
arglist += "bool has_%s, " % c_var(argname)
arglist += "%s %s, " % (argtype, c_var(argname))
@ -104,7 +102,7 @@ def gen_visitor_input_vars_decl(args):
bool has_%(argname)s = false;
''',
argname=c_var(argname))
if c_type(argtype).endswith("*"):
if is_c_ptr(argtype):
ret += mcgen('''
%(argtype)s %(argname)s = NULL;
''',
@ -229,7 +227,7 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
''')
if ret_type:
if c_type(ret_type).endswith("*"):
if is_c_ptr(ret_type):
retval = " %s retval = NULL;" % c_type(ret_type)
else:
retval = " %s retval;" % c_type(ret_type)

369
scripts/qapi-event.py Normal file
View File

@ -0,0 +1,369 @@
#
# QAPI event generator
#
# Copyright (c) 2014 Wenchao Xia
#
# Authors:
# Wenchao Xia <wenchaoqemu@gmail.com>
#
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
from ordereddict import OrderedDict
from qapi import *
import sys
import os
import getopt
import errno
def _generate_event_api_name(event_name, params):
api_name = "void qapi_event_send_%s(" % c_fun(event_name).lower();
l = len(api_name)
if params:
for argname, argentry, optional, structured in parse_args(params):
if optional:
api_name += "bool has_%s,\n" % c_var(argname)
api_name += "".ljust(l)
if argentry == "str":
api_name += "const "
api_name += "%s %s,\n" % (c_type(argentry), c_var(argname))
api_name += "".ljust(l)
api_name += "Error **errp)"
return api_name;
# Following are the core functions that generate C APIs to emit event.
def generate_event_declaration(api_name):
return mcgen('''
%(api_name)s;
''',
api_name = api_name)
def generate_event_implement(api_name, event_name, params):
# step 1: declare any variables
ret = mcgen("""
%(api_name)s
{
QDict *qmp;
Error *local_err = NULL;
QMPEventFuncEmit emit;
""",
api_name = api_name)
if params:
ret += mcgen("""
QmpOutputVisitor *qov;
Visitor *v;
QObject *obj;
""")
# step 2: check emit function, create a dict
ret += mcgen("""
emit = qmp_event_get_func_emit();
if (!emit) {
return;
}
qmp = qmp_event_build_dict("%(event_name)s");
""",
event_name = event_name)
# step 3: visit the params if params != None
if params:
ret += mcgen("""
qov = qmp_output_visitor_new();
g_assert(qov);
v = qmp_output_get_visitor(qov);
g_assert(v);
/* Fake visit, as if all members are under a structure */
visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
if (local_err) {
goto clean;
}
""",
event_name = event_name)
for argname, argentry, optional, structured in parse_args(params):
if optional:
ret += mcgen("""
if (has_%(var)s) {
""",
var = c_var(argname))
push_indent()
if argentry == "str":
var_type = "(char **)"
else:
var_type = ""
ret += mcgen("""
visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
if (local_err) {
goto clean;
}
""",
var_type = var_type,
var = c_var(argname),
type = type_name(argentry),
name = argname)
if optional:
pop_indent()
ret += mcgen("""
}
""")
ret += mcgen("""
visit_end_struct(v, &local_err);
if (local_err) {
goto clean;
}
obj = qmp_output_get_qobject(qov);
g_assert(obj != NULL);
qdict_put_obj(qmp, "data", obj);
""")
# step 4: call qmp event api
ret += mcgen("""
emit(%(event_enum_value)s, qmp, &local_err);
""",
event_enum_value = event_enum_value)
# step 5: clean up
if params:
ret += mcgen("""
clean:
qmp_output_visitor_cleanup(qov);
""")
ret += mcgen("""
error_propagate(errp, local_err);
QDECREF(qmp);
}
""")
return ret
# Following are the functions that generate an enum type for all defined
# events, similar to qapi-types.py. Here we already have enum name and
# values which were generated before and recorded in event_enum_*. It also
# works around the issue that "import qapi-types" can't work.
def generate_event_enum_decl(event_enum_name, event_enum_values):
lookup_decl = mcgen('''
extern const char *%(event_enum_name)s_lookup[];
''',
event_enum_name = event_enum_name)
enum_decl = mcgen('''
typedef enum %(event_enum_name)s
{
''',
event_enum_name = event_enum_name)
# append automatically generated _MAX value
enum_max_value = generate_enum_full_value(event_enum_name, "MAX")
enum_values = event_enum_values + [ enum_max_value ]
i = 0
for value in enum_values:
enum_decl += mcgen('''
%(value)s = %(i)d,
''',
value = value,
i = i)
i += 1
enum_decl += mcgen('''
} %(event_enum_name)s;
''',
event_enum_name = event_enum_name)
return lookup_decl + enum_decl
def generate_event_enum_lookup(event_enum_name, event_enum_strings):
ret = mcgen('''
const char *%(event_enum_name)s_lookup[] = {
''',
event_enum_name = event_enum_name)
i = 0
for string in event_enum_strings:
ret += mcgen('''
"%(string)s",
''',
string = string)
ret += mcgen('''
NULL,
};
''')
return ret
# Start the real job
try:
opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
["source", "header", "builtins", "prefix=",
"input-file=", "output-dir="])
except getopt.GetoptError, err:
print str(err)
sys.exit(1)
input_file = ""
output_dir = ""
prefix = ""
c_file = 'qapi-event.c'
h_file = 'qapi-event.h'
do_c = False
do_h = False
do_builtins = False
for o, a in opts:
if o in ("-p", "--prefix"):
prefix = a
elif o in ("-i", "--input-file"):
input_file = a
elif o in ("-o", "--output-dir"):
output_dir = a + "/"
elif o in ("-c", "--source"):
do_c = True
elif o in ("-h", "--header"):
do_h = True
elif o in ("-b", "--builtins"):
do_builtins = True
if not do_c and not do_h:
do_c = True
do_h = True
c_file = output_dir + prefix + c_file
h_file = output_dir + prefix + h_file
try:
os.makedirs(output_dir)
except os.error, e:
if e.errno != errno.EEXIST:
raise
def maybe_open(really, name, opt):
if really:
return open(name, opt)
else:
import StringIO
return StringIO.StringIO()
fdef = maybe_open(do_c, c_file, 'w')
fdecl = maybe_open(do_h, h_file, 'w')
fdef.write(mcgen('''
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
* schema-defined QAPI event functions
*
* Copyright (c) 2014 Wenchao Xia
*
* Authors:
* Wenchao Xia <wenchaoqemu@gmail.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "%(header)s"
#include "%(prefix)sqapi-visit.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/qmp-event.h"
''',
prefix=prefix, header=basename(h_file)))
fdecl.write(mcgen('''
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
* schema-defined QAPI event functions
*
* Copyright (c) 2014 Wenchao Xia
*
* Authors:
* Wenchao Xia <wenchaoqemu@gmail.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#ifndef %(guard)s
#define %(guard)s
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "%(prefix)sqapi-types.h"
''',
prefix=prefix, guard=guardname(h_file)))
exprs = parse_schema(input_file)
event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
event_enum_values = []
event_enum_strings = []
for expr in exprs:
if expr.has_key('event'):
event_name = expr['event']
params = expr.get('data')
if params and len(params) == 0:
params = None
api_name = _generate_event_api_name(event_name, params)
ret = generate_event_declaration(api_name)
fdecl.write(ret)
# We need an enum value per event
event_enum_value = generate_enum_full_value(event_enum_name,
event_name)
ret = generate_event_implement(api_name, event_name, params)
fdef.write(ret)
# Record it, and generate enum later
event_enum_values.append(event_enum_value)
event_enum_strings.append(event_name)
ret = generate_event_enum_decl(event_enum_name, event_enum_values)
fdecl.write(ret)
ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
fdef.write(ret)
fdecl.write('''
#endif
''')
fdecl.flush()
fdecl.close()
fdef.flush()
fdef.close()

View File

@ -77,7 +77,7 @@ static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj
ret += mcgen('''
static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error **errp)
static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
{
Error *err = NULL;
''',
@ -186,7 +186,7 @@ def generate_visit_struct(expr):
ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
{
''',
name=name)
@ -201,7 +201,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
def generate_visit_list(name, members):
return mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
{
Error *err = NULL;
GenericList *i, **prev;
@ -230,7 +230,7 @@ out:
def generate_visit_enum(name, members):
return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
{
visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
}
@ -240,7 +240,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e
def generate_visit_anon_union(name, members):
ret = mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
@ -327,7 +327,7 @@ def generate_visit_union(expr):
ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
@ -399,13 +399,13 @@ def generate_declaration(name, members, genlist=True, builtin_type=False):
if not builtin_type:
ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
''',
name=name)
if genlist:
ret += mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
''',
name=name)
@ -415,7 +415,7 @@ def generate_enum_declaration(name, members, genlist=True):
ret = ""
if genlist:
ret += mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
''',
name=name)
@ -424,7 +424,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name,
def generate_decl_enum(name, members, genlist=True):
return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
''',
name=name)

View File

@ -248,6 +248,16 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type)
def check_event(expr, expr_info):
params = expr.get('data')
if params:
for argname, argentry, optional, structured in parse_args(params):
if structured:
raise QAPIExprError(expr_info,
"Nested structure define in event is not "
"supported now, event '%s', argname '%s'"
% (expr['event'], argname))
def check_union(expr, expr_info):
name = expr['union']
base = expr.get('base')
@ -311,6 +321,8 @@ def check_exprs(schema):
expr = expr_elem['expr']
if expr.has_key('union'):
check_union(expr, expr_elem['info'])
if expr.has_key('event'):
check_event(expr, expr_elem['info'])
def parse_schema(input_file):
try:
@ -470,9 +482,17 @@ def find_enum(name):
def is_enum(name):
return find_enum(name) != None
def c_type(name):
eatspace = '\033EATSPACE.'
# A special suffix is added in c_type() for pointer types, and it's
# stripped in mcgen(). So please notice this when you check the return
# value of c_type() outside mcgen().
def c_type(name, is_param=False):
if name == 'str':
return 'char *'
if is_param:
return 'const char *' + eatspace
return 'char *' + eatspace
elif name == 'int':
return 'int64_t'
elif (name == 'int8' or name == 'int16' or name == 'int32' or
@ -486,15 +506,19 @@ def c_type(name):
elif name == 'number':
return 'double'
elif type(name) == list:
return '%s *' % c_list_type(name[0])
return '%s *%s' % (c_list_type(name[0]), eatspace)
elif is_enum(name):
return name
elif name == None or len(name) == 0:
return 'void'
elif name == name.upper():
return '%sEvent *' % camel_case(name)
return '%sEvent *%s' % (camel_case(name), eatspace)
else:
return '%s *' % name
return '%s *%s' % (name, eatspace)
def is_c_ptr(name):
suffix = "*" + eatspace
return c_type(name).endswith(suffix)
def genindent(count):
ret = ""
@ -519,7 +543,8 @@ def cgen(code, **kwds):
return '\n'.join(lines) % kwds + '\n'
def mcgen(code, **kwds):
return cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
return re.sub(re.escape(eatspace) + ' *', '', raw)
def basename(filename):
return filename.split("/")[-1]

View File

@ -268,7 +268,7 @@ static CharDriverState *chr_open(const char *subtype,
CharDriverState *chr;
SpiceCharDriver *s;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
s = g_malloc0(sizeof(SpiceCharDriver));
s->chr = chr;
s->active = false;

View File

@ -20,7 +20,6 @@ stub-obj-y += machine-init-done.o
stub-obj-y += migr-blocker.o
stub-obj-y += mon-is-qmp.o
stub-obj-y += mon-printf.o
stub-obj-y += mon-protocol-event.o
stub-obj-y += mon-set-error.o
stub-obj-y += monitor-init.o
stub-obj-y += notify-event.o

View File

@ -1,6 +0,0 @@
#include "qemu-common.h"
#include "monitor/monitor.h"
void monitor_protocol_event(MonitorEvent event, QObject *data)
{
}

View File

@ -39,6 +39,7 @@
#include "monitor/monitor.h"
#include "exec/gdbstub.h"
#include "trace.h"
#include "qapi-event.h"
/* #define DEBUG_KVM */
@ -1029,12 +1030,8 @@ static bool is_special_wait_psw(CPUState *cs)
static void guest_panicked(void)
{
QObject *data;
data = qobject_from_jsonf("{ 'action': %s }", "pause");
monitor_protocol_event(QEVENT_GUEST_PANICKED, data);
qobject_decref(data);
qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE,
&error_abort);
vm_stop(RUN_STATE_GUEST_PANICKED);
}

View File

@ -27,6 +27,8 @@ check-unit-y += tests/test-string-input-visitor$(EXESUF)
gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c
check-unit-y += tests/test-string-output-visitor$(EXESUF)
gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c
check-unit-y += tests/test-qmp-event$(EXESUF)
gcov-files-test-qmp-event-y += qapi/qmp-event.c
check-unit-y += tests/test-opts-visitor$(EXESUF)
gcov-files-test-opts-visitor-y = qapi/opts-visitor.c
check-unit-y += tests/test-coroutine$(EXESUF)
@ -199,9 +201,10 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
include-simple.json include-relpath.json include-format-err.json \
include-non-file.json include-no-file.json include-before-err.json \
include-nested-err.json include-self-cycle.json include-cycle.json \
include-repetition.json)
include-repetition.json event-nest-struct.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \
tests/test-qmp-commands.h tests/test-qapi-event.h
test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \
@ -210,9 +213,10 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
tests/test-qmp-commands.o tests/test-visitor-serialization.o \
tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \
tests/test-opts-visitor.o
tests/test-opts-visitor.o tests/test-qmp-event.o
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
tests/test-qapi-event.o
$(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
@ -264,9 +268,15 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-com
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
$(gen-out-type) -o tests -p "test-" -i $<, \
" GEN $@")
tests/test-qapi-event.c tests/test-qapi-event.h :\
$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
$(gen-out-type) -o tests -p "test-" -i $<, \
" GEN $@")
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a

View File

@ -45,6 +45,13 @@ static void escaped_string(void)
{ "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
{ "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
{ "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
{ "'\\b'", "\b", .skip = 1 },
{ "'\\f'", "\f", .skip = 1 },
{ "'\\n'", "\n", .skip = 1 },
{ "'\\r'", "\r", .skip = 1 },
{ "'\\t'", "\t", .skip = 1 },
{ "'\\/'", "/", .skip = 1 },
{ "'\\\\'", "\\", .skip = 1 },
{}
};

View File

@ -0,0 +1 @@
tests/qapi-schema/event-nest-struct.json:1: Nested structure define in event is not supported now, event 'EVENT_A', argname 'a'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'event': 'EVENT_A',
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }

View File

View File

@ -89,3 +89,15 @@
'*u16' : [ 'uint16' ],
'*i64x': 'int' ,
'*u64x': 'uint64' } }
# testing event
{ 'type': 'EventStructOne',
'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } }
{ 'event': 'EVENT_A' }
{ 'event': 'EVENT_B',
'data': { } }
{ 'event': 'EVENT_C',
'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } }
{ 'event': 'EVENT_D',
'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } }

View File

@ -15,7 +15,12 @@
OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]),
OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]),
OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]),
OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])]
OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
OrderedDict([('type', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]),
OrderedDict([('event', 'EVENT_A')]),
OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]),
OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]),
OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))])]
[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
{'enum_name': 'UserDefUnionKind', 'enum_values': None},
{'enum_name': 'UserDefAnonUnionKind', 'enum_values': None},
@ -28,4 +33,5 @@
OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])]
OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
OrderedDict([('type', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))])]

265
tests/test-qmp-event.c Normal file
View File

@ -0,0 +1,265 @@
/*
* qapi event unit-tests.
*
* Copyright (c) 2014 Wenchao Xia
*
* Authors:
* Wenchao Xia <wenchaoqemu@gmail.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include <glib.h>
#include <stdarg.h>
#include "qemu-common.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "test-qapi-event.h"
#include "qapi/qmp/types.h"
#include "qapi/qmp/qint.h"
#include "qapi/qmp/qobject.h"
#include "qapi/qmp-event.h"
typedef struct TestEventData {
QDict *expect;
} TestEventData;
typedef struct QDictCmpData {
QDict *expect;
bool result;
} QDictCmpData;
TestEventData *test_event_data;
static CompatGMutex test_event_lock;
/* Only compares bool, int, string */
static
void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque)
{
QObject *obj2;
QDictCmpData d_new, *d = opaque;
if (!d->result) {
return;
}
obj2 = qdict_get(d->expect, key);
if (!obj2) {
d->result = false;
return;
}
if (qobject_type(obj1) != qobject_type(obj2)) {
d->result = false;
return;
}
switch (qobject_type(obj1)) {
case QTYPE_QBOOL:
d->result = (qbool_get_int(qobject_to_qbool(obj1)) ==
qbool_get_int(qobject_to_qbool(obj2)));
return;
case QTYPE_QINT:
d->result = (qint_get_int(qobject_to_qint(obj1)) ==
qint_get_int(qobject_to_qint(obj2)));
return;
case QTYPE_QSTRING:
d->result = g_strcmp0(qstring_get_str(qobject_to_qstring(obj1)),
qstring_get_str(qobject_to_qstring(obj2))) == 0;
return;
case QTYPE_QDICT:
d_new.expect = qobject_to_qdict(obj2);
d_new.result = true;
qdict_iter(qobject_to_qdict(obj1), qdict_cmp_do_simple, &d_new);
d->result = d_new.result;
return;
default:
abort();
}
}
static bool qdict_cmp_simple(QDict *a, QDict *b)
{
QDictCmpData d;
d.expect = b;
d.result = true;
qdict_iter(a, qdict_cmp_do_simple, &d);
return d.result;
}
/* This function is hooked as final emit function, which can verify the
correctness. */
static void event_test_emit(TEST_QAPIEvent event, QDict *d, Error **errp)
{
QObject *obj;
QDict *t;
int64_t s, ms;
/* Verify that we have timestamp, then remove it to compare other fields */
obj = qdict_get(d, "timestamp");
g_assert(obj);
t = qobject_to_qdict(obj);
g_assert(t);
obj = qdict_get(t, "seconds");
g_assert(obj && qobject_type(obj) == QTYPE_QINT);
s = qint_get_int(qobject_to_qint(obj));
obj = qdict_get(t, "microseconds");
g_assert(obj && qobject_type(obj) == QTYPE_QINT);
ms = qint_get_int(qobject_to_qint(obj));
if (s == -1) {
g_assert(ms == -1);
} else {
g_assert(ms >= 0 && ms <= 999999);
}
g_assert(qdict_size(t) == 2);
qdict_del(d, "timestamp");
g_assert(qdict_cmp_simple(d, test_event_data->expect));
}
static void event_prepare(TestEventData *data,
const void *unused)
{
/* Global variable test_event_data was used to pass the expectation, so
test cases can't be executed at same time. */
g_mutex_lock(&test_event_lock);
data->expect = qdict_new();
test_event_data = data;
}
static void event_teardown(TestEventData *data,
const void *unused)
{
QDECREF(data->expect);
test_event_data = NULL;
g_mutex_unlock(&test_event_lock);
}
static void event_test_add(const char *testpath,
void (*test_func)(TestEventData *data,
const void *user_data))
{
g_test_add(testpath, TestEventData, NULL, event_prepare, test_func,
event_teardown);
}
/* Test cases */
static void test_event_a(TestEventData *data,
const void *unused)
{
QDict *d;
d = data->expect;
qdict_put(d, "event", qstring_from_str("EVENT_A"));
qapi_event_send_event_a(&error_abort);
}
static void test_event_b(TestEventData *data,
const void *unused)
{
QDict *d;
d = data->expect;
qdict_put(d, "event", qstring_from_str("EVENT_B"));
qapi_event_send_event_b(&error_abort);
}
static void test_event_c(TestEventData *data,
const void *unused)
{
QDict *d, *d_data, *d_b;
UserDefOne b;
UserDefZero z;
z.integer = 2;
b.base = &z;
b.string = g_strdup("test1");
b.has_enum1 = false;
d_b = qdict_new();
qdict_put(d_b, "integer", qint_from_int(2));
qdict_put(d_b, "string", qstring_from_str("test1"));
d_data = qdict_new();
qdict_put(d_data, "a", qint_from_int(1));
qdict_put(d_data, "b", d_b);
qdict_put(d_data, "c", qstring_from_str("test2"));
d = data->expect;
qdict_put(d, "event", qstring_from_str("EVENT_C"));
qdict_put(d, "data", d_data);
qapi_event_send_event_c(true, 1, true, &b, "test2", &error_abort);
g_free(b.string);
}
/* Complex type */
static void test_event_d(TestEventData *data,
const void *unused)
{
UserDefOne struct1;
EventStructOne a;
UserDefZero z;
QDict *d, *d_data, *d_a, *d_struct1;
z.integer = 2;
struct1.base = &z;
struct1.string = g_strdup("test1");
struct1.has_enum1 = true;
struct1.enum1 = ENUM_ONE_VALUE1;
a.struct1 = &struct1;
a.string = g_strdup("test2");
a.has_enum2 = true;
a.enum2 = ENUM_ONE_VALUE2;
d_struct1 = qdict_new();
qdict_put(d_struct1, "integer", qint_from_int(2));
qdict_put(d_struct1, "string", qstring_from_str("test1"));
qdict_put(d_struct1, "enum1", qstring_from_str("value1"));
d_a = qdict_new();
qdict_put(d_a, "struct1", d_struct1);
qdict_put(d_a, "string", qstring_from_str("test2"));
qdict_put(d_a, "enum2", qstring_from_str("value2"));
d_data = qdict_new();
qdict_put(d_data, "a", d_a);
qdict_put(d_data, "b", qstring_from_str("test3"));
qdict_put(d_data, "enum3", qstring_from_str("value3"));
d = data->expect;
qdict_put(d, "event", qstring_from_str("EVENT_D"));
qdict_put(d, "data", d_data);
qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3,
&error_abort);
g_free(struct1.string);
g_free(a.string);
}
int main(int argc, char **argv)
{
qmp_event_set_func_emit(event_test_emit);
g_test_init(&argc, &argv, NULL);
event_test_add("/event/event_a", test_event_a);
event_test_add("/event/event_b", test_event_b);
event_test_add("/event/event_c", test_event_c);
event_test_add("/event/event_d", test_event_d);
g_test_run();
return 0;
}

View File

@ -1821,7 +1821,7 @@ static CharDriverState *text_console_init(ChardevVC *vc)
unsigned width = 0;
unsigned height = 0;
chr = g_malloc0(sizeof(CharDriverState));
chr = qemu_chr_alloc();
if (vc->has_width) {
width = vc->width;

View File

@ -35,9 +35,9 @@
#include "qapi/qmp/qjson.h"
#include "qemu/notify.h"
#include "migration/migration.h"
#include "monitor/monitor.h"
#include "hw/hw.h"
#include "ui/spice-display.h"
#include "qapi-event.h"
/* core bits */
@ -174,39 +174,34 @@ static void channel_list_del(SpiceChannelEventInfo *info)
}
}
static void add_addr_info(QDict *dict, struct sockaddr *addr, int len)
static void add_addr_info(SpiceBasicInfo *info, struct sockaddr *addr, int len)
{
char host[NI_MAXHOST], port[NI_MAXSERV];
const char *family;
getnameinfo(addr, len, host, sizeof(host), port, sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV);
family = inet_strfamily(addr->sa_family);
qdict_put(dict, "host", qstring_from_str(host));
qdict_put(dict, "port", qstring_from_str(port));
qdict_put(dict, "family", qstring_from_str(family));
info->host = g_strdup(host);
info->port = g_strdup(port);
info->family = inet_netfamily(addr->sa_family);
}
static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
static void add_channel_info(SpiceChannel *sc, SpiceChannelEventInfo *info)
{
int tls = info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
qdict_put(dict, "connection-id", qint_from_int(info->connection_id));
qdict_put(dict, "channel-type", qint_from_int(info->type));
qdict_put(dict, "channel-id", qint_from_int(info->id));
qdict_put(dict, "tls", qbool_from_int(tls));
sc->connection_id = info->connection_id;
sc->channel_type = info->type;
sc->channel_id = info->id;
sc->tls = !!tls;
}
static void channel_event(int event, SpiceChannelEventInfo *info)
{
static const int qevent[] = {
[ SPICE_CHANNEL_EVENT_CONNECTED ] = QEVENT_SPICE_CONNECTED,
[ SPICE_CHANNEL_EVENT_INITIALIZED ] = QEVENT_SPICE_INITIALIZED,
[ SPICE_CHANNEL_EVENT_DISCONNECTED ] = QEVENT_SPICE_DISCONNECTED,
};
QDict *server, *client;
QObject *data;
SpiceServerInfo *server = g_malloc0(sizeof(*server));
SpiceChannel *client = g_malloc0(sizeof(*client));
server->base = g_malloc0(sizeof(*server->base));
client->base = g_malloc0(sizeof(*client->base));
/*
* Spice server might have called us from spice worker thread
@ -222,36 +217,43 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
qemu_mutex_lock_iothread();
}
client = qdict_new();
server = qdict_new();
if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
add_addr_info(client, (struct sockaddr *)&info->paddr_ext,
add_addr_info(client->base, (struct sockaddr *)&info->paddr_ext,
info->plen_ext);
add_addr_info(server, (struct sockaddr *)&info->laddr_ext,
add_addr_info(server->base, (struct sockaddr *)&info->laddr_ext,
info->llen_ext);
} else {
error_report("spice: %s, extended address is expected",
__func__);
}
if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
qdict_put(server, "auth", qstring_from_str(auth));
switch (event) {
case SPICE_CHANNEL_EVENT_CONNECTED:
qapi_event_send_spice_connected(server->base, client->base, &error_abort);
break;
case SPICE_CHANNEL_EVENT_INITIALIZED:
if (auth) {
server->has_auth = true;
server->auth = g_strdup(auth);
}
add_channel_info(client, info);
channel_list_add(info);
}
if (event == SPICE_CHANNEL_EVENT_DISCONNECTED) {
qapi_event_send_spice_initialized(server, client, &error_abort);
break;
case SPICE_CHANNEL_EVENT_DISCONNECTED:
channel_list_del(info);
qapi_event_send_spice_disconnected(server->base, client->base, &error_abort);
break;
default:
break;
}
data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
QOBJECT(client), QOBJECT(server));
monitor_protocol_event(qevent[event], data);
qobject_decref(data);
if (need_lock) {
qemu_mutex_unlock_iothread();
}
qapi_free_SpiceServerInfo(server);
qapi_free_SpiceChannel(client);
}
static SpiceCoreInterface core_interface = {
@ -305,7 +307,7 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
static void migrate_end_complete_cb(SpiceMigrateInstance *sin)
{
monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
qapi_event_send_spice_migrate_completed(&error_abort);
spice_migration_completed = true;
}
@ -391,15 +393,16 @@ static SpiceChannelList *qmp_query_spice_channels(void)
chan = g_malloc0(sizeof(*chan));
chan->value = g_malloc0(sizeof(*chan->value));
chan->value->base = g_malloc0(sizeof(*chan->value->base));
paddr = (struct sockaddr *)&item->info->paddr_ext;
plen = item->info->plen_ext;
getnameinfo(paddr, plen,
host, sizeof(host), port, sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV);
chan->value->host = g_strdup(host);
chan->value->port = g_strdup(port);
chan->value->family = g_strdup(inet_strfamily(paddr->sa_family));
chan->value->base->host = g_strdup(host);
chan->value->base->port = g_strdup(port);
chan->value->base->family = inet_netfamily(paddr->sa_family);
chan->value->connection_id = item->info->connection_id;
chan->value->channel_type = item->info->type;

120
ui/vnc.c
View File

@ -35,6 +35,7 @@
#include "qmp-commands.h"
#include "qemu/osdep.h"
#include "ui/input.h"
#include "qapi-event.h"
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
#define VNC_REFRESH_INTERVAL_INC 50
@ -124,9 +125,10 @@ char *vnc_socket_remote_addr(const char *format, int fd) {
return addr_to_string(format, &sa, salen);
}
static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
socklen_t salen)
static VncBasicInfo *vnc_basic_info_get(struct sockaddr_storage *sa,
socklen_t salen)
{
VncBasicInfo *info;
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
int err;
@ -137,40 +139,40 @@ static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
VNC_DEBUG("Cannot resolve address %d: %s\n",
err, gai_strerror(err));
return -1;
return NULL;
}
qdict_put(qdict, "host", qstring_from_str(host));
qdict_put(qdict, "service", qstring_from_str(serv));
qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family)));
return 0;
info = g_malloc0(sizeof(VncBasicInfo));
info->host = g_strdup(host);
info->service = g_strdup(serv);
info->family = inet_netfamily(sa->ss_family);
return info;
}
static int vnc_server_addr_put(QDict *qdict, int fd)
static VncBasicInfo *vnc_basic_info_get_from_server_addr(int fd)
{
struct sockaddr_storage sa;
socklen_t salen;
salen = sizeof(sa);
if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
return -1;
return NULL;
}
return put_addr_qdict(qdict, &sa, salen);
return vnc_basic_info_get(&sa, salen);
}
static int vnc_qdict_remote_addr(QDict *qdict, int fd)
static VncBasicInfo *vnc_basic_info_get_from_remote_addr(int fd)
{
struct sockaddr_storage sa;
socklen_t salen;
salen = sizeof(sa);
if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
return -1;
return NULL;
}
return put_addr_qdict(qdict, &sa, salen);
return vnc_basic_info_get(&sa, salen);
}
static const char *vnc_auth_name(VncDisplay *vd) {
@ -224,81 +226,82 @@ static const char *vnc_auth_name(VncDisplay *vd) {
return "unknown";
}
static int vnc_server_info_put(QDict *qdict)
static VncServerInfo *vnc_server_info_get(void)
{
if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
return -1;
VncServerInfo *info;
VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vnc_display->lsock);
if (!bi) {
return NULL;
}
qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display)));
return 0;
info = g_malloc(sizeof(*info));
info->base = bi;
info->has_auth = true;
info->auth = g_strdup(vnc_auth_name(vnc_display));
return info;
}
static void vnc_client_cache_auth(VncState *client)
{
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
QDict *qdict;
#endif
if (!client->info) {
return;
}
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
qdict = qobject_to_qdict(client->info);
#endif
#ifdef CONFIG_VNC_TLS
if (client->tls.session &&
client->tls.dname) {
qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
client->info->has_x509_dname = true;
client->info->x509_dname = g_strdup(client->tls.dname);
}
#endif
#ifdef CONFIG_VNC_SASL
if (client->sasl.conn &&
client->sasl.username) {
qdict_put(qdict, "sasl_username",
qstring_from_str(client->sasl.username));
client->info->has_sasl_username = true;
client->info->sasl_username = g_strdup(client->sasl.username);
}
#endif
}
static void vnc_client_cache_addr(VncState *client)
{
QDict *qdict;
VncBasicInfo *bi = vnc_basic_info_get_from_remote_addr(client->csock);
qdict = qdict_new();
if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
QDECREF(qdict);
/* XXX: how to report the error? */
return;
if (bi) {
client->info = g_malloc0(sizeof(*client->info));
client->info->base = bi;
}
client->info = QOBJECT(qdict);
}
static void vnc_qmp_event(VncState *vs, MonitorEvent event)
static void vnc_qmp_event(VncState *vs, QAPIEvent event)
{
QDict *server;
QObject *data;
VncServerInfo *si;
if (!vs->info) {
return;
}
g_assert(vs->info->base);
server = qdict_new();
if (vnc_server_info_put(server) < 0) {
QDECREF(server);
si = vnc_server_info_get();
if (!si) {
return;
}
data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
vs->info, QOBJECT(server));
switch (event) {
case QAPI_EVENT_VNC_CONNECTED:
qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
break;
case QAPI_EVENT_VNC_INITIALIZED:
qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
break;
case QAPI_EVENT_VNC_DISCONNECTED:
qapi_event_send_vnc_disconnected(si, vs->info, &error_abort);
break;
default:
break;
}
monitor_protocol_event(event, data);
qobject_incref(vs->info);
qobject_decref(data);
qapi_free_VncServerInfo(si);
}
static VncClientInfo *qmp_query_vnc_client(const VncState *client)
@ -321,9 +324,10 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client)
}
info = g_malloc0(sizeof(*info));
info->host = g_strdup(host);
info->service = g_strdup(serv);
info->family = g_strdup(inet_strfamily(sa.ss_family));
info->base = g_malloc0(sizeof(*info->base));
info->base->host = g_strdup(host);
info->base->service = g_strdup(serv);
info->base->family = inet_netfamily(sa.ss_family);
#ifdef CONFIG_VNC_TLS
if (client->tls.session && client->tls.dname) {
@ -398,7 +402,7 @@ VncInfo *qmp_query_vnc(Error **errp)
info->service = g_strdup(serv);
info->has_family = true;
info->family = g_strdup(inet_strfamily(sa.ss_family));
info->family = inet_netfamily(sa.ss_family);
info->has_auth = true;
info->auth = g_strdup(vnc_auth_name(vnc_display));
@ -1039,7 +1043,7 @@ void vnc_disconnect_finish(VncState *vs)
vnc_jobs_join(vs); /* Wait encoding jobs */
vnc_lock_output(vs);
vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
vnc_qmp_event(vs, QAPI_EVENT_VNC_DISCONNECTED);
buffer_free(&vs->input);
buffer_free(&vs->output);
@ -1048,7 +1052,7 @@ void vnc_disconnect_finish(VncState *vs)
buffer_free(&vs->ws_output);
#endif /* CONFIG_VNC_WS */
qobject_decref(vs->info);
qapi_free_VncClientInfo(vs->info);
vnc_zlib_clear(vs);
vnc_tight_clear(vs);
@ -2323,7 +2327,7 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
vnc_flush(vs);
vnc_client_cache_auth(vs);
vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED);
vnc_qmp_event(vs, QAPI_EVENT_VNC_INITIALIZED);
vnc_read_when(vs, protocol_client_msg, 1);
@ -2846,7 +2850,7 @@ static void vnc_connect(VncDisplay *vd, int csock,
}
vnc_client_cache_addr(vs);
vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
vs->vd = vd;

View File

@ -31,7 +31,6 @@
#include "qemu/queue.h"
#include "qemu/thread.h"
#include "ui/console.h"
#include "monitor/monitor.h"
#include "audio/audio.h"
#include "qemu/bitmap.h"
#include <zlib.h>
@ -40,6 +39,7 @@
#include "keymaps.h"
#include "vnc-palette.h"
#include "vnc-enc-zrle.h"
#include "qapi-types.h"
// #define _VNC_DEBUG 1
@ -292,7 +292,7 @@ struct VncState
bool websocket;
#endif /* CONFIG_VNC_WS */
QObject *info;
VncClientInfo *info;
Buffer output;
Buffer input;

View File

@ -92,14 +92,14 @@ static void inet_setport(struct addrinfo *e, int port)
}
}
const char *inet_strfamily(int family)
NetworkAddressFamily inet_netfamily(int family)
{
switch (family) {
case PF_INET6: return "ipv6";
case PF_INET: return "ipv4";
case PF_UNIX: return "unix";
case PF_INET6: return NETWORK_ADDRESS_FAMILY_IPV6;
case PF_INET: return NETWORK_ADDRESS_FAMILY_IPV4;
case PF_UNIX: return NETWORK_ADDRESS_FAMILY_UNIX;
}
return "unknown";
return NETWORK_ADDRESS_FAMILY_UNKNOWN;
}
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)

25
vl.c
View File

@ -116,6 +116,8 @@ int main(int argc, char **argv)
#include "ui/qemu-spice.h"
#include "qapi/string-input-visitor.h"
#include "qapi/opts-visitor.h"
#include "qom/object_interfaces.h"
#include "qapi-event.h"
#define DEFAULT_RAM_SIZE 128
@ -737,7 +739,7 @@ void vm_start(void)
* the STOP event.
*/
if (runstate_is_running()) {
monitor_protocol_event(QEVENT_STOP, NULL);
qapi_event_send_stop(&error_abort);
} else {
cpu_enable_ticks();
runstate_set(RUN_STATE_RUNNING);
@ -745,7 +747,7 @@ void vm_start(void)
resume_all_vcpus();
}
monitor_protocol_event(QEVENT_RESUME, NULL);
qapi_event_send_resume(&error_abort);
}
@ -789,15 +791,6 @@ int qemu_timedate_diff(struct tm *tm)
return seconds - time(NULL);
}
void rtc_change_mon_event(struct tm *tm)
{
QObject *data;
data = qobject_from_jsonf("{ 'offset': %d }", qemu_timedate_diff(tm));
monitor_protocol_event(QEVENT_RTC_CHANGE, data);
qobject_decref(data);
}
static void configure_rtc_date_offset(const char *startdate, int legacy)
{
time_t rtc_start_date;
@ -1849,7 +1842,7 @@ void qemu_system_reset(bool report)
qemu_devices_reset();
}
if (report) {
monitor_protocol_event(QEVENT_RESET, NULL);
qapi_event_send_reset(&error_abort);
}
cpu_synchronize_all_post_reset();
}
@ -1870,7 +1863,7 @@ static void qemu_system_suspend(void)
pause_all_vcpus();
notifier_list_notify(&suspend_notifiers, NULL);
runstate_set(RUN_STATE_SUSPENDED);
monitor_protocol_event(QEVENT_SUSPEND, NULL);
qapi_event_send_suspend(&error_abort);
}
void qemu_system_suspend_request(void)
@ -1933,7 +1926,7 @@ void qemu_system_shutdown_request(void)
static void qemu_system_powerdown(void)
{
monitor_protocol_event(QEVENT_POWERDOWN, NULL);
qapi_event_send_powerdown(&error_abort);
notifier_list_notify(&powerdown_notifiers, NULL);
}
@ -1965,7 +1958,7 @@ static bool main_loop_should_exit(void)
}
if (qemu_shutdown_requested()) {
qemu_kill_report();
monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
qapi_event_send_shutdown(&error_abort);
if (no_shutdown) {
vm_stop(RUN_STATE_SHUTDOWN);
} else {
@ -1988,7 +1981,7 @@ static bool main_loop_should_exit(void)
notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
wakeup_reason = QEMU_WAKEUP_REASON_NONE;
resume_all_vcpus();
monitor_protocol_event(QEVENT_WAKEUP, NULL);
qapi_event_send_wakeup(&error_abort);
}
if (qemu_powerdown_requested()) {
qemu_system_powerdown();