提交 e3800998 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
...@@ -666,22 +666,27 @@ command: ...@@ -666,22 +666,27 @@ command:
- They are executed in order, - They are executed in order,
- They run only in main thread of QEMU, - 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: When a command is executed with OOB, the following changes occur:
- They can be completed before a pending in-band command, - They can be completed before a pending in-band command,
- They run in a dedicated monitor thread, - 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: OOB command handlers must satisfy the following conditions:
- It executes extremely fast, - It terminates quickly,
- 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 does not invoke system calls that may block, - It does not invoke system calls that may block,
- It does not access guest RAM that may block when userfaultfd is - 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. If in doubt, do not implement OOB execution support.
......
...@@ -22,7 +22,16 @@ typedef enum { ...@@ -22,7 +22,16 @@ typedef enum {
CHR_EVENT_OPENED, /* new connection established */ CHR_EVENT_OPENED, /* new connection established */
CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */ CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
CHR_EVENT_MUX_OUT, /* mux-focus will move on */ 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; } QEMUChrEvent;
#define CHR_READ_BUF_LEN 4096 #define CHR_READ_BUF_LEN 4096
......
...@@ -541,37 +541,54 @@ struct QMPResponse { ...@@ -541,37 +541,54 @@ struct QMPResponse {
}; };
typedef struct QMPResponse 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 * Pop a QMPResponse from any monitor's response queue into @response.
* response.data is not NULL. * 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; Monitor *mon;
QObject *data = NULL; QObject *data = NULL;
qemu_mutex_lock(&monitor_lock); qemu_mutex_lock(&monitor_lock);
QTAILQ_FOREACH(mon, &mon_list, entry) { QTAILQ_FOREACH(mon, &mon_list, entry) {
qemu_mutex_lock(&mon->qmp.qmp_queue_lock); data = monitor_qmp_response_pop_one(mon);
data = g_queue_pop_head(mon->qmp.qmp_responses);
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
if (data) { if (data) {
response->mon = mon;
response->data = data;
break; break;
} }
} }
qemu_mutex_unlock(&monitor_lock); qemu_mutex_unlock(&monitor_lock);
return (QMPResponse) { .mon = mon, .data = data }; return data != NULL;
} }
static void monitor_qmp_bh_responder(void *opaque) static void monitor_qmp_bh_responder(void *opaque)
{ {
QMPResponse response; QMPResponse response;
while (true) { while (monitor_qmp_response_pop_any(&response)) {
response = monitor_qmp_response_pop_one();
if (!response.data) {
break;
}
monitor_json_emitter_raw(response.mon, response.data); monitor_json_emitter_raw(response.mon, response.data);
qobject_unref(response.data); qobject_unref(response.data);
} }
...@@ -4199,7 +4216,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj) ...@@ -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 * when we process one request on a specific monitor, we put that
* monitor to the end of mon_list queue. * 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; QMPRequest *req_obj = NULL;
Monitor *mon; Monitor *mon;
...@@ -4231,7 +4248,7 @@ static QMPRequest *monitor_qmp_requests_pop_one(void) ...@@ -4231,7 +4248,7 @@ static QMPRequest *monitor_qmp_requests_pop_one(void)
static void monitor_qmp_bh_dispatcher(void *data) 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) { if (req_obj) {
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: ""); 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) ...@@ -4458,6 +4475,13 @@ static void monitor_qmp_event(void *opaque, int event)
mon_refcount++; mon_refcount++;
break; break;
case CHR_EVENT_CLOSED: 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); monitor_qmp_cleanup_queues(mon);
json_message_parser_destroy(&mon->qmp.parser); json_message_parser_destroy(&mon->qmp.parser);
json_message_parser_init(&mon->qmp.parser, handle_qmp_command); json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
......
...@@ -33,6 +33,14 @@ _cleanup() ...@@ -33,6 +33,14 @@ _cleanup()
} }
trap "_cleanup; exit \$status" 0 1 2 3 15 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 # get standard environment, filters and checks
. ./common.rc . ./common.rc
. ./common.filter . ./common.filter
...@@ -464,7 +472,7 @@ echo "{'execute': 'qmp_capabilities'} ...@@ -464,7 +472,7 @@ echo "{'execute': 'qmp_capabilities'}
}}" \ }}" \
-incoming exec:'cat /dev/null' \ -incoming exec:'cat /dev/null' \
2>&1 \ 2>&1 \
| _filter_qmp | _filter_qemu_io | _filter_qmp | _filter_qemu_io | _filter_io_error
echo echo
# Image should not have been marked corrupt # Image should not have been marked corrupt
......
...@@ -428,7 +428,6 @@ QMP_VERSION ...@@ -428,7 +428,6 @@ QMP_VERSION
{"return": {}} {"return": {}}
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed 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}} {"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": ""}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册