* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <dirent.h>
+#include "qemu-common.h"
+#include "cpu.h"
#include "hw/hw.h"
#include "monitor/qdev.h"
#include "hw/usb.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
#include "audio/audio.h"
#include "disas/disas.h"
#include "sysemu/balloon.h"
#include "qapi/qmp/json-streamer.h"
#include "qapi/qmp/json-parser.h"
#include <qom/object_interfaces.h>
-#include "qemu/osdep.h"
#include "cpu.h"
#include "trace.h"
#include "trace/control.h"
#include "trace/simple.h"
#endif
#include "exec/memory.h"
+#include "exec/exec-all.h"
+#include "qemu/log.h"
#include "qmp-commands.h"
#include "hmp.h"
#include "qemu/thread.h"
#include "qapi-event.h"
#include "qmp-introspect.h"
#include "sysemu/block-backend.h"
+#include "sysemu/qtest.h"
+#include "qemu/cutils.h"
/* for hmp_info_irq/pic */
#if defined(TARGET_SPARC)
* instance.
*/
typedef struct MonitorQAPIEventState {
- QAPIEvent event; /* Event being tracked */
- int64_t rate; /* Minimum time (in ns) between two events */
+ QAPIEvent event; /* Throttling state for this event type and... */
+ QDict *data; /* ... data, see qapi_event_throttle_equal() */
QEMUTimer *timer; /* Timer for handling delayed events */
QDict *qdict; /* Delayed event (if any) */
} MonitorQAPIEventState;
+typedef struct {
+ int64_t rate; /* Minimum time (in ns) between two events */
+} MonitorQAPIEventConf;
+
struct Monitor {
CharDriverState *chr;
int reset_seen;
Monitor *cur_mon;
+static QEMUClockType event_clock_type = QEMU_CLOCK_REALTIME;
+
static void monitor_command_cb(void *opaque, const char *cmdline,
void *readline_opaque);
QObject *obj;
obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
- ErrorClass_lookup[error_get_class(err)],
+ QapiErrorClass_lookup[error_get_class(err)],
error_get_pretty(err));
return qobject_to_qdict(obj);
}
-static MonitorQAPIEventState monitor_qapi_event_state[QAPI_EVENT_MAX];
+static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
+ /* Limit guest-triggerable events to 1 per second */
+ [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_BALLOON_CHANGE] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS },
+};
+
+GHashTable *monitor_qapi_event_state;
/*
* Emits the event to every monitor instance, @event is only used for trace
}
}
+static void monitor_qapi_event_handler(void *opaque);
+
/*
* Queue a new event for emission to Monitor instances,
* applying any rate limiting if required.
static void
monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
{
+ MonitorQAPIEventConf *evconf;
MonitorQAPIEventState *evstate;
- assert(event < QAPI_EVENT_MAX);
- evstate = &monitor_qapi_event_state[event];
- trace_monitor_protocol_event_queue(event, qdict, evstate->rate);
+ assert(event < QAPI_EVENT__MAX);
+ evconf = &monitor_qapi_event_conf[event];
+ trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
qemu_mutex_lock(&monitor_lock);
- if (!evstate->rate) {
+ if (!evconf->rate) {
/* Unthrottled event */
monitor_qapi_event_emit(event, qdict);
} else {
- if (timer_pending(evstate->timer)) {
+ QDict *data = qobject_to_qdict(qdict_get(qdict, "data"));
+ MonitorQAPIEventState key = { .event = event, .data = data };
+
+ evstate = g_hash_table_lookup(monitor_qapi_event_state, &key);
+ assert(!evstate || timer_pending(evstate->timer));
+
+ if (evstate) {
/*
- * Timer is pending for (at least) evstate->rate ns after
+ * Timer is pending for (at least) evconf->rate ns after
* last send. Store event for sending when timer fires,
* replacing a prior stored event if any.
*/
QINCREF(evstate->qdict);
} else {
/*
- * Last send was (at least) evstate->rate ns ago.
+ * Last send was (at least) evconf->rate ns ago.
* Send immediately, and arm the timer to call
- * monitor_qapi_event_handler() in evstate->rate ns. Any
+ * monitor_qapi_event_handler() in evconf->rate ns. Any
* events arriving before then will be delayed until then.
*/
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+ int64_t now = qemu_clock_get_ns(event_clock_type);
monitor_qapi_event_emit(event, qdict);
- timer_mod_ns(evstate->timer, now + evstate->rate);
+
+ evstate = g_new(MonitorQAPIEventState, 1);
+ evstate->event = event;
+ evstate->data = data;
+ QINCREF(evstate->data);
+ evstate->qdict = NULL;
+ evstate->timer = timer_new_ns(event_clock_type,
+ monitor_qapi_event_handler,
+ evstate);
+ g_hash_table_add(monitor_qapi_event_state, evstate);
+ timer_mod_ns(evstate->timer, now + evconf->rate);
}
}
}
/*
- * This function runs evstate->rate ns after sending a throttled
+ * This function runs evconf->rate ns after sending a throttled
* event.
* If another event has since been stored, send it.
*/
static void monitor_qapi_event_handler(void *opaque)
{
MonitorQAPIEventState *evstate = opaque;
+ MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
qemu_mutex_lock(&monitor_lock);
if (evstate->qdict) {
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+ int64_t now = qemu_clock_get_ns(event_clock_type);
monitor_qapi_event_emit(evstate->event, evstate->qdict);
QDECREF(evstate->qdict);
evstate->qdict = NULL;
- timer_mod_ns(evstate->timer, now + evstate->rate);
+ timer_mod_ns(evstate->timer, now + evconf->rate);
+ } else {
+ g_hash_table_remove(monitor_qapi_event_state, evstate);
+ QDECREF(evstate->data);
+ timer_free(evstate->timer);
+ g_free(evstate);
}
qemu_mutex_unlock(&monitor_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_qapi_event_throttle(QAPIEvent event, int64_t rate)
+static unsigned int qapi_event_throttle_hash(const void *key)
{
- MonitorQAPIEventState *evstate;
- assert(event < QAPI_EVENT_MAX);
+ const MonitorQAPIEventState *evstate = key;
+ unsigned int hash = evstate->event * 255;
+
+ if (evstate->event == QAPI_EVENT_VSERPORT_CHANGE) {
+ hash += g_str_hash(qdict_get_str(evstate->data, "id"));
+ }
+
+ if (evstate->event == QAPI_EVENT_QUORUM_REPORT_BAD) {
+ hash += g_str_hash(qdict_get_str(evstate->data, "node-name"));
+ }
+
+ return hash;
+}
+
+static gboolean qapi_event_throttle_equal(const void *a, const void *b)
+{
+ const MonitorQAPIEventState *eva = a;
+ const MonitorQAPIEventState *evb = b;
+
+ if (eva->event != evb->event) {
+ return FALSE;
+ }
+
+ if (eva->event == QAPI_EVENT_VSERPORT_CHANGE) {
+ return !strcmp(qdict_get_str(eva->data, "id"),
+ qdict_get_str(evb->data, "id"));
+ }
- evstate = &(monitor_qapi_event_state[event]);
+ if (eva->event == QAPI_EVENT_QUORUM_REPORT_BAD) {
+ return !strcmp(qdict_get_str(eva->data, "node-name"),
+ qdict_get_str(evb->data, "node-name"));
+ }
- trace_monitor_protocol_event_throttle(event, rate);
- evstate->event = event;
- assert(rate * SCALE_MS <= INT64_MAX);
- evstate->rate = rate * SCALE_MS;
- evstate->qdict = NULL;
- evstate->timer = timer_new_ns(QEMU_CLOCK_REALTIME,
- monitor_qapi_event_handler,
- evstate);
+ return TRUE;
}
static void monitor_qapi_event_init(void)
{
- /* 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);
- monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_REPORT_BAD, 1000);
- monitor_qapi_event_throttle(QAPI_EVENT_QUORUM_FAILURE, 1000);
- monitor_qapi_event_throttle(QAPI_EVENT_VSERPORT_CHANGE, 1000);
+ if (qtest_enabled()) {
+ event_clock_type = QEMU_CLOCK_VIRTUAL;
+ }
+ monitor_qapi_event_state = g_hash_table_new(qapi_event_throttle_hash,
+ qapi_event_throttle_equal);
qmp_event_set_func_emit(monitor_qapi_event_queue);
}
EventInfoList *info, *ev_list = NULL;
QAPIEvent e;
- for (e = 0 ; e < QAPI_EVENT_MAX ; 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));
static void hmp_mouse_button(Monitor *mon, const QDict *qdict)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
qemu_boot_set(bootdevice, &local_err);
if (local_err) {
- monitor_printf(mon, "%s\n", error_get_pretty(local_err));
- error_free(local_err);
+ error_report_err(local_err);
} else {
monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
}
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
- dev_time, dev_time / (double)get_ticks_per_sec());
+ dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
- tcg_time, tcg_time / (double)get_ticks_per_sec());
+ tcg_time, tcg_time / (double)NANOSECONDS_PER_SECOND);
tcg_time = 0;
dev_time = 0;
}
{
const MonitorDef *md = target_monitor_defs();
void *ptr;
+ uint64_t tmp = 0;
+ int ret;
if (md == NULL) {
return -1;
return 0;
}
}
- return -1;
+
+ ret = target_get_monitor_def(mon_get_cpu(), name, &tmp);
+ if (!ret) {
+ *pval = (target_long) tmp;
+ }
+
+ return ret;
}
static void next(void)
}
len = strlen(str);
readline_set_completion_index(rs, len);
- for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+ for (i = 0; i < Q_KEY_CODE__MAX; i++) {
if (!strncmp(str, QKeyCode_lookup[i], len)) {
readline_add_completion(rs, QKeyCode_lookup[i]);
}
readline_set_completion_index(rs, len);
if (nb_args == 2) {
int i;
- for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
const char *name = MigrationCapability_lookup[i];
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
int i;
- for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) {
+ for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
const char *name = MigrationParameter_lookup[i];
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
static void vm_completion(ReadLineState *rs, const char *str)
{
size_t len;
- BlockDriverState *bs = NULL;
+ BlockDriverState *bs;
+ BdrvNextIterator it;
len = strlen(str);
readline_set_completion_index(rs, len);
- while ((bs = bdrv_next(bs))) {
+
+ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
SnapshotInfoList *snapshots, *snapshot;
+ AioContext *ctx = bdrv_get_aio_context(bs);
+ bool ok = false;
- if (!bdrv_can_snapshot(bs)) {
- continue;
+ aio_context_acquire(ctx);
+ if (bdrv_can_snapshot(bs)) {
+ ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0;
}
- if (bdrv_query_snapshot_info_list(bs, &snapshots, NULL)) {
+ aio_context_release(ctx);
+ if (!ok) {
continue;
}
+
snapshot = snapshots;
while (snapshot) {
char *completion = snapshot->value->name;
int i;
const char *ptype, *str, *name;
const mon_cmd_t *cmd;
- BlockDriverState *bs;
+ BlockBackend *blk = NULL;
if (nb_args <= 1) {
/* command completion */
case 'B':
/* block device name completion */
readline_set_completion_index(mon->rs, strlen(str));
- for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
- name = bdrv_get_device_name(bs);
+ while ((blk = blk_next(blk)) != NULL) {
+ name = blk_name(blk);
if (str[0] == '\0' ||
!strncmp(name, str, strlen(str))) {
readline_add_completion(mon->rs, name);
return input_dict;
}
-static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
+static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
{
Error *local_err = NULL;
QObject *obj, *data;
err_out:
monitor_protocol_emitter(mon, data, local_err);
qobject_decref(data);
+ error_free(local_err);
QDECREF(input);
QDECREF(args);
}
bdrv_add_key(bs, password, &local_err);
if (local_err) {
- monitor_printf(mon, "%s\n", error_get_pretty(local_err));
- error_free(local_err);
+ error_report_err(local_err);
ret = -EPERM;
}
if (mon->password_completion_cb)
error_setg(errp, QERR_FEATURE_DISABLED, "dump-skeys");
}
#endif
+
+#ifndef TARGET_ARM
+GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
+{
+ error_setg(errp, QERR_FEATURE_DISABLED, "query-gic-capabilities");
+ return NULL;
+}
+#endif