aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-06-30 17:30:09 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-06-30 17:30:09 +0100
commite3800998e66c13b24d8cc8a06fdcc8d03cd408fc (patch)
tree7a4eeaf3ce8c8c362403381ecc4f7bd6228105b0
parent6f4fa0998fd13bd8a533f38ee69774ecad6911b6 (diff)
parent4bfa7974d90a0cbad29c0a27334d02cbd37bb23d (diff)
Merge remote-tracking branch 'remotes/armbru/tags/pull-monitor-2018-06-30' into staging
Monitor patches for 2018-06-30 # gpg: Signature made Sat 30 Jun 2018 17:22:12 BST # gpg: using RSA key 3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-monitor-2018-06-30: docs: mention shared state protect for OOB tests: iotests: drop some stderr line monitor: flush qmp responses when CLOSED monitor: rename *_pop_one to *_pop_any chardev: comment details for CLOSED event Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--docs/devel/qapi-code-gen.txt17
-rw-r--r--include/chardev/char.h11
-rw-r--r--monitor.c52
-rwxr-xr-xtests/qemu-iotests/06010
-rw-r--r--tests/qemu-iotests/060.out1
5 files changed, 68 insertions, 23 deletions
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 88a70e4d45..94a7e8f4d0 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -666,22 +666,27 @@ command:
- They are executed in order,
- They run only in main thread of QEMU,
-- They have the BQL taken during execution.
+- They run with the BQL held.
When a command is executed with OOB, the following changes occur:
- They can be completed before a pending in-band command,
- They run in a dedicated monitor thread,
-- They do not take the BQL during execution.
+- They run with the BQL not held.
OOB command handlers must satisfy the following conditions:
-- It executes extremely fast,
-- It does not take any lock, or, it can take very small locks if all
- critical regions also follow the rules for OOB command handler code,
+- It terminates quickly,
- It does not invoke system calls that may block,
- It does not access guest RAM that may block when userfaultfd is
- enabled for postcopy live migration.
+ enabled for postcopy live migration,
+- It takes only "fast" locks, i.e. all critical sections protected by
+ any lock it takes also satisfy the conditions for OOB command
+ handler code.
+
+The restrictions on locking limit access to shared state. Such access
+requires synchronization, but OOB commands can't take the BQL or any
+other "slow" lock.
If in doubt, do not implement OOB execution support.
diff --git a/include/chardev/char.h b/include/chardev/char.h
index 04de45795e..6f0576e214 100644
--- a/include/chardev/char.h
+++ b/include/chardev/char.h
@@ -22,7 +22,16 @@ typedef enum {
CHR_EVENT_OPENED, /* new connection established */
CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
CHR_EVENT_MUX_OUT, /* mux-focus will move on */
- CHR_EVENT_CLOSED /* connection closed */
+ CHR_EVENT_CLOSED /* connection closed. NOTE: currently this event
+ * is only bound to the read port of the chardev.
+ * Normally the read port and write port of a
+ * chardev should be the same, but it can be
+ * different, e.g., for fd chardevs, when the two
+ * fds are different. So when we received the
+ * CLOSED event it's still possible that the out
+ * port is still open. TODO: we should only send
+ * the CLOSED event when both ports are closed.
+ */
} QEMUChrEvent;
#define CHR_READ_BUF_LEN 4096
diff --git a/monitor.c b/monitor.c
index 7b473aad1f..567668a0e7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -541,37 +541,54 @@ struct QMPResponse {
};
typedef struct QMPResponse QMPResponse;
+static QObject *monitor_qmp_response_pop_one(Monitor *mon)
+{
+ QObject *data;
+
+ qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
+ data = g_queue_pop_head(mon->qmp.qmp_responses);
+ qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+
+ return data;
+}
+
+static void monitor_qmp_response_flush(Monitor *mon)
+{
+ QObject *data;
+
+ while ((data = monitor_qmp_response_pop_one(mon))) {
+ monitor_json_emitter_raw(mon, data);
+ qobject_unref(data);
+ }
+}
+
/*
- * Return one QMPResponse. The response is only valid if
- * response.data is not NULL.
+ * Pop a QMPResponse from any monitor's response queue into @response.
+ * Return false if all the queues are empty; else true.
*/
-static QMPResponse monitor_qmp_response_pop_one(void)
+static bool monitor_qmp_response_pop_any(QMPResponse *response)
{
Monitor *mon;
QObject *data = NULL;
qemu_mutex_lock(&monitor_lock);
QTAILQ_FOREACH(mon, &mon_list, entry) {
- qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
- data = g_queue_pop_head(mon->qmp.qmp_responses);
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+ data = monitor_qmp_response_pop_one(mon);
if (data) {
+ response->mon = mon;
+ response->data = data;
break;
}
}
qemu_mutex_unlock(&monitor_lock);
- return (QMPResponse) { .mon = mon, .data = data };
+ return data != NULL;
}
static void monitor_qmp_bh_responder(void *opaque)
{
QMPResponse response;
- while (true) {
- response = monitor_qmp_response_pop_one();
- if (!response.data) {
- break;
- }
+ while (monitor_qmp_response_pop_any(&response)) {
monitor_json_emitter_raw(response.mon, response.data);
qobject_unref(response.data);
}
@@ -4199,7 +4216,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj)
* when we process one request on a specific monitor, we put that
* monitor to the end of mon_list queue.
*/
-static QMPRequest *monitor_qmp_requests_pop_one(void)
+static QMPRequest *monitor_qmp_requests_pop_any(void)
{
QMPRequest *req_obj = NULL;
Monitor *mon;
@@ -4231,7 +4248,7 @@ static QMPRequest *monitor_qmp_requests_pop_one(void)
static void monitor_qmp_bh_dispatcher(void *data)
{
- QMPRequest *req_obj = monitor_qmp_requests_pop_one();
+ QMPRequest *req_obj = monitor_qmp_requests_pop_any();
if (req_obj) {
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
@@ -4458,6 +4475,13 @@ static void monitor_qmp_event(void *opaque, int event)
mon_refcount++;
break;
case CHR_EVENT_CLOSED:
+ /*
+ * Note: this is only useful when the output of the chardev
+ * backend is still open. For example, when the backend is
+ * stdio, it's possible that stdout is still open when stdin
+ * is closed.
+ */
+ monitor_qmp_response_flush(mon);
monitor_qmp_cleanup_queues(mon);
json_message_parser_destroy(&mon->qmp.parser);
json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index 7bdf609f3f..74ad371885 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -33,6 +33,14 @@ _cleanup()
}
trap "_cleanup; exit \$status" 0 1 2 3 15
+# Sometimes the error line might be dumped before/after an event
+# randomly. Mask it out for specific test that may trigger this
+# uncertainty for current test for now.
+_filter_io_error()
+{
+ sed '/Input\/output error/d'
+}
+
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
@@ -464,7 +472,7 @@ echo "{'execute': 'qmp_capabilities'}
}}" \
-incoming exec:'cat /dev/null' \
2>&1 \
- | _filter_qmp | _filter_qemu_io
+ | _filter_qmp | _filter_qemu_io | _filter_io_error
echo
# Image should not have been marked corrupt
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index bff023d889..d67c6234a4 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -428,7 +428,6 @@ QMP_VERSION
{"return": {}}
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
-read failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}