QMP and QObject patches

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWMyUCAAoJEDhwtADrkYZTNAMQAKW+cQaH1GdWb0cX38fJ3ngM
 HYeHiYa4g7DXJGTUtobfq19v688JTZRF9DzZVj0iU8qY/UDxDtOzH10eX02C/oZn
 1ra8otYNtTHCz2xGnSP+AFcn+5VjhucBH+SwWTb889NriQASnxbOiCKkBrsxxRhK
 0ReCUOi7FqG8Yq5PKTIZHcU4u5LYZQm07/4WNM0Rv8HnflRF/I6CswG60ZWsy4lM
 x4WFnB/K6aB8Tg0TmSQgz5jFNfJyO+IVvplaqW3Lz/cUmOam7hx6eB5xxH84MrY9
 Ng6taT7v+V6mKvq1wof57D0EFa2Ple4HqKvEYza6ShwkoTN57joJAr6MCKbILMXp
 /GYDMHo+IJvf1T2NkeM6nMDYMFsWMYBxxJN6ygukRdb/H5ACDxl9juZpHx3QP4KR
 V6+JpJ+BBtfWCTGzYD8Yn0Qs2O2Th43KvPAZ7j/RlcU/MNzv6fyRCc+7fwNdG9fo
 Xoz4c2S6Io7GJtLMDZiVG7Xz27TacprZx4CucBE2ccxJGsKIWrWRYrtqTQTh0Vtk
 br9QHK/Dqh02VJ42TCo16EDkDd594Q4QdhxvAgblmH0MH6lWDpuMJwbIfZKfkJxl
 KJ1c6DvYGdgixWhBWavVMwGSvzDr7udU1uz2FEfQmGKneiQIxfjTnHYl0CyQb/q0
 Y4lGGbmdtQ+1iBogq3Y/
 =0NNZ
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-monitor-2015-10-30' into staging

QMP and QObject patches

# gpg: Signature made Fri 30 Oct 2015 08:06:26 GMT using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-monitor-2015-10-30:
  docs: Document QMP event rate limiting
  monitor: Throttle event VSERPORT_CHANGE separately by "id"
  monitor: Turn monitor_qapi_event_state[] into a hash table
  glib: add compatibility interface for g_hash_table_add()
  monitor: Split MonitorQAPIEventConf off MonitorQAPIEventState
  monitor: Switch from timer_new() to timer_new_ns()
  monitor: Simplify event throttling
  monitor: Reduce casting of QAPI event QDict
  qstring: Make conversion from QObject * accept null
  qlist: Make conversion from QObject * accept null
  qfloat qint: Make conversion from QObject * accept null
  qdict: Make conversion from QObject * accept null
  qbool: Make conversion from QObject * accept null
  qobject: Drop QObject_HEAD

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-10-30 09:41:14 +00:00
commit fdf927621a
20 changed files with 189 additions and 153 deletions

View File

@ -28,6 +28,8 @@ Example:
"data": { "actual": 944766976 }, "data": { "actual": 944766976 },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } } "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
Note: this event is rate-limited.
BLOCK_IMAGE_CORRUPTED BLOCK_IMAGE_CORRUPTED
--------------------- ---------------------
@ -296,6 +298,8 @@ Example:
"data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 }, "data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } } "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
Note: this event is rate-limited.
QUORUM_REPORT_BAD QUORUM_REPORT_BAD
----------------- -----------------
@ -318,6 +322,8 @@ Example:
"data": { "node-name": "1.raw", "sector-num": 345435, "sectors-count": 5 }, "data": { "node-name": "1.raw", "sector-num": 345435, "sectors-count": 5 },
"timestamp": { "seconds": 1344522075, "microseconds": 745528 } } "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
Note: this event is rate-limited.
RESET RESET
----- -----
@ -358,6 +364,8 @@ Example:
"data": { "offset": 78 }, "data": { "offset": 78 },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } } "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
Note: this event is rate-limited.
SHUTDOWN SHUTDOWN
-------- --------
@ -632,6 +640,8 @@ Example:
"data": { "id": "channel0", "open": true }, "data": { "id": "channel0", "open": true },
"timestamp": { "seconds": 1401385907, "microseconds": 422329 } } "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
Note: this event is rate-limited separately for each "id".
WAKEUP WAKEUP
------ ------
@ -662,3 +672,5 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events. followed respectively by the RESET, SHUTDOWN, or STOP events.
Note: this event is rate-limited.

View File

@ -175,6 +175,11 @@ The format of asynchronous events is:
For a listing of supported asynchronous events, please, refer to the For a listing of supported asynchronous events, please, refer to the
qmp-events.txt file. qmp-events.txt file.
Some events are rate-limited to at most one per second. If additional
"similar" events arrive within one second, all but the last one are
dropped, and the last one is delayed. "Similar" normally means same
event type. See qmp-events.txt for details.
2.5 QGA Synchronization 2.5 QGA Synchronization
----------------------- -----------------------

View File

@ -165,6 +165,14 @@ static inline GThread *g_thread_new(const char *name,
#define CompatGCond GCond #define CompatGCond GCond
#endif /* glib 2.31 */ #endif /* glib 2.31 */
#if !GLIB_CHECK_VERSION(2, 32, 0)
/* Beware, function returns gboolean since 2.39.2, see GLib commit 9101915 */
static inline void g_hash_table_add(GHashTable *hash_table, gpointer key)
{
g_hash_table_replace(hash_table, key, key);
}
#endif
#ifndef g_assert_true #ifndef g_assert_true
#define g_assert_true(expr) \ #define g_assert_true(expr) \
do { \ do { \

View File

@ -18,7 +18,7 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
typedef struct QBool { typedef struct QBool {
QObject_HEAD; QObject base;
bool value; bool value;
} QBool; } QBool;

View File

@ -28,7 +28,7 @@ typedef struct QDictEntry {
} QDictEntry; } QDictEntry;
typedef struct QDict { typedef struct QDict {
QObject_HEAD; QObject base;
size_t size; size_t size;
QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX]; QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX];
} QDict; } QDict;

View File

@ -18,7 +18,7 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
typedef struct QFloat { typedef struct QFloat {
QObject_HEAD; QObject base;
double value; double value;
} QFloat; } QFloat;

View File

@ -17,7 +17,7 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
typedef struct QInt { typedef struct QInt {
QObject_HEAD; QObject base;
int64_t value; int64_t value;
} QInt; } QInt;

View File

@ -22,7 +22,7 @@ typedef struct QListEntry {
} QListEntry; } QListEntry;
typedef struct QList { typedef struct QList {
QObject_HEAD; QObject base;
QTAILQ_HEAD(,QListEntry) head; QTAILQ_HEAD(,QListEntry) head;
} QList; } QList;

View File

@ -59,10 +59,6 @@ typedef struct QObject {
size_t refcnt; size_t refcnt;
} QObject; } QObject;
/* Objects definitions must include this */
#define QObject_HEAD \
QObject base
/* Get the 'base' part of an object */ /* Get the 'base' part of an object */
#define QOBJECT(obj) (&(obj)->base) #define QOBJECT(obj) (&(obj)->base)

View File

@ -17,7 +17,7 @@
#include "qapi/qmp/qobject.h" #include "qapi/qmp/qobject.h"
typedef struct QString { typedef struct QString {
QObject_HEAD; QObject base;
char *string; char *string;
size_t length; size_t length;
size_t capacity; size_t capacity;

192
monitor.c
View File

@ -181,13 +181,16 @@ typedef struct {
* instance. * instance.
*/ */
typedef struct MonitorQAPIEventState { typedef struct MonitorQAPIEventState {
QAPIEvent event; /* Event being tracked */ QAPIEvent event; /* Throttling state for this event type and... */
int64_t rate; /* Minimum time (in ns) between two events */ QDict *data; /* ... data, see qapi_event_throttle_equal() */
int64_t last; /* QEMU_CLOCK_REALTIME value at last emission */
QEMUTimer *timer; /* Timer for handling delayed events */ QEMUTimer *timer; /* Timer for handling delayed events */
QObject *data; /* Event pending delayed dispatch */ QDict *qdict; /* Delayed event (if any) */
} MonitorQAPIEventState; } MonitorQAPIEventState;
typedef struct {
int64_t rate; /* Minimum time (in ns) between two events */
} MonitorQAPIEventConf;
struct Monitor { struct Monitor {
CharDriverState *chr; CharDriverState *chr;
int reset_seen; int reset_seen;
@ -438,132 +441,161 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data,
} }
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 * Emits the event to every monitor instance, @event is only used for trace
* Called with monitor_lock held. * Called with monitor_lock held.
*/ */
static void monitor_qapi_event_emit(QAPIEvent event, QObject *data) static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict)
{ {
Monitor *mon; Monitor *mon;
trace_monitor_protocol_event_emit(event, data); trace_monitor_protocol_event_emit(event, qdict);
QLIST_FOREACH(mon, &mon_list, entry) { QLIST_FOREACH(mon, &mon_list, entry) {
if (monitor_is_qmp(mon) && mon->qmp.in_command_mode) { if (monitor_is_qmp(mon) && mon->qmp.in_command_mode) {
monitor_json_emitter(mon, data); monitor_json_emitter(mon, QOBJECT(qdict));
} }
} }
} }
static void monitor_qapi_event_handler(void *opaque);
/* /*
* Queue a new event for emission to Monitor instances, * Queue a new event for emission to Monitor instances,
* applying any rate limiting if required. * applying any rate limiting if required.
*/ */
static void static void
monitor_qapi_event_queue(QAPIEvent event, QDict *data, Error **errp) monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
{ {
MonitorQAPIEventConf *evconf;
MonitorQAPIEventState *evstate; MonitorQAPIEventState *evstate;
assert(event < QAPI_EVENT_MAX); assert(event < QAPI_EVENT_MAX);
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); evconf = &monitor_qapi_event_conf[event];
trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
evstate = &(monitor_qapi_event_state[event]);
trace_monitor_protocol_event_queue(event,
data,
evstate->rate,
evstate->last,
now);
/* Rate limit of 0 indicates no throttling */
qemu_mutex_lock(&monitor_lock); qemu_mutex_lock(&monitor_lock);
if (!evstate->rate) {
monitor_qapi_event_emit(event, QOBJECT(data)); if (!evconf->rate) {
evstate->last = now; /* Unthrottled event */
monitor_qapi_event_emit(event, qdict);
} else { } else {
int64_t delta = now - evstate->last; QDict *data = qobject_to_qdict(qdict_get(qdict, "data"));
if (evstate->data || MonitorQAPIEventState key = { .event = event, .data = data };
delta < evstate->rate) {
/* If there's an existing event pending, replace evstate = g_hash_table_lookup(monitor_qapi_event_state, &key);
* it with the new event, otherwise schedule a assert(!evstate || timer_pending(evstate->timer));
* timer for delayed emission
if (evstate) {
/*
* 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.
*/ */
if (evstate->data) { QDECREF(evstate->qdict);
qobject_decref(evstate->data); evstate->qdict = qdict;
} else { QINCREF(evstate->qdict);
int64_t then = evstate->last + evstate->rate;
timer_mod_ns(evstate->timer, then);
}
evstate->data = QOBJECT(data);
qobject_incref(evstate->data);
} else { } else {
monitor_qapi_event_emit(event, QOBJECT(data)); /*
evstate->last = now; * Last send was (at least) evconf->rate ns ago.
* Send immediately, and arm the timer to call
* 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);
monitor_qapi_event_emit(event, qdict);
evstate = g_new(MonitorQAPIEventState, 1);
evstate->event = event;
evstate->data = data;
QINCREF(evstate->data);
evstate->qdict = NULL;
evstate->timer = timer_new_ns(QEMU_CLOCK_REALTIME,
monitor_qapi_event_handler,
evstate);
g_hash_table_add(monitor_qapi_event_state, evstate);
timer_mod_ns(evstate->timer, now + evconf->rate);
} }
} }
qemu_mutex_unlock(&monitor_lock); qemu_mutex_unlock(&monitor_lock);
} }
/* /*
* The callback invoked by QemuTimer when a delayed * This function runs evconf->rate ns after sending a throttled
* event is ready to be emitted * event.
* If another event has since been stored, send it.
*/ */
static void monitor_qapi_event_handler(void *opaque) static void monitor_qapi_event_handler(void *opaque)
{ {
MonitorQAPIEventState *evstate = opaque; MonitorQAPIEventState *evstate = opaque;
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
trace_monitor_protocol_event_handler(evstate->event, trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
evstate->data,
evstate->last,
now);
qemu_mutex_lock(&monitor_lock); qemu_mutex_lock(&monitor_lock);
if (evstate->data) {
monitor_qapi_event_emit(evstate->event, evstate->data); if (evstate->qdict) {
qobject_decref(evstate->data); int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
evstate->data = NULL;
monitor_qapi_event_emit(evstate->event, evstate->qdict);
QDECREF(evstate->qdict);
evstate->qdict = NULL;
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);
} }
evstate->last = now;
qemu_mutex_unlock(&monitor_lock); qemu_mutex_unlock(&monitor_lock);
} }
/* static unsigned int qapi_event_throttle_hash(const void *key)
* @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)
{ {
MonitorQAPIEventState *evstate; const MonitorQAPIEventState *evstate = key;
assert(event < QAPI_EVENT_MAX); unsigned int hash = evstate->event * 255;
evstate = &(monitor_qapi_event_state[event]); if (evstate->event == QAPI_EVENT_VSERPORT_CHANGE) {
hash += g_str_hash(qdict_get_str(evstate->data, "id"));
}
trace_monitor_protocol_event_throttle(event, rate); return hash;
evstate->event = event; }
assert(rate * SCALE_MS <= INT64_MAX);
evstate->rate = rate * SCALE_MS; static gboolean qapi_event_throttle_equal(const void *a, const void *b)
evstate->last = 0; {
evstate->data = NULL; const MonitorQAPIEventState *eva = a;
evstate->timer = timer_new(QEMU_CLOCK_REALTIME, const MonitorQAPIEventState *evb = b;
SCALE_MS,
monitor_qapi_event_handler, if (eva->event != evb->event) {
evstate); return FALSE;
}
if (eva->event == QAPI_EVENT_VSERPORT_CHANGE) {
return !strcmp(qdict_get_str(eva->data, "id"),
qdict_get_str(evb->data, "id"));
}
return TRUE;
} }
static void monitor_qapi_event_init(void) static void monitor_qapi_event_init(void)
{ {
/* Limit guest-triggerable events to 1 per second */ monitor_qapi_event_state = g_hash_table_new(qapi_event_throttle_hash,
monitor_qapi_event_throttle(QAPI_EVENT_RTC_CHANGE, 1000); qapi_event_throttle_equal);
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);
qmp_event_set_func_emit(monitor_qapi_event_queue); qmp_event_set_func_emit(monitor_qapi_event_queue);
} }

View File

@ -225,45 +225,45 @@ static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
if (!qobj || qobject_type(qobj) != QTYPE_QINT) { if (!qint) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"integer"); "integer");
return; return;
} }
*obj = qint_get_int(qobject_to_qint(qobj)); *obj = qint_get_int(qint);
} }
static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name, static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) { if (!qbool) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"boolean"); "boolean");
return; return;
} }
*obj = qbool_get_bool(qobject_to_qbool(qobj)); *obj = qbool_get_bool(qbool);
} }
static void qmp_input_type_str(Visitor *v, char **obj, const char *name, static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) { if (!qstr) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"string"); "string");
return; return;
} }
*obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj))); *obj = g_strdup(qstring_get_str(qstr));
} }
static void qmp_input_type_number(Visitor *v, double *obj, const char *name, static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
@ -271,19 +271,23 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true);
QInt *qint;
QFloat *qfloat;
if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT && qint = qobject_to_qint(qobj);
qobject_type(qobj) != QTYPE_QINT)) { if (qint) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", *obj = qint_get_int(qobject_to_qint(qobj));
"number");
return; return;
} }
if (qobject_type(qobj) == QTYPE_QINT) { qfloat = qobject_to_qfloat(qobj);
*obj = qint_get_int(qobject_to_qint(qobj)); if (qfloat) {
} else {
*obj = qfloat_get_double(qobject_to_qfloat(qobj)); *obj = qfloat_get_double(qobject_to_qfloat(qobj));
return;
} }
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"number");
} }
static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name, static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name,

View File

@ -573,7 +573,6 @@ static void process_command(GAState *s, QDict *req)
static void process_event(JSONMessageParser *parser, QList *tokens) static void process_event(JSONMessageParser *parser, QList *tokens)
{ {
GAState *s = container_of(parser, GAState, parser); GAState *s = container_of(parser, GAState, parser);
QObject *obj;
QDict *qdict; QDict *qdict;
Error *err = NULL; Error *err = NULL;
int ret; int ret;
@ -581,9 +580,9 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
g_assert(s && parser); g_assert(s && parser);
g_debug("process_event: called"); g_debug("process_event: called");
obj = json_parser_parse_err(tokens, NULL, &err); qdict = qobject_to_qdict(json_parser_parse_err(tokens, NULL, &err));
if (err || !obj || qobject_type(obj) != QTYPE_QDICT) { if (err || !qdict) {
qobject_decref(obj); QDECREF(qdict);
qdict = qdict_new(); qdict = qdict_new();
if (!err) { if (!err) {
g_warning("failed to parse event: unknown error"); g_warning("failed to parse event: unknown error");
@ -593,12 +592,8 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
} }
qdict_put_obj(qdict, "error", qmp_build_error_object(err)); qdict_put_obj(qdict, "error", qmp_build_error_object(err));
error_free(err); error_free(err);
} else {
qdict = qobject_to_qdict(obj);
} }
g_assert(qdict);
/* handle host->guest commands */ /* handle host->guest commands */
if (qdict_haskey(qdict, "execute")) { if (qdict_haskey(qdict, "execute")) {
process_command(s, qdict); process_command(s, qdict);

View File

@ -51,9 +51,9 @@ bool qbool_get_bool(const QBool *qb)
*/ */
QBool *qobject_to_qbool(const QObject *obj) QBool *qobject_to_qbool(const QObject *obj)
{ {
if (qobject_type(obj) != QTYPE_QBOOL) if (!obj || qobject_type(obj) != QTYPE_QBOOL) {
return NULL; return NULL;
}
return container_of(obj, QBool, base); return container_of(obj, QBool, base);
} }

View File

@ -46,9 +46,9 @@ QDict *qdict_new(void)
*/ */
QDict *qobject_to_qdict(const QObject *obj) QDict *qobject_to_qdict(const QObject *obj)
{ {
if (qobject_type(obj) != QTYPE_QDICT) if (!obj || qobject_type(obj) != QTYPE_QDICT) {
return NULL; return NULL;
}
return container_of(obj, QDict, base); return container_of(obj, QDict, base);
} }
@ -229,8 +229,7 @@ double qdict_get_double(const QDict *qdict, const char *key)
*/ */
int64_t qdict_get_int(const QDict *qdict, const char *key) int64_t qdict_get_int(const QDict *qdict, const char *key)
{ {
QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT); return qint_get_int(qobject_to_qint(qdict_get(qdict, key)));
return qint_get_int(qobject_to_qint(obj));
} }
/** /**
@ -243,8 +242,7 @@ int64_t qdict_get_int(const QDict *qdict, const char *key)
*/ */
bool qdict_get_bool(const QDict *qdict, const char *key) bool qdict_get_bool(const QDict *qdict, const char *key)
{ {
QObject *obj = qdict_get_obj(qdict, key, QTYPE_QBOOL); return qbool_get_bool(qobject_to_qbool(qdict_get(qdict, key)));
return qbool_get_bool(qobject_to_qbool(obj));
} }
/** /**
@ -270,7 +268,7 @@ QList *qdict_get_qlist(const QDict *qdict, const char *key)
*/ */
QDict *qdict_get_qdict(const QDict *qdict, const char *key) QDict *qdict_get_qdict(const QDict *qdict, const char *key)
{ {
return qobject_to_qdict(qdict_get_obj(qdict, key, QTYPE_QDICT)); return qobject_to_qdict(qdict_get(qdict, key));
} }
/** /**
@ -284,8 +282,7 @@ QDict *qdict_get_qdict(const QDict *qdict, const char *key)
*/ */
const char *qdict_get_str(const QDict *qdict, const char *key) const char *qdict_get_str(const QDict *qdict, const char *key)
{ {
QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING); return qstring_get_str(qobject_to_qstring(qdict_get(qdict, key)));
return qstring_get_str(qobject_to_qstring(obj));
} }
/** /**
@ -298,13 +295,9 @@ const char *qdict_get_str(const QDict *qdict, const char *key)
int64_t qdict_get_try_int(const QDict *qdict, const char *key, int64_t qdict_get_try_int(const QDict *qdict, const char *key,
int64_t def_value) int64_t def_value)
{ {
QObject *obj; QInt *qint = qobject_to_qint(qdict_get(qdict, key));
obj = qdict_get(qdict, key); return qint ? qint_get_int(qint) : def_value;
if (!obj || qobject_type(obj) != QTYPE_QINT)
return def_value;
return qint_get_int(qobject_to_qint(obj));
} }
/** /**
@ -316,13 +309,9 @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
*/ */
bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value) bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value)
{ {
QObject *obj; QBool *qbool = qobject_to_qbool(qdict_get(qdict, key));
obj = qdict_get(qdict, key); return qbool ? qbool_get_bool(qbool) : def_value;
if (!obj || qobject_type(obj) != QTYPE_QBOOL)
return def_value;
return qbool_get_bool(qobject_to_qbool(obj));
} }
/** /**
@ -335,13 +324,9 @@ bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value)
*/ */
const char *qdict_get_try_str(const QDict *qdict, const char *key) const char *qdict_get_try_str(const QDict *qdict, const char *key)
{ {
QObject *obj; QString *qstr = qobject_to_qstring(qdict_get(qdict, key));
obj = qdict_get(qdict, key); return qstr ? qstring_get_str(qstr) : NULL;
if (!obj || qobject_type(obj) != QTYPE_QSTRING)
return NULL;
return qstring_get_str(qobject_to_qstring(obj));
} }
/** /**

View File

@ -51,9 +51,9 @@ double qfloat_get_double(const QFloat *qf)
*/ */
QFloat *qobject_to_qfloat(const QObject *obj) QFloat *qobject_to_qfloat(const QObject *obj)
{ {
if (qobject_type(obj) != QTYPE_QFLOAT) if (!obj || qobject_type(obj) != QTYPE_QFLOAT) {
return NULL; return NULL;
}
return container_of(obj, QFloat, base); return container_of(obj, QFloat, base);
} }

View File

@ -50,9 +50,9 @@ int64_t qint_get_int(const QInt *qi)
*/ */
QInt *qobject_to_qint(const QObject *obj) QInt *qobject_to_qint(const QObject *obj)
{ {
if (qobject_type(obj) != QTYPE_QINT) if (!obj || qobject_type(obj) != QTYPE_QINT) {
return NULL; return NULL;
}
return container_of(obj, QInt, base); return container_of(obj, QInt, base);
} }

View File

@ -142,10 +142,9 @@ size_t qlist_size(const QList *qlist)
*/ */
QList *qobject_to_qlist(const QObject *obj) QList *qobject_to_qlist(const QObject *obj)
{ {
if (qobject_type(obj) != QTYPE_QLIST) { if (!obj || qobject_type(obj) != QTYPE_QLIST) {
return NULL; return NULL;
} }
return container_of(obj, QList, base); return container_of(obj, QList, base);
} }

View File

@ -117,9 +117,9 @@ void qstring_append_chr(QString *qstring, int c)
*/ */
QString *qobject_to_qstring(const QObject *obj) QString *qobject_to_qstring(const QObject *obj)
{ {
if (qobject_type(obj) != QTYPE_QSTRING) if (!obj || qobject_type(obj) != QTYPE_QSTRING) {
return NULL; return NULL;
}
return container_of(obj, QString, base); return container_of(obj, QString, base);
} }

View File

@ -1031,9 +1031,9 @@ esp_pci_sbac_write(uint32_t reg, uint32_t val) "sbac: 0x%8.8x -> 0x%8.8x"
# monitor.c # monitor.c
handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\"" handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
monitor_protocol_emitter(void *mon) "mon %p" monitor_protocol_emitter(void *mon) "mon %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_handler(uint32_t event, void *qdict) "event=%d data=%p"
monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p" 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_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64
monitor_protocol_event_throttle(uint32_t event, uint64_t rate) "event=%d rate=%" PRId64 monitor_protocol_event_throttle(uint32_t event, uint64_t rate) "event=%d rate=%" PRId64
# hw/net/opencores_eth.c # hw/net/opencores_eth.c