QMP patches patches for 2021-02-04
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmAb5tsSHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTQMsQAJSlE7ns788RRhPH79kPh9yTFp8/DCWD vzNesSCMVp3o7a9DBPf2U2+oxHvF5HsLJG+2eqftouqlT4DWUtfYsBFPCsaHyPry KCAvrb3smP4GjedI5xpseyLKeW/c5SmNdwqahAD8ma/hAtJnoTBblphne88jYxj9 Q2l/dUzQuIgPy+jZ2DjxQYam9Vu2l3svNLvMGMe5L6/TAcSoNJV3jJ14Wz7GjoL2 If2LaHsvStFgMAniL16kv4OGd5c4jOy1QFdLGQQAbxavJsHQPhXGlq7xYRudXcdX vn2HH6WQHCfwFfxkPAqOgund3Bf/LacODD9+oNUhhWgeZUiZZfVGvHjmODp2gzHa b7m3YogIYHdr8taYemwEzuuhOR9I1gE/v4UvTokd3eXRY6HhkjTpwWjV06Codrhq DKAPcjRZ1Q4XZVWAURZBz7icGXc15EuuneC6ygIZDrR1Ez73xfJ82WUscNx6MujX 8pOPgNmQtVCRqMFRlfvZl1cVCu9Qh/1pkeDDWjR80OxvNB4iYQKfvB1GLxZJL3Vx zsH8oVajd+8sXdUyUA1JTM5r7b9/6TJOlktHhZ9F3TDDVbwhmcBPgTWvRa139SVf SUkAMZjBFx/lsuuR8S3aOG+NftYQZs3TjPqWBklpXe1nEwOxjBipPDAZMq5xccVf DVrE5Ay2/1T0 =l1y4 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qmp-2021-02-04' into staging QMP patches patches for 2021-02-04 # gpg: Signature made Thu 04 Feb 2021 12:21:47 GMT # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qmp-2021-02-04: qmp: Resume OOB-enabled monitor before processing the request qmp: Add more tracepoints qmp: Fix up comments after commit 9ce44e2ce2 docs/interop/qmp-spec: Document the request queue limit qobject: braces {} are necessary for all arms of this statement qobject: spaces required around that operators qobject: code indent should never use tabs qobject: open brace '{' following struct go on the same line monitor/qmp-cmds.c: Don't include ui/vnc.h Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1ba089f225
@ -133,9 +133,11 @@ to pass "id" with out-of-band commands. Passing it with all commands
|
|||||||
is recommended for clients that accept capability "oob".
|
is recommended for clients that accept capability "oob".
|
||||||
|
|
||||||
If the client sends in-band commands faster than the server can
|
If the client sends in-band commands faster than the server can
|
||||||
execute them, the server will stop reading the requests from the QMP
|
execute them, the server will stop reading requests until the request
|
||||||
channel until the request queue length is reduced to an acceptable
|
queue length is reduced to an acceptable range.
|
||||||
range.
|
|
||||||
|
To ensure commands to be executed out-of-band get read and executed,
|
||||||
|
the client should have at most eight in-band commands in flight.
|
||||||
|
|
||||||
Only a few commands support out-of-band execution. The ones that do
|
Only a few commands support out-of-band execution. The ones that do
|
||||||
have "allow-oob": true in output of query-qmp-schema.
|
have "allow-oob": true in output of query-qmp-schema.
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "qemu/uuid.h"
|
#include "qemu/uuid.h"
|
||||||
#include "chardev/char.h"
|
#include "chardev/char.h"
|
||||||
#include "ui/qemu-spice.h"
|
#include "ui/qemu-spice.h"
|
||||||
#include "ui/vnc.h"
|
#include "ui/console.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "sysemu/runstate-action.h"
|
#include "sysemu/runstate-action.h"
|
||||||
|
@ -79,7 +79,7 @@ static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
|
|||||||
qemu_mutex_lock(&mon->qmp_queue_lock);
|
qemu_mutex_lock(&mon->qmp_queue_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same condition as in monitor_qmp_bh_dispatcher(), but before
|
* Same condition as in monitor_qmp_dispatcher_co(), but before
|
||||||
* removing an element from the queue (hence no `- 1`).
|
* removing an element from the queue (hence no `- 1`).
|
||||||
* Also, the queue should not be empty either, otherwise the
|
* Also, the queue should not be empty either, otherwise the
|
||||||
* monitor hasn't been suspended yet (or was already resumed).
|
* monitor hasn't been suspended yet (or was already resumed).
|
||||||
@ -113,6 +113,7 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp)
|
|||||||
|
|
||||||
json = qobject_to_json_pretty(data, mon->pretty);
|
json = qobject_to_json_pretty(data, mon->pretty);
|
||||||
assert(json != NULL);
|
assert(json != NULL);
|
||||||
|
trace_monitor_qmp_respond(mon, json->str);
|
||||||
|
|
||||||
g_string_append_c(json, '\n');
|
g_string_append_c(json, '\n');
|
||||||
monitor_puts(&mon->common, json->str);
|
monitor_puts(&mon->common, json->str);
|
||||||
@ -213,7 +214,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
|
|||||||
{
|
{
|
||||||
QMPRequest *req_obj = NULL;
|
QMPRequest *req_obj = NULL;
|
||||||
QDict *rsp;
|
QDict *rsp;
|
||||||
bool need_resume;
|
bool oob_enabled;
|
||||||
MonitorQMP *mon;
|
MonitorQMP *mon;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -251,6 +252,9 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_monitor_qmp_in_band_dequeue(req_obj,
|
||||||
|
req_obj->mon->qmp_requests->length);
|
||||||
|
|
||||||
if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) {
|
if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) {
|
||||||
/*
|
/*
|
||||||
* Someone rescheduled us (probably because a new requests
|
* Someone rescheduled us (probably because a new requests
|
||||||
@ -269,11 +273,32 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
|
|||||||
aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
|
aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @req_obj has a request, we hold req_obj->mon->qmp_queue_lock
|
||||||
|
*/
|
||||||
|
|
||||||
mon = req_obj->mon;
|
mon = req_obj->mon;
|
||||||
/* qmp_oob_enabled() might change after "qmp_capabilities" */
|
|
||||||
need_resume = !qmp_oob_enabled(mon) ||
|
/*
|
||||||
mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
|
* We need to resume the monitor if handle_qmp_command()
|
||||||
|
* suspended it. Two cases:
|
||||||
|
* 1. OOB enabled: mon->qmp_requests has no more space
|
||||||
|
* Resume right away, so that OOB commands can get executed while
|
||||||
|
* this request is being processed.
|
||||||
|
* 2. OOB disabled: always
|
||||||
|
* Resume only after we're done processing the request,
|
||||||
|
* We need to save qmp_oob_enabled() for later, because
|
||||||
|
* qmp_qmp_capabilities() can change it.
|
||||||
|
*/
|
||||||
|
oob_enabled = qmp_oob_enabled(mon);
|
||||||
|
if (oob_enabled
|
||||||
|
&& mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
|
||||||
|
monitor_resume(&mon->common);
|
||||||
|
}
|
||||||
|
|
||||||
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
||||||
|
|
||||||
|
/* Process request */
|
||||||
if (req_obj->req) {
|
if (req_obj->req) {
|
||||||
if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) {
|
if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) {
|
||||||
QDict *qdict = qobject_to(QDict, req_obj->req);
|
QDict *qdict = qobject_to(QDict, req_obj->req);
|
||||||
@ -287,16 +312,17 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
|
|||||||
monitor_qmp_dispatch(mon, req_obj->req);
|
monitor_qmp_dispatch(mon, req_obj->req);
|
||||||
} else {
|
} else {
|
||||||
assert(req_obj->err);
|
assert(req_obj->err);
|
||||||
|
trace_monitor_qmp_err_in_band(error_get_pretty(req_obj->err));
|
||||||
rsp = qmp_error_response(req_obj->err);
|
rsp = qmp_error_response(req_obj->err);
|
||||||
req_obj->err = NULL;
|
req_obj->err = NULL;
|
||||||
monitor_qmp_respond(mon, rsp);
|
monitor_qmp_respond(mon, rsp);
|
||||||
qobject_unref(rsp);
|
qobject_unref(rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_resume) {
|
if (!oob_enabled) {
|
||||||
/* Pairs with the monitor_suspend() in handle_qmp_command() */
|
|
||||||
monitor_resume(&mon->common);
|
monitor_resume(&mon->common);
|
||||||
}
|
}
|
||||||
|
|
||||||
qmp_request_free(req_obj);
|
qmp_request_free(req_obj);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -349,7 +375,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Suspend the monitor when we can't queue more requests after
|
* Suspend the monitor when we can't queue more requests after
|
||||||
* this one. Dequeuing in monitor_qmp_bh_dispatcher() or
|
* this one. Dequeuing in monitor_qmp_dispatcher_co() or
|
||||||
* monitor_qmp_cleanup_queue_and_resume() will resume it.
|
* monitor_qmp_cleanup_queue_and_resume() will resume it.
|
||||||
* Note that when OOB is disabled, we queue at most one command,
|
* Note that when OOB is disabled, we queue at most one command,
|
||||||
* for backward compatibility.
|
* for backward compatibility.
|
||||||
@ -364,6 +390,8 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
|
|||||||
* handled in time order. Ownership for req_obj, req,
|
* handled in time order. Ownership for req_obj, req,
|
||||||
* etc. will be delivered to the handler side.
|
* etc. will be delivered to the handler side.
|
||||||
*/
|
*/
|
||||||
|
trace_monitor_qmp_in_band_enqueue(req_obj, mon,
|
||||||
|
mon->qmp_requests->length);
|
||||||
assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
|
assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
|
||||||
g_queue_push_tail(mon->qmp_requests, req_obj);
|
g_queue_push_tail(mon->qmp_requests, req_obj);
|
||||||
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
qemu_mutex_unlock(&mon->qmp_queue_lock);
|
||||||
|
@ -10,6 +10,10 @@ monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=
|
|||||||
monitor_suspend(void *ptr, int cnt) "mon %p: %d"
|
monitor_suspend(void *ptr, int cnt) "mon %p: %d"
|
||||||
|
|
||||||
# qmp.c
|
# qmp.c
|
||||||
|
monitor_qmp_in_band_enqueue(void *req, void *mon, unsigned len) "%p mon %p len %u"
|
||||||
|
monitor_qmp_in_band_dequeue(void *req, unsigned len) "%p len %u"
|
||||||
monitor_qmp_cmd_in_band(const char *id) "%s"
|
monitor_qmp_cmd_in_band(const char *id) "%s"
|
||||||
|
monitor_qmp_err_in_band(const char *desc) "%s"
|
||||||
monitor_qmp_cmd_out_of_band(const char *id) "%s"
|
monitor_qmp_cmd_out_of_band(const char *id) "%s"
|
||||||
|
monitor_qmp_respond(void *mon, const char *json) "mon %p resp: %s"
|
||||||
handle_qmp_command(void *mon, const char *req) "mon %p req: %s"
|
handle_qmp_command(void *mon, const char *req) "mon %p req: %s"
|
||||||
|
@ -31,8 +31,7 @@ struct JSONToken {
|
|||||||
char str[];
|
char str[];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct JSONParserContext
|
typedef struct JSONParserContext {
|
||||||
{
|
|
||||||
Error *err;
|
Error *err;
|
||||||
JSONToken *current;
|
JSONToken *current;
|
||||||
GQueue *buf;
|
GQueue *buf;
|
||||||
|
@ -39,12 +39,13 @@ QDict *qdict_new(void)
|
|||||||
*/
|
*/
|
||||||
static unsigned int tdb_hash(const char *name)
|
static unsigned int tdb_hash(const char *name)
|
||||||
{
|
{
|
||||||
unsigned value; /* Used to compute the hash value. */
|
unsigned value; /* Used to compute the hash value. */
|
||||||
unsigned i; /* Used to cycle through random values. */
|
unsigned i; /* Used to cycle through random values. */
|
||||||
|
|
||||||
/* Set the initial value from the key size. */
|
/* Set the initial value from the key size. */
|
||||||
for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
|
for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) {
|
||||||
value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
|
value = (value + (((const unsigned char *)name)[i] << (i * 5 % 24)));
|
||||||
|
}
|
||||||
|
|
||||||
return (1103515243 * value + 12345);
|
return (1103515243 * value + 12345);
|
||||||
}
|
}
|
||||||
@ -93,8 +94,9 @@ static QDictEntry *qdict_find(const QDict *qdict,
|
|||||||
QDictEntry *entry;
|
QDictEntry *entry;
|
||||||
|
|
||||||
QLIST_FOREACH(entry, &qdict->table[bucket], next)
|
QLIST_FOREACH(entry, &qdict->table[bucket], next)
|
||||||
if (!strcmp(entry->key, key))
|
if (!strcmp(entry->key, key)) {
|
||||||
return entry;
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,7 @@
|
|||||||
#include "qapi/qmp/qnum.h"
|
#include "qapi/qmp/qnum.h"
|
||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
|
|
||||||
typedef struct JSONParsingState
|
typedef struct JSONParsingState {
|
||||||
{
|
|
||||||
JSONMessageParser parser;
|
JSONMessageParser parser;
|
||||||
QObject *result;
|
QObject *result;
|
||||||
Error *err;
|
Error *err;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user