Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/armbru/tags/pull-qmp-2021-02-04…
Browse files Browse the repository at this point in the history
…' 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 9ce44e2
  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>
  • Loading branch information
pm215 committed Feb 4, 2021
2 parents db754f8 + 88daf09 commit 1ba089f
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 21 deletions.
8 changes: 5 additions & 3 deletions docs/interop/qmp-spec.txt
Expand Up @@ -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".

If the client sends in-band commands faster than the server can
execute them, the server will stop reading the requests from the QMP
channel until the request queue length is reduced to an acceptable
range.
execute them, the server will stop reading requests until the request
queue length is reduced to an acceptable 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
have "allow-oob": true in output of query-qmp-schema.
Expand Down
2 changes: 1 addition & 1 deletion monitor/qmp-cmds.c
Expand Up @@ -23,7 +23,7 @@
#include "qemu/uuid.h"
#include "chardev/char.h"
#include "ui/qemu-spice.h"
#include "ui/vnc.h"
#include "ui/console.h"
#include "sysemu/kvm.h"
#include "sysemu/runstate.h"
#include "sysemu/runstate-action.h"
Expand Down
44 changes: 36 additions & 8 deletions monitor/qmp.c
Expand Up @@ -79,7 +79,7 @@ static void monitor_qmp_cleanup_queue_and_resume(MonitorQMP *mon)
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`).
* Also, the queue should not be empty either, otherwise the
* monitor hasn't been suspended yet (or was already resumed).
Expand Down Expand Up @@ -113,6 +113,7 @@ void qmp_send_response(MonitorQMP *mon, const QDict *rsp)

json = qobject_to_json_pretty(data, mon->pretty);
assert(json != NULL);
trace_monitor_qmp_respond(mon, json->str);

g_string_append_c(json, '\n');
monitor_puts(&mon->common, json->str);
Expand Down Expand Up @@ -213,7 +214,7 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
{
QMPRequest *req_obj = NULL;
QDict *rsp;
bool need_resume;
bool oob_enabled;
MonitorQMP *mon;

while (true) {
Expand Down Expand Up @@ -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) {
/*
* Someone rescheduled us (probably because a new requests
Expand All @@ -269,11 +273,32 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
qemu_coroutine_yield();

/*
* @req_obj has a request, we hold req_obj->mon->qmp_queue_lock
*/

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);

/* Process request */
if (req_obj->req) {
if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) {
QDict *qdict = qobject_to(QDict, req_obj->req);
Expand All @@ -287,16 +312,17 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
monitor_qmp_dispatch(mon, req_obj->req);
} else {
assert(req_obj->err);
trace_monitor_qmp_err_in_band(error_get_pretty(req_obj->err));
rsp = qmp_error_response(req_obj->err);
req_obj->err = NULL;
monitor_qmp_respond(mon, rsp);
qobject_unref(rsp);
}

if (need_resume) {
/* Pairs with the monitor_suspend() in handle_qmp_command() */
if (!oob_enabled) {
monitor_resume(&mon->common);
}

qmp_request_free(req_obj);

/*
Expand Down Expand Up @@ -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
* 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.
* Note that when OOB is disabled, we queue at most one command,
* for backward compatibility.
Expand All @@ -364,6 +390,8 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
* handled in time order. Ownership for req_obj, req,
* 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);
g_queue_push_tail(mon->qmp_requests, req_obj);
qemu_mutex_unlock(&mon->qmp_queue_lock);
Expand Down
4 changes: 4 additions & 0 deletions monitor/trace-events
Expand Up @@ -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"

# 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_err_in_band(const char *desc) "%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"
3 changes: 1 addition & 2 deletions qobject/json-parser.c
Expand Up @@ -31,8 +31,7 @@ struct JSONToken {
char str[];
};

typedef struct JSONParserContext
{
typedef struct JSONParserContext {
Error *err;
JSONToken *current;
GQueue *buf;
Expand Down
12 changes: 7 additions & 5 deletions qobject/qdict.c
Expand Up @@ -39,12 +39,13 @@ QDict *qdict_new(void)
*/
static unsigned int tdb_hash(const char *name)
{
unsigned value; /* Used to compute the hash value. */
unsigned i; /* Used to cycle through random values. */
unsigned value; /* Used to compute the hash value. */
unsigned i; /* Used to cycle through random values. */

/* Set the initial value from the key size. */
for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) {
value = (value + (((const unsigned char *)name)[i] << (i * 5 % 24)));
}

return (1103515243 * value + 12345);
}
Expand Down Expand Up @@ -93,8 +94,9 @@ static QDictEntry *qdict_find(const QDict *qdict,
QDictEntry *entry;

QLIST_FOREACH(entry, &qdict->table[bucket], next)
if (!strcmp(entry->key, key))
if (!strcmp(entry->key, key)) {
return entry;
}

return NULL;
}
Expand Down
3 changes: 1 addition & 2 deletions qobject/qjson.c
Expand Up @@ -22,8 +22,7 @@
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"

typedef struct JSONParsingState
{
typedef struct JSONParsingState {
JSONMessageParser parser;
QObject *result;
Error *err;
Expand Down

0 comments on commit 1ba089f

Please sign in to comment.