mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 19:03:38 +08:00
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:
commit
089a39486f
21
Makefile
21
Makefile
@ -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 $@")
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
13
balloon.c
13
balloon.c
@ -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
73
block.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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--;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
12
blockdev.c
12
blockdev.c
@ -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);
|
||||
}
|
||||
|
55
blockjob.c
55
blockjob.c
@ -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
4
cpus.c
@ -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();
|
||||
|
@ -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 ==
|
||||
|
||||
|
@ -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.
|
@ -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 );
|
||||
|
@ -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
5
hmp.c
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
|
@ -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
27
include/qapi/qmp-event.h
Normal 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
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
227
monitor.c
@ -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
318
qapi-event.json
Normal 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' } }
|
166
qapi-schema.json
166
qapi-schema.json
@ -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' }
|
||||
|
@ -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
|
||||
|
@ -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' } }
|
||||
|
@ -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
74
qapi/qmp-event.c
Normal 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;
|
||||
}
|
134
qemu-char.c
134
qemu-char.c
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
369
scripts/qapi-event.py
Normal 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()
|
@ -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)
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -1,6 +0,0 @@
|
||||
#include "qemu-common.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
{
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
1
tests/qapi-schema/event-nest-struct.err
Normal file
1
tests/qapi-schema/event-nest-struct.err
Normal 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'
|
1
tests/qapi-schema/event-nest-struct.exit
Normal file
1
tests/qapi-schema/event-nest-struct.exit
Normal file
@ -0,0 +1 @@
|
||||
1
|
2
tests/qapi-schema/event-nest-struct.json
Normal file
2
tests/qapi-schema/event-nest-struct.json
Normal file
@ -0,0 +1,2 @@
|
||||
{ 'event': 'EVENT_A',
|
||||
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
|
0
tests/qapi-schema/event-nest-struct.out
Normal file
0
tests/qapi-schema/event-nest-struct.out
Normal 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' } }
|
||||
|
@ -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
265
tests/test-qmp-event.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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
120
ui/vnc.c
@ -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;
|
||||
|
4
ui/vnc.h
4
ui/vnc.h
@ -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;
|
||||
|
@ -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
25
vl.c
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user