Merge remote-tracking branch 'qmp/queue/qmp' into staging
* qmp/queue/qmp: build: install qmp-commands.txt Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events Add event notification for guest balloon changes Fix some more license versions (GPL2+ instead of GPL2) monitor: Fix memory leak with readline completion qmp: do not include monitor.h from qapi-types-core.h qmp: include monitor.h when needed kvm: add missing include files
This commit is contained in:
commit
664535c31c
1
Makefile
1
Makefile
@ -272,6 +272,7 @@ endif
|
||||
install-doc: $(DOCS)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
|
@ -335,3 +335,21 @@ Example:
|
||||
"len": 10737418240, "offset": 134217728,
|
||||
"speed": 0 },
|
||||
"timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
|
||||
|
||||
|
||||
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 } }
|
||||
|
14
balloon.c
14
balloon.c
@ -30,6 +30,7 @@
|
||||
#include "balloon.h"
|
||||
#include "trace.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qjson.h"
|
||||
|
||||
static QEMUBalloonEvent *balloon_event_fn;
|
||||
static QEMUBalloonStatus *balloon_stat_fn;
|
||||
@ -80,6 +81,19 @@ 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;
|
||||
|
@ -24,4 +24,6 @@ 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
|
||||
|
1
hmp.c
1
hmp.c
@ -18,6 +18,7 @@
|
||||
#include "qemu-option.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "monitor.h"
|
||||
|
||||
static void hmp_handle_error(Monitor *mon, Error **errp)
|
||||
{
|
||||
|
@ -146,8 +146,13 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
|
||||
{
|
||||
VirtIOBalloon *dev = to_virtio_balloon(vdev);
|
||||
struct virtio_balloon_config config;
|
||||
uint32_t oldactual = dev->actual;
|
||||
memcpy(&config, config_data, 8);
|
||||
dev->actual = le32_to_cpu(config.actual);
|
||||
if (dev->actual != oldactual) {
|
||||
qemu_balloon_changed(ram_size -
|
||||
(dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-barrier.h"
|
||||
#include "qemu-option.h"
|
||||
#include "qemu-config.h"
|
||||
#include "sysemu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/msi.h"
|
||||
|
159
monitor.c
159
monitor.c
@ -66,6 +66,7 @@
|
||||
#include "memory.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "hmp.h"
|
||||
#include "qemu-thread.h"
|
||||
|
||||
/* for pic/irq_info */
|
||||
#if defined(TARGET_SPARC)
|
||||
@ -145,6 +146,19 @@ typedef struct MonitorControl {
|
||||
int command_mode;
|
||||
} MonitorControl;
|
||||
|
||||
/*
|
||||
* To prevent flooding clients, events can be throttled. The
|
||||
* 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 */
|
||||
QEMUTimer *timer; /* Timer for handling delayed events */
|
||||
QObject *data; /* Event pending delayed dispatch */
|
||||
} MonitorEventState;
|
||||
|
||||
struct Monitor {
|
||||
CharDriverState *chr;
|
||||
int mux_out;
|
||||
@ -443,9 +457,145 @@ static const char *monitor_event_names[] = {
|
||||
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
|
||||
[QEVENT_SUSPEND] = "SUSPEND",
|
||||
[QEVENT_WAKEUP] = "WAKEUP",
|
||||
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
|
||||
};
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
|
||||
|
||||
MonitorEventState monitor_event_state[QEVENT_MAX];
|
||||
QemuMutex monitor_event_state_lock;
|
||||
|
||||
/*
|
||||
* Emits the event to every monitor instance
|
||||
*/
|
||||
static void
|
||||
monitor_protocol_event_emit(MonitorEvent event,
|
||||
QObject *data)
|
||||
{
|
||||
Monitor *mon;
|
||||
|
||||
trace_monitor_protocol_event_emit(event, data);
|
||||
QLIST_FOREACH(mon, &mon_list, entry) {
|
||||
if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
|
||||
monitor_json_emitter(mon, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
MonitorEventState *evstate;
|
||||
int64_t now = qemu_get_clock_ns(rt_clock);
|
||||
assert(event < QEVENT_MAX);
|
||||
|
||||
qemu_mutex_lock(&monitor_event_state_lock);
|
||||
evstate = &(monitor_event_state[event]);
|
||||
trace_monitor_protocol_event_queue(event,
|
||||
data,
|
||||
evstate->rate,
|
||||
evstate->last,
|
||||
now);
|
||||
|
||||
/* Rate limit of 0 indicates no throttling */
|
||||
if (!evstate->rate) {
|
||||
monitor_protocol_event_emit(event, data);
|
||||
evstate->last = now;
|
||||
} else {
|
||||
int64_t delta = now - evstate->last;
|
||||
if (evstate->data ||
|
||||
delta < evstate->rate) {
|
||||
/* If there's an existing event pending, replace
|
||||
* it with the new event, otherwise schedule a
|
||||
* timer for delayed emission
|
||||
*/
|
||||
if (evstate->data) {
|
||||
qobject_decref(evstate->data);
|
||||
} else {
|
||||
int64_t then = evstate->last + evstate->rate;
|
||||
qemu_mod_timer_ns(evstate->timer, then);
|
||||
}
|
||||
evstate->data = data;
|
||||
qobject_incref(evstate->data);
|
||||
} else {
|
||||
monitor_protocol_event_emit(event, data);
|
||||
evstate->last = now;
|
||||
}
|
||||
}
|
||||
qemu_mutex_unlock(&monitor_event_state_lock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The callback invoked by QemuTimer when a delayed
|
||||
* event is ready to be emitted
|
||||
*/
|
||||
static void monitor_protocol_event_handler(void *opaque)
|
||||
{
|
||||
MonitorEventState *evstate = opaque;
|
||||
int64_t now = qemu_get_clock_ns(rt_clock);
|
||||
|
||||
qemu_mutex_lock(&monitor_event_state_lock);
|
||||
|
||||
trace_monitor_protocol_event_handler(evstate->event,
|
||||
evstate->data,
|
||||
evstate->last,
|
||||
now);
|
||||
if (evstate->data) {
|
||||
monitor_protocol_event_emit(evstate->event, evstate->data);
|
||||
qobject_decref(evstate->data);
|
||||
evstate->data = NULL;
|
||||
}
|
||||
evstate->last = now;
|
||||
qemu_mutex_unlock(&monitor_event_state_lock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @event: the event ID to be limited
|
||||
* @rate: the rate limit in milliseconds
|
||||
*
|
||||
* Sets a rate limit on a particular event, so no
|
||||
* more than 1 event will be emitted within @rate
|
||||
* milliseconds
|
||||
*/
|
||||
static void
|
||||
monitor_protocol_event_throttle(MonitorEvent event,
|
||||
int64_t rate)
|
||||
{
|
||||
MonitorEventState *evstate;
|
||||
assert(event < QEVENT_MAX);
|
||||
|
||||
evstate = &(monitor_event_state[event]);
|
||||
|
||||
trace_monitor_protocol_event_throttle(event, rate);
|
||||
evstate->event = event;
|
||||
evstate->rate = rate * SCALE_MS;
|
||||
evstate->timer = qemu_new_timer(rt_clock,
|
||||
SCALE_MS,
|
||||
monitor_protocol_event_handler,
|
||||
evstate);
|
||||
evstate->last = 0;
|
||||
evstate->data = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Global, one-time initializer to configure the rate limiting
|
||||
* and initialize state */
|
||||
static void monitor_protocol_event_init(void)
|
||||
{
|
||||
qemu_mutex_init(&monitor_event_state_lock);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* monitor_protocol_event(): Generate a Monitor event
|
||||
*
|
||||
@ -455,7 +605,6 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
{
|
||||
QDict *qmp;
|
||||
const char *event_name;
|
||||
Monitor *mon;
|
||||
|
||||
assert(event < QEVENT_MAX);
|
||||
|
||||
@ -470,11 +619,8 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
qdict_put_obj(qmp, "data", data);
|
||||
}
|
||||
|
||||
QLIST_FOREACH(mon, &mon_list, entry) {
|
||||
if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
|
||||
monitor_json_emitter(mon, QOBJECT(qmp));
|
||||
}
|
||||
}
|
||||
trace_monitor_protocol_event(event, event_name, qmp);
|
||||
monitor_protocol_event_queue(event, QOBJECT(qmp));
|
||||
QDECREF(qmp);
|
||||
}
|
||||
|
||||
@ -4570,6 +4716,7 @@ void monitor_init(CharDriverState *chr, int flags)
|
||||
|
||||
if (is_first_init) {
|
||||
key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
|
||||
monitor_protocol_event_init();
|
||||
is_first_init = 0;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ typedef enum MonitorEvent {
|
||||
QEVENT_DEVICE_TRAY_MOVED,
|
||||
QEVENT_SUSPEND,
|
||||
QEVENT_WAKEUP,
|
||||
QEVENT_BALLOON_CHANGE,
|
||||
|
||||
/* Add to 'monitor_event_names' array in monitor.c when
|
||||
* defining new events here */
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <net/if.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "monitor.h"
|
||||
#include "sysemu.h"
|
||||
#include "qemu-char.h"
|
||||
#include "qemu-common.h"
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "error.h"
|
||||
|
||||
/* FIXME this is temporary until we remove middle mode */
|
||||
#include "monitor.h"
|
||||
#include "qerror.h"
|
||||
|
||||
#endif
|
||||
|
@ -677,6 +677,11 @@ esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)"
|
||||
# monitor.c
|
||||
handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
|
||||
monitor_protocol_emitter(void *mon) "mon %p"
|
||||
monitor_protocol_event(uint32_t event, const char *evname, void *data) "event=%d name \"%s\" data %p"
|
||||
monitor_protocol_event_handler(uint32_t event, void *data, uint64_t last, uint64_t now) "event=%d data=%p last=%" PRId64 " now=%" PRId64
|
||||
monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p"
|
||||
monitor_protocol_event_queue(uint32_t event, void *data, uint64_t rate, uint64_t last, uint64_t now) "event=%d data=%p rate=%" PRId64 " last=%" PRId64 " now=%" PRId64
|
||||
monitor_protocol_event_throttle(uint32_t event, uint64_t rate) "event=%d rate=%" PRId64
|
||||
|
||||
# hw/opencores_eth.c
|
||||
open_eth_mii_write(unsigned idx, uint16_t v) "MII[%02x] <- %04x"
|
||||
|
Loading…
Reference in New Issue
Block a user