1
The following changes since commit 6c769690ac845fa62642a5f93b4e4bd906adab95:
1
The following changes since commit 801f3db7564dcce8a37a70833c0abe40ec19f8ce:
2
2
3
Merge remote-tracking branch 'remotes/vsementsov/tags/pull-simplebench-2021-05-04' into staging (2021-05-21 12:02:34 +0100)
3
Merge remote-tracking branch 'remotes/philmd/tags/kconfig-20210720' into staging (2021-07-20 19:30:28 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 0a6f0c76a030710780ce10d6347a70f098024d21:
9
for you to fetch changes up to d7ddd0a1618a75b31dc308bb37365ce1da972154:
10
10
11
coroutine-sleep: introduce qemu_co_sleep (2021-05-21 18:22:33 +0100)
11
linux-aio: limit the batch size using `aio-max-batch` parameter (2021-07-21 13:47:50 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Pull request
15
15
16
(Resent due to an email preparation mistake.)
16
Stefano's performance regression fix for commit 2558cb8dd4 ("linux-aio:
17
increasing MAX_EVENTS to a larger hardcoded value").
17
18
18
----------------------------------------------------------------
19
----------------------------------------------------------------
19
20
20
Paolo Bonzini (6):
21
Stefano Garzarella (3):
21
coroutine-sleep: use a stack-allocated timer
22
iothread: generalize iothread_set_param/iothread_get_param
22
coroutine-sleep: disallow NULL QemuCoSleepState** argument
23
iothread: add aio-max-batch parameter
23
coroutine-sleep: allow qemu_co_sleep_wake that wakes nothing
24
linux-aio: limit the batch size using `aio-max-batch` parameter
24
coroutine-sleep: move timer out of QemuCoSleepState
25
coroutine-sleep: replace QemuCoSleepState pointer with struct in the
26
API
27
coroutine-sleep: introduce qemu_co_sleep
28
25
29
Philippe Mathieu-Daudé (1):
26
qapi/misc.json | 6 ++-
30
bitops.h: Improve find_xxx_bit() documentation
27
qapi/qom.json | 7 +++-
31
28
include/block/aio.h | 12 ++++++
32
Zenghui Yu (1):
29
include/sysemu/iothread.h | 3 ++
33
multi-process: Initialize variables declared with g_auto*
30
block/linux-aio.c | 9 ++++-
34
31
iothread.c | 82 ++++++++++++++++++++++++++++++++++-----
35
include/qemu/bitops.h | 15 ++++++--
32
monitor/hmp-cmds.c | 2 +
36
include/qemu/coroutine.h | 27 ++++++++-----
33
util/aio-posix.c | 12 ++++++
37
block/block-copy.c | 10 ++---
34
util/aio-win32.c | 5 +++
38
block/nbd.c | 14 +++----
35
util/async.c | 2 +
39
hw/remote/memory.c | 5 +--
36
qemu-options.hx | 8 +++-
40
hw/remote/proxy.c | 3 +-
37
11 files changed, 134 insertions(+), 14 deletions(-)
41
util/qemu-coroutine-sleep.c | 75 +++++++++++++++++++------------------
42
7 files changed, 79 insertions(+), 70 deletions(-)
43
38
44
--
39
--
45
2.31.1
40
2.31.1
46
41
diff view generated by jsdifflib
Deleted patch
1
From: Zenghui Yu <yuzenghui@huawei.com>
2
1
3
Quote docs/devel/style.rst (section "Automatic memory deallocation"):
4
5
* Variables declared with g_auto* MUST always be initialized,
6
otherwise the cleanup function will use uninitialized stack memory
7
8
Initialize @name properly to get rid of the compilation error (using
9
gcc-7.3.0 on CentOS):
10
11
../hw/remote/proxy.c: In function 'pci_proxy_dev_realize':
12
/usr/include/glib-2.0/glib/glib-autocleanups.h:28:3: error: 'name' may be used uninitialized in this function [-Werror=maybe-uninitialized]
13
g_free (*pp);
14
^~~~~~~~~~~~
15
../hw/remote/proxy.c:350:30: note: 'name' was declared here
16
g_autofree char *name;
17
^~~~
18
19
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
20
Reviewed-by: Jagannathan Raman <jag.raman@oracle.com>
21
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
22
Reviewed-by: Miroslav Rezanina <mrezanin@redhat.com>
23
Message-id: 20210312112143.1369-1-yuzenghui@huawei.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
---
26
hw/remote/memory.c | 5 ++---
27
hw/remote/proxy.c | 3 +--
28
2 files changed, 3 insertions(+), 5 deletions(-)
29
30
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/remote/memory.c
33
+++ b/hw/remote/memory.c
34
@@ -XXX,XX +XXX,XX @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp)
35
36
remote_sysmem_reset();
37
38
- for (region = 0; region < msg->num_fds; region++) {
39
- g_autofree char *name;
40
+ for (region = 0; region < msg->num_fds; region++, suffix++) {
41
+ g_autofree char *name = g_strdup_printf("remote-mem-%u", suffix);
42
subregion = g_new(MemoryRegion, 1);
43
- name = g_strdup_printf("remote-mem-%u", suffix++);
44
memory_region_init_ram_from_fd(subregion, NULL,
45
name, sysmem_info->sizes[region],
46
true, msg->fds[region],
47
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/remote/proxy.c
50
+++ b/hw/remote/proxy.c
51
@@ -XXX,XX +XXX,XX @@ static void probe_pci_info(PCIDevice *dev, Error **errp)
52
PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
53
54
if (size) {
55
- g_autofree char *name;
56
+ g_autofree char *name = g_strdup_printf("bar-region-%d", i);
57
pdev->region[i].dev = pdev;
58
pdev->region[i].present = true;
59
if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) {
60
pdev->region[i].memory = true;
61
}
62
- name = g_strdup_printf("bar-region-%d", i);
63
memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev),
64
&proxy_mr_ops, &pdev->region[i],
65
name, size);
66
--
67
2.31.1
68
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
Document the following functions return the bitmap size
4
if no matching bit is found:
5
6
- find_first_bit
7
- find_next_bit
8
- find_last_bit
9
- find_first_zero_bit
10
- find_next_zero_bit
11
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-id: 20210510200758.2623154-2-philmd@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
18
include/qemu/bitops.h | 15 ++++++++++++---
19
1 file changed, 12 insertions(+), 3 deletions(-)
20
21
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/qemu/bitops.h
24
+++ b/include/qemu/bitops.h
25
@@ -XXX,XX +XXX,XX @@ static inline int test_bit(long nr, const unsigned long *addr)
26
* @addr: The address to start the search at
27
* @size: The maximum size to search
28
*
29
- * Returns the bit number of the first set bit, or size.
30
+ * Returns the bit number of the last set bit,
31
+ * or @size if there is no set bit in the bitmap.
32
*/
33
unsigned long find_last_bit(const unsigned long *addr,
34
unsigned long size);
35
@@ -XXX,XX +XXX,XX @@ unsigned long find_last_bit(const unsigned long *addr,
36
* @addr: The address to base the search on
37
* @offset: The bitnumber to start searching at
38
* @size: The bitmap size in bits
39
+ *
40
+ * Returns the bit number of the next set bit,
41
+ * or @size if there are no further set bits in the bitmap.
42
*/
43
unsigned long find_next_bit(const unsigned long *addr,
44
unsigned long size,
45
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_bit(const unsigned long *addr,
46
* @addr: The address to base the search on
47
* @offset: The bitnumber to start searching at
48
* @size: The bitmap size in bits
49
+ *
50
+ * Returns the bit number of the next cleared bit,
51
+ * or @size if there are no further clear bits in the bitmap.
52
*/
53
54
unsigned long find_next_zero_bit(const unsigned long *addr,
55
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_zero_bit(const unsigned long *addr,
56
* @addr: The address to start the search at
57
* @size: The maximum size to search
58
*
59
- * Returns the bit number of the first set bit.
60
+ * Returns the bit number of the first set bit,
61
+ * or @size if there is no set bit in the bitmap.
62
*/
63
static inline unsigned long find_first_bit(const unsigned long *addr,
64
unsigned long size)
65
@@ -XXX,XX +XXX,XX @@ static inline unsigned long find_first_bit(const unsigned long *addr,
66
* @addr: The address to start the search at
67
* @size: The maximum size to search
68
*
69
- * Returns the bit number of the first cleared bit.
70
+ * Returns the bit number of the first cleared bit,
71
+ * or @size if there is no clear bit in the bitmap.
72
*/
73
static inline unsigned long find_first_zero_bit(const unsigned long *addr,
74
unsigned long size)
75
--
76
2.31.1
77
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
The lifetime of the timer is well-known (it cannot outlive
4
qemu_co_sleep_ns_wakeable, because it's deleted by the time the
5
coroutine resumes), so it is not necessary to place it on the heap.
6
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-id: 20210517100548.28806-2-pbonzini@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
util/qemu-coroutine-sleep.c | 9 ++++-----
13
1 file changed, 4 insertions(+), 5 deletions(-)
14
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/util/qemu-coroutine-sleep.c
18
+++ b/util/qemu-coroutine-sleep.c
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
20
21
struct QemuCoSleepState {
22
Coroutine *co;
23
- QEMUTimer *ts;
24
+ QEMUTimer ts;
25
QemuCoSleepState **user_state_pointer;
26
};
27
28
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
29
if (sleep_state->user_state_pointer) {
30
*sleep_state->user_state_pointer = NULL;
31
}
32
- timer_del(sleep_state->ts);
33
+ timer_del(&sleep_state->ts);
34
aio_co_wake(sleep_state->co);
35
}
36
37
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
38
AioContext *ctx = qemu_get_current_aio_context();
39
QemuCoSleepState state = {
40
.co = qemu_coroutine_self(),
41
- .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state),
42
.user_state_pointer = sleep_state,
43
};
44
45
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
46
abort();
47
}
48
49
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
50
if (sleep_state) {
51
*sleep_state = &state;
52
}
53
- timer_mod(state.ts, qemu_clock_get_ns(type) + ns);
54
+ timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
55
qemu_coroutine_yield();
56
if (sleep_state) {
57
/*
58
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
59
*/
60
assert(*sleep_state == NULL);
61
}
62
- timer_free(state.ts);
63
}
64
--
65
2.31.1
66
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
This simplification is enabled by the previous patch. Now aio_co_wake
3
Changes in preparation for next patches where we add a new
4
will only be called once, therefore we do not care about a spurious
4
parameter not related to the poll mechanism.
5
firing of the timer after a qemu_co_sleep_wake.
6
5
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Let's add two new generic functions (iothread_set_param and
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
iothread_get_param) that we use to set and get IOThread
9
Message-id: 20210517100548.28806-5-pbonzini@redhat.com
8
parameters.
9
10
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
11
Message-id: 20210721094211.69853-2-sgarzare@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
13
---
12
util/qemu-coroutine-sleep.c | 8 ++++----
14
iothread.c | 27 +++++++++++++++++++++++----
13
1 file changed, 4 insertions(+), 4 deletions(-)
15
1 file changed, 23 insertions(+), 4 deletions(-)
14
16
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
17
diff --git a/iothread.c b/iothread.c
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/util/qemu-coroutine-sleep.c
19
--- a/iothread.c
18
+++ b/util/qemu-coroutine-sleep.c
20
+++ b/iothread.c
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
21
@@ -XXX,XX +XXX,XX @@ static PollParamInfo poll_shrink_info = {
20
22
"poll-shrink", offsetof(IOThread, poll_shrink),
21
struct QemuCoSleepState {
22
Coroutine *co;
23
- QEMUTimer ts;
24
QemuCoSleepState **user_state_pointer;
25
};
23
};
26
24
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
25
-static void iothread_get_poll_param(Object *obj, Visitor *v,
28
26
+static void iothread_get_param(Object *obj, Visitor *v,
29
assert(scheduled == qemu_co_sleep_ns__scheduled);
27
const char *name, void *opaque, Error **errp)
30
*sleep_state->user_state_pointer = NULL;
28
{
31
- timer_del(&sleep_state->ts);
29
IOThread *iothread = IOTHREAD(obj);
32
aio_co_wake(sleep_state->co);
30
@@ -XXX,XX +XXX,XX @@ static void iothread_get_poll_param(Object *obj, Visitor *v,
31
visit_type_int64(v, name, field, errp);
32
}
33
34
-static void iothread_set_poll_param(Object *obj, Visitor *v,
35
+static bool iothread_set_param(Object *obj, Visitor *v,
36
const char *name, void *opaque, Error **errp)
37
{
38
IOThread *iothread = IOTHREAD(obj);
39
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
40
int64_t value;
41
42
if (!visit_type_int64(v, name, &value, errp)) {
43
- return;
44
+ return false;
33
}
45
}
34
}
46
35
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
47
if (value < 0) {
36
QemuCoSleepState **sleep_state)
48
error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
37
{
49
info->name, INT64_MAX);
38
AioContext *ctx = qemu_get_current_aio_context();
50
- return;
39
+ QEMUTimer ts;
51
+ return false;
40
QemuCoSleepState state = {
41
.co = qemu_coroutine_self(),
42
.user_state_pointer = sleep_state,
43
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
44
abort();
45
}
52
}
46
53
47
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
54
*field = value;
48
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
55
49
*sleep_state = &state;
56
+ return true;
50
- timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
57
+}
51
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
58
+
52
qemu_coroutine_yield();
59
+static void iothread_get_poll_param(Object *obj, Visitor *v,
53
+ timer_del(&ts);
60
+ const char *name, void *opaque, Error **errp)
54
61
+{
55
/* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
62
+
56
assert(*sleep_state == NULL);
63
+ iothread_get_param(obj, v, name, opaque, errp);
64
+}
65
+
66
+static void iothread_set_poll_param(Object *obj, Visitor *v,
67
+ const char *name, void *opaque, Error **errp)
68
+{
69
+ IOThread *iothread = IOTHREAD(obj);
70
+
71
+ if (!iothread_set_param(obj, v, name, opaque, errp)) {
72
+ return;
73
+ }
74
+
75
if (iothread->ctx) {
76
aio_context_set_poll_params(iothread->ctx,
77
iothread->poll_max_ns,
57
--
78
--
58
2.31.1
79
2.31.1
59
80
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Allow using QemuCoSleep to sleep forever until woken by qemu_co_sleep_wake.
3
The `aio-max-batch` parameter will be propagated to AIO engines
4
This makes the logic of qemu_co_sleep_ns_wakeable easy to understand.
4
and it will be used to control the maximum number of queued requests.
5
5
6
In the future we will introduce an API that can work even if the
6
When there are in queue a number of requests equal to `aio-max-batch`,
7
sleep and wake happen from different threads. For now, initializing
7
the engine invokes the system call to forward the requests to the kernel.
8
w->to_wake after timer_mod is fine because the timer can only fire in
8
9
the same AioContext.
9
This parameter allows us to control the maximum batch size to reduce
10
10
the latency that requests might accumulate while queued in the AIO
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
engine queue.
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
13
Message-id: 20210517100548.28806-7-pbonzini@redhat.com
13
If `aio-max-batch` is equal to 0 (default value), the AIO engine will
14
use its default maximum batch size value.
15
16
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
17
Message-id: 20210721094211.69853-3-sgarzare@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
19
---
16
include/qemu/coroutine.h | 5 +++++
20
qapi/misc.json | 6 ++++-
17
util/qemu-coroutine-sleep.c | 26 +++++++++++++++++++-------
21
qapi/qom.json | 7 ++++-
18
2 files changed, 24 insertions(+), 7 deletions(-)
22
include/block/aio.h | 12 +++++++++
19
23
include/sysemu/iothread.h | 3 +++
20
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
24
iothread.c | 55 +++++++++++++++++++++++++++++++++++----
21
index XXXXXXX..XXXXXXX 100644
25
monitor/hmp-cmds.c | 2 ++
22
--- a/include/qemu/coroutine.h
26
util/aio-posix.c | 12 +++++++++
23
+++ b/include/qemu/coroutine.h
27
util/aio-win32.c | 5 ++++
24
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleep {
28
util/async.c | 2 ++
25
void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
29
qemu-options.hx | 8 ++++--
26
QEMUClockType type, int64_t ns);
30
10 files changed, 103 insertions(+), 9 deletions(-)
31
32
diff --git a/qapi/misc.json b/qapi/misc.json
33
index XXXXXXX..XXXXXXX 100644
34
--- a/qapi/misc.json
35
+++ b/qapi/misc.json
36
@@ -XXX,XX +XXX,XX @@
37
# @poll-shrink: how many ns will be removed from polling time, 0 means that
38
# it's not configured (since 2.9)
39
#
40
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
41
+# 0 means that the engine will use its default (since 6.1)
42
+#
43
# Since: 2.0
44
##
45
{ 'struct': 'IOThreadInfo',
46
@@ -XXX,XX +XXX,XX @@
47
'thread-id': 'int',
48
'poll-max-ns': 'int',
49
'poll-grow': 'int',
50
- 'poll-shrink': 'int' } }
51
+ 'poll-shrink': 'int',
52
+ 'aio-max-batch': 'int' } }
53
54
##
55
# @query-iothreads:
56
diff --git a/qapi/qom.json b/qapi/qom.json
57
index XXXXXXX..XXXXXXX 100644
58
--- a/qapi/qom.json
59
+++ b/qapi/qom.json
60
@@ -XXX,XX +XXX,XX @@
61
# algorithm detects it is spending too long polling without
62
# encountering events. 0 selects a default behaviour (default: 0)
63
#
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
65
+# 0 means that the engine will use its default
66
+# (default:0, since 6.1)
67
+#
68
# Since: 2.0
69
##
70
{ 'struct': 'IothreadProperties',
71
'data': { '*poll-max-ns': 'int',
72
'*poll-grow': 'int',
73
- '*poll-shrink': 'int' } }
74
+ '*poll-shrink': 'int',
75
+ '*aio-max-batch': 'int' } }
76
77
##
78
# @MemoryBackendProperties:
79
diff --git a/include/block/aio.h b/include/block/aio.h
80
index XXXXXXX..XXXXXXX 100644
81
--- a/include/block/aio.h
82
+++ b/include/block/aio.h
83
@@ -XXX,XX +XXX,XX @@ struct AioContext {
84
int64_t poll_grow; /* polling time growth factor */
85
int64_t poll_shrink; /* polling time shrink factor */
86
87
+ /* AIO engine parameters */
88
+ int64_t aio_max_batch; /* maximum number of requests in a batch */
89
+
90
/*
91
* List of handlers participating in userspace polling. Protected by
92
* ctx->list_lock. Iterated and modified mostly by the event loop thread
93
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
94
int64_t grow, int64_t shrink,
95
Error **errp);
27
96
28
+/**
97
+/**
29
+ * Yield the coroutine until the next call to qemu_co_sleep_wake.
98
+ * aio_context_set_aio_params:
99
+ * @ctx: the aio context
100
+ * @max_batch: maximum number of requests in a batch, 0 means that the
101
+ * engine will use its default
30
+ */
102
+ */
31
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w);
103
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
32
+
104
+ Error **errp);
33
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
105
+
106
#endif
107
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
108
index XXXXXXX..XXXXXXX 100644
109
--- a/include/sysemu/iothread.h
110
+++ b/include/sysemu/iothread.h
111
@@ -XXX,XX +XXX,XX @@ struct IOThread {
112
int64_t poll_max_ns;
113
int64_t poll_grow;
114
int64_t poll_shrink;
115
+
116
+ /* AioContext AIO engine parameters */
117
+ int64_t aio_max_batch;
118
};
119
typedef struct IOThread IOThread;
120
121
diff --git a/iothread.c b/iothread.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/iothread.c
124
+++ b/iothread.c
125
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
126
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
127
}
128
129
+static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
130
+{
131
+ ERRP_GUARD();
132
+
133
+ aio_context_set_poll_params(iothread->ctx,
134
+ iothread->poll_max_ns,
135
+ iothread->poll_grow,
136
+ iothread->poll_shrink,
137
+ errp);
138
+ if (*errp) {
139
+ return;
140
+ }
141
+
142
+ aio_context_set_aio_params(iothread->ctx,
143
+ iothread->aio_max_batch,
144
+ errp);
145
+}
146
+
147
static void iothread_complete(UserCreatable *obj, Error **errp)
34
{
148
{
35
QemuCoSleep w = { 0 };
149
Error *local_error = NULL;
36
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
150
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
37
index XXXXXXX..XXXXXXX 100644
151
*/
38
--- a/util/qemu-coroutine-sleep.c
152
iothread_init_gcontext(iothread);
39
+++ b/util/qemu-coroutine-sleep.c
153
40
@@ -XXX,XX +XXX,XX @@ static void co_sleep_cb(void *opaque)
154
- aio_context_set_poll_params(iothread->ctx,
41
qemu_co_sleep_wake(w);
155
- iothread->poll_max_ns,
42
}
156
- iothread->poll_grow,
43
157
- iothread->poll_shrink,
44
-void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
158
- &local_error);
45
- QEMUClockType type, int64_t ns)
159
+ iothread_set_aio_context_params(iothread, &local_error);
46
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w)
160
if (local_error) {
161
error_propagate(errp, local_error);
162
aio_context_unref(iothread->ctx);
163
@@ -XXX,XX +XXX,XX @@ static PollParamInfo poll_grow_info = {
164
static PollParamInfo poll_shrink_info = {
165
"poll-shrink", offsetof(IOThread, poll_shrink),
166
};
167
+static PollParamInfo aio_max_batch_info = {
168
+ "aio-max-batch", offsetof(IOThread, aio_max_batch),
169
+};
170
171
static void iothread_get_param(Object *obj, Visitor *v,
172
const char *name, void *opaque, Error **errp)
173
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
174
}
175
}
176
177
+static void iothread_get_aio_param(Object *obj, Visitor *v,
178
+ const char *name, void *opaque, Error **errp)
179
+{
180
+
181
+ iothread_get_param(obj, v, name, opaque, errp);
182
+}
183
+
184
+static void iothread_set_aio_param(Object *obj, Visitor *v,
185
+ const char *name, void *opaque, Error **errp)
186
+{
187
+ IOThread *iothread = IOTHREAD(obj);
188
+
189
+ if (!iothread_set_param(obj, v, name, opaque, errp)) {
190
+ return;
191
+ }
192
+
193
+ if (iothread->ctx) {
194
+ aio_context_set_aio_params(iothread->ctx,
195
+ iothread->aio_max_batch,
196
+ errp);
197
+ }
198
+}
199
+
200
static void iothread_class_init(ObjectClass *klass, void *class_data)
47
{
201
{
48
Coroutine *co = qemu_coroutine_self();
202
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
49
- AioContext *ctx = qemu_get_current_aio_context();
203
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
50
- QEMUTimer ts;
204
iothread_get_poll_param,
51
205
iothread_set_poll_param,
52
const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
206
NULL, &poll_shrink_info);
53
qemu_co_sleep_ns__scheduled);
207
+ object_class_property_add(klass, "aio-max-batch", "int",
54
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
208
+ iothread_get_aio_param,
209
+ iothread_set_aio_param,
210
+ NULL, &aio_max_batch_info);
211
}
212
213
static const TypeInfo iothread_info = {
214
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
215
info->poll_max_ns = iothread->poll_max_ns;
216
info->poll_grow = iothread->poll_grow;
217
info->poll_shrink = iothread->poll_shrink;
218
+ info->aio_max_batch = iothread->aio_max_batch;
219
220
QAPI_LIST_APPEND(*tail, info);
221
return 0;
222
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
223
index XXXXXXX..XXXXXXX 100644
224
--- a/monitor/hmp-cmds.c
225
+++ b/monitor/hmp-cmds.c
226
@@ -XXX,XX +XXX,XX @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
227
monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
228
monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
229
monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
230
+ monitor_printf(mon, " aio-max-batch=%" PRId64 "\n",
231
+ value->aio_max_batch);
55
}
232
}
56
233
57
w->to_wake = co;
234
qapi_free_IOThreadInfoList(info_list);
58
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
235
diff --git a/util/aio-posix.c b/util/aio-posix.c
59
- timer_mod(&ts, qemu_clock_get_ns(type) + ns);
236
index XXXXXXX..XXXXXXX 100644
60
qemu_coroutine_yield();
237
--- a/util/aio-posix.c
61
- timer_del(&ts);
238
+++ b/util/aio-posix.c
62
239
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
63
/* w->to_wake is cleared before resuming this coroutine. */
240
64
assert(w->to_wake == NULL);
241
aio_notify(ctx);
65
}
242
}
66
+
243
+
67
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
244
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
68
+ QEMUClockType type, int64_t ns)
245
+ Error **errp)
69
+{
246
+{
70
+ AioContext *ctx = qemu_get_current_aio_context();
71
+ QEMUTimer ts;
72
+
73
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w);
74
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
75
+
76
+ /*
247
+ /*
77
+ * The timer will fire in the current AiOContext, so the callback
248
+ * No thread synchronization here, it doesn't matter if an incorrect value
78
+ * must happen after qemu_co_sleep yields and there is no race
249
+ * is used once.
79
+ * between timer_mod and qemu_co_sleep.
80
+ */
250
+ */
81
+ qemu_co_sleep(w);
251
+ ctx->aio_max_batch = max_batch;
82
+ timer_del(&ts);
252
+
83
+}
253
+ aio_notify(ctx);
254
+}
255
diff --git a/util/aio-win32.c b/util/aio-win32.c
256
index XXXXXXX..XXXXXXX 100644
257
--- a/util/aio-win32.c
258
+++ b/util/aio-win32.c
259
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
260
error_setg(errp, "AioContext polling is not implemented on Windows");
261
}
262
}
263
+
264
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
265
+ Error **errp)
266
+{
267
+}
268
diff --git a/util/async.c b/util/async.c
269
index XXXXXXX..XXXXXXX 100644
270
--- a/util/async.c
271
+++ b/util/async.c
272
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
273
ctx->poll_grow = 0;
274
ctx->poll_shrink = 0;
275
276
+ ctx->aio_max_batch = 0;
277
+
278
return ctx;
279
fail:
280
g_source_destroy(&ctx->source);
281
diff --git a/qemu-options.hx b/qemu-options.hx
282
index XXXXXXX..XXXXXXX 100644
283
--- a/qemu-options.hx
284
+++ b/qemu-options.hx
285
@@ -XXX,XX +XXX,XX @@ SRST
286
287
CN=laptop.example.com,O=Example Home,L=London,ST=London,C=GB
288
289
- ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink``
290
+ ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink,aio-max-batch=aio-max-batch``
291
Creates a dedicated event loop thread that devices can be
292
assigned to. This is known as an IOThread. By default device
293
emulation happens in vCPU threads or the main event loop thread.
294
@@ -XXX,XX +XXX,XX @@ SRST
295
the polling time when the algorithm detects it is spending too
296
long polling without encountering events.
297
298
- The polling parameters can be modified at run-time using the
299
+ The ``aio-max-batch`` parameter is the maximum number of requests
300
+ in a batch for the AIO engine, 0 means that the engine will use
301
+ its default.
302
+
303
+ The IOThread parameters can be modified at run-time using the
304
``qom-set`` command (where ``iothread1`` is the IOThread's
305
``id``):
306
84
--
307
--
85
2.31.1
308
2.31.1
86
309
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Simplify the code by removing conditionals. qemu_co_sleep_ns
3
When there are multiple queues attached to the same AIO context,
4
can simply point the argument to an on-stack temporary.
4
some requests may experience high latency, since in the worst case
5
the AIO engine queue is only flushed when it is full (MAX_EVENTS) or
6
there are no more queues plugged.
5
7
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Commit 2558cb8dd4 ("linux-aio: increasing MAX_EVENTS to a larger
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
hardcoded value") changed MAX_EVENTS from 128 to 1024, to increase
8
Message-id: 20210517100548.28806-3-pbonzini@redhat.com
10
the number of in-flight requests. But this change also increased
11
the potential maximum batch to 1024 elements.
12
13
When there is a single queue attached to the AIO context, the issue
14
is mitigated from laio_io_unplug() that will flush the queue every
15
time is invoked since there can't be others queue plugged.
16
17
Let's use the new `aio-max-batch` IOThread parameter to mitigate
18
this issue, limiting the number of requests in a batch.
19
20
We also define a default value (32): this value is obtained running
21
some benchmarks and it represents a good tradeoff between the latency
22
increase while a request is queued and the cost of the io_submit(2)
23
system call.
24
25
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
26
Message-id: 20210721094211.69853-4-sgarzare@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
28
---
11
include/qemu/coroutine.h | 5 +++--
29
block/linux-aio.c | 9 ++++++++-
12
util/qemu-coroutine-sleep.c | 18 +++++-------------
30
1 file changed, 8 insertions(+), 1 deletion(-)
13
2 files changed, 8 insertions(+), 15 deletions(-)
14
31
15
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
32
diff --git a/block/linux-aio.c b/block/linux-aio.c
16
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
17
--- a/include/qemu/coroutine.h
34
--- a/block/linux-aio.c
18
+++ b/include/qemu/coroutine.h
35
+++ b/block/linux-aio.c
19
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleepState QemuCoSleepState;
36
@@ -XXX,XX +XXX,XX @@
20
37
*/
21
/**
38
#define MAX_EVENTS 1024
22
* Yield the coroutine for a given duration. During this yield, @sleep_state
39
23
- * (if not NULL) is set to an opaque pointer, which may be used for
40
+/* Maximum number of requests in a batch. (default value) */
24
+ * is set to an opaque pointer, which may be used for
41
+#define DEFAULT_MAX_BATCH 32
25
* qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
42
+
26
* timer fires. Don't save the obtained value to other variables and don't call
43
struct qemu_laiocb {
27
* qemu_co_sleep_wake from another aio context.
44
Coroutine *co;
28
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
45
LinuxAioState *ctx;
29
QemuCoSleepState **sleep_state);
46
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
30
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
47
LinuxAioState *s = laiocb->ctx;
31
{
48
struct iocb *iocbs = &laiocb->iocb;
32
- qemu_co_sleep_ns_wakeable(type, ns, NULL);
49
QEMUIOVector *qiov = laiocb->qiov;
33
+ QemuCoSleepState *unused = NULL;
50
+ int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
34
+ qemu_co_sleep_ns_wakeable(type, ns, &unused);
51
+
35
}
52
+ /* limit the batch with the number of available events */
36
53
+ max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
37
/**
54
38
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
55
switch (type) {
39
index XXXXXXX..XXXXXXX 100644
56
case QEMU_AIO_WRITE:
40
--- a/util/qemu-coroutine-sleep.c
57
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
41
+++ b/util/qemu-coroutine-sleep.c
58
s->io_q.in_queue++;
42
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
59
if (!s->io_q.blocked &&
43
qemu_co_sleep_ns__scheduled, NULL);
60
(!s->io_q.plugged ||
44
61
- s->io_q.in_flight + s->io_q.in_queue >= MAX_EVENTS)) {
45
assert(scheduled == qemu_co_sleep_ns__scheduled);
62
+ s->io_q.in_queue >= max_batch)) {
46
- if (sleep_state->user_state_pointer) {
63
ioq_submit(s);
47
- *sleep_state->user_state_pointer = NULL;
48
- }
49
+ *sleep_state->user_state_pointer = NULL;
50
timer_del(&sleep_state->ts);
51
aio_co_wake(sleep_state->co);
52
}
53
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
54
}
64
}
55
65
56
aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
57
- if (sleep_state) {
58
- *sleep_state = &state;
59
- }
60
+ *sleep_state = &state;
61
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
62
qemu_coroutine_yield();
63
- if (sleep_state) {
64
- /*
65
- * Note that *sleep_state is cleared during qemu_co_sleep_wake
66
- * before resuming this coroutine.
67
- */
68
- assert(*sleep_state == NULL);
69
- }
70
+
71
+ /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
72
+ assert(*sleep_state == NULL);
73
}
74
--
66
--
75
2.31.1
67
2.31.1
76
68
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
All callers of qemu_co_sleep_wake are checking whether they are passing
4
a NULL argument inside the pointer-to-pointer: do the check in
5
qemu_co_sleep_wake itself.
6
7
As a side effect, qemu_co_sleep_wake can be called more than once and
8
it will only wake the coroutine once; after the first time, the argument
9
will be set to NULL via *sleep_state->user_state_pointer. However, this
10
would not be safe unless co_sleep_cb keeps using the QemuCoSleepState*
11
directly, so make it go through the pointer-to-pointer instead.
12
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-id: 20210517100548.28806-4-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
18
block/block-copy.c | 4 +---
19
block/nbd.c | 8 ++------
20
util/qemu-coroutine-sleep.c | 21 ++++++++++++---------
21
3 files changed, 15 insertions(+), 18 deletions(-)
22
23
diff --git a/block/block-copy.c b/block/block-copy.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/block-copy.c
26
+++ b/block/block-copy.c
27
@@ -XXX,XX +XXX,XX @@ out:
28
29
void block_copy_kick(BlockCopyCallState *call_state)
30
{
31
- if (call_state->sleep_state) {
32
- qemu_co_sleep_wake(call_state->sleep_state);
33
- }
34
+ qemu_co_sleep_wake(call_state->sleep_state);
35
}
36
37
/*
38
diff --git a/block/nbd.c b/block/nbd.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/nbd.c
41
+++ b/block/nbd.c
42
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
43
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
44
45
s->drained = true;
46
- if (s->connection_co_sleep_ns_state) {
47
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
48
- }
49
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
50
51
nbd_co_establish_connection_cancel(bs, false);
52
53
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
54
55
s->state = NBD_CLIENT_QUIT;
56
if (s->connection_co) {
57
- if (s->connection_co_sleep_ns_state) {
58
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
59
- }
60
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
61
nbd_co_establish_connection_cancel(bs, true);
62
}
63
if (qemu_in_coroutine()) {
64
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/util/qemu-coroutine-sleep.c
67
+++ b/util/qemu-coroutine-sleep.c
68
@@ -XXX,XX +XXX,XX @@ struct QemuCoSleepState {
69
70
void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
71
{
72
- /* Write of schedule protected by barrier write in aio_co_schedule */
73
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
74
- qemu_co_sleep_ns__scheduled, NULL);
75
+ if (sleep_state) {
76
+ /* Write of schedule protected by barrier write in aio_co_schedule */
77
+ const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
78
+ qemu_co_sleep_ns__scheduled, NULL);
79
80
- assert(scheduled == qemu_co_sleep_ns__scheduled);
81
- *sleep_state->user_state_pointer = NULL;
82
- timer_del(&sleep_state->ts);
83
- aio_co_wake(sleep_state->co);
84
+ assert(scheduled == qemu_co_sleep_ns__scheduled);
85
+ *sleep_state->user_state_pointer = NULL;
86
+ timer_del(&sleep_state->ts);
87
+ aio_co_wake(sleep_state->co);
88
+ }
89
}
90
91
static void co_sleep_cb(void *opaque)
92
{
93
- qemu_co_sleep_wake(opaque);
94
+ QemuCoSleepState **sleep_state = opaque;
95
+ qemu_co_sleep_wake(*sleep_state);
96
}
97
98
void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
99
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
100
abort();
101
}
102
103
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
104
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
105
*sleep_state = &state;
106
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
107
qemu_coroutine_yield();
108
--
109
2.31.1
110
diff view generated by jsdifflib
Deleted patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
1
3
Right now, users of qemu_co_sleep_ns_wakeable are simply passing
4
a pointer to QemuCoSleepState by reference to the function. But
5
QemuCoSleepState really is just a Coroutine*; making the
6
content of the struct public is just as efficient and lets us
7
skip the user_state_pointer indirection.
8
9
Since the usage is changed, take the occasion to rename the
10
struct to QemuCoSleep.
11
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
14
Message-id: 20210517100548.28806-6-pbonzini@redhat.com
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
---
17
include/qemu/coroutine.h | 23 +++++++++++----------
18
block/block-copy.c | 8 ++++----
19
block/nbd.c | 10 ++++-----
20
util/qemu-coroutine-sleep.c | 41 ++++++++++++++++---------------------
21
4 files changed, 39 insertions(+), 43 deletions(-)
22
23
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/qemu/coroutine.h
26
+++ b/include/qemu/coroutine.h
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock);
28
*/
29
void qemu_co_rwlock_unlock(CoRwlock *lock);
30
31
-typedef struct QemuCoSleepState QemuCoSleepState;
32
+typedef struct QemuCoSleep {
33
+ Coroutine *to_wake;
34
+} QemuCoSleep;
35
36
/**
37
- * Yield the coroutine for a given duration. During this yield, @sleep_state
38
- * is set to an opaque pointer, which may be used for
39
- * qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
40
- * timer fires. Don't save the obtained value to other variables and don't call
41
- * qemu_co_sleep_wake from another aio context.
42
+ * Yield the coroutine for a given duration. Initializes @w so that,
43
+ * during this yield, it can be passed to qemu_co_sleep_wake() to
44
+ * terminate the sleep.
45
*/
46
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
47
- QemuCoSleepState **sleep_state);
48
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
49
+ QEMUClockType type, int64_t ns);
50
+
51
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
52
{
53
- QemuCoSleepState *unused = NULL;
54
- qemu_co_sleep_ns_wakeable(type, ns, &unused);
55
+ QemuCoSleep w = { 0 };
56
+ qemu_co_sleep_ns_wakeable(&w, type, ns);
57
}
58
59
/**
60
@@ -XXX,XX +XXX,XX @@ static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
61
* qemu_co_sleep_ns() and should be checked to be non-NULL before calling
62
* qemu_co_sleep_wake().
63
*/
64
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state);
65
+void qemu_co_sleep_wake(QemuCoSleep *w);
66
67
/**
68
* Yield until a file descriptor becomes readable
69
diff --git a/block/block-copy.c b/block/block-copy.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/block-copy.c
72
+++ b/block/block-copy.c
73
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyCallState {
74
/* State */
75
int ret;
76
bool finished;
77
- QemuCoSleepState *sleep_state;
78
+ QemuCoSleep sleep;
79
bool cancelled;
80
81
/* OUT parameters */
82
@@ -XXX,XX +XXX,XX @@ block_copy_dirty_clusters(BlockCopyCallState *call_state)
83
if (ns > 0) {
84
block_copy_task_end(task, -EAGAIN);
85
g_free(task);
86
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, ns,
87
- &call_state->sleep_state);
88
+ qemu_co_sleep_ns_wakeable(&call_state->sleep,
89
+ QEMU_CLOCK_REALTIME, ns);
90
continue;
91
}
92
}
93
@@ -XXX,XX +XXX,XX @@ out:
94
95
void block_copy_kick(BlockCopyCallState *call_state)
96
{
97
- qemu_co_sleep_wake(call_state->sleep_state);
98
+ qemu_co_sleep_wake(&call_state->sleep);
99
}
100
101
/*
102
diff --git a/block/nbd.c b/block/nbd.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/block/nbd.c
105
+++ b/block/nbd.c
106
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVNBDState {
107
CoQueue free_sema;
108
Coroutine *connection_co;
109
Coroutine *teardown_co;
110
- QemuCoSleepState *connection_co_sleep_ns_state;
111
+ QemuCoSleep reconnect_sleep;
112
bool drained;
113
bool wait_drained_end;
114
int in_flight;
115
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
116
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
117
118
s->drained = true;
119
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
120
+ qemu_co_sleep_wake(&s->reconnect_sleep);
121
122
nbd_co_establish_connection_cancel(bs, false);
123
124
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
125
126
s->state = NBD_CLIENT_QUIT;
127
if (s->connection_co) {
128
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
129
+ qemu_co_sleep_wake(&s->reconnect_sleep);
130
nbd_co_establish_connection_cancel(bs, true);
131
}
132
if (qemu_in_coroutine()) {
133
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
134
}
135
bdrv_inc_in_flight(s->bs);
136
} else {
137
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout,
138
- &s->connection_co_sleep_ns_state);
139
+ qemu_co_sleep_ns_wakeable(&s->reconnect_sleep,
140
+ QEMU_CLOCK_REALTIME, timeout);
141
if (s->drained) {
142
continue;
143
}
144
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/util/qemu-coroutine-sleep.c
147
+++ b/util/qemu-coroutine-sleep.c
148
@@ -XXX,XX +XXX,XX @@
149
150
static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
151
152
-struct QemuCoSleepState {
153
+void qemu_co_sleep_wake(QemuCoSleep *w)
154
+{
155
Coroutine *co;
156
- QemuCoSleepState **user_state_pointer;
157
-};
158
159
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
160
-{
161
- if (sleep_state) {
162
+ co = w->to_wake;
163
+ w->to_wake = NULL;
164
+ if (co) {
165
/* Write of schedule protected by barrier write in aio_co_schedule */
166
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
167
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled,
168
qemu_co_sleep_ns__scheduled, NULL);
169
170
assert(scheduled == qemu_co_sleep_ns__scheduled);
171
- *sleep_state->user_state_pointer = NULL;
172
- aio_co_wake(sleep_state->co);
173
+ aio_co_wake(co);
174
}
175
}
176
177
static void co_sleep_cb(void *opaque)
178
{
179
- QemuCoSleepState **sleep_state = opaque;
180
- qemu_co_sleep_wake(*sleep_state);
181
+ QemuCoSleep *w = opaque;
182
+ qemu_co_sleep_wake(w);
183
}
184
185
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
186
- QemuCoSleepState **sleep_state)
187
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
188
+ QEMUClockType type, int64_t ns)
189
{
190
+ Coroutine *co = qemu_coroutine_self();
191
AioContext *ctx = qemu_get_current_aio_context();
192
QEMUTimer ts;
193
- QemuCoSleepState state = {
194
- .co = qemu_coroutine_self(),
195
- .user_state_pointer = sleep_state,
196
- };
197
198
- const char *scheduled = qatomic_cmpxchg(&state.co->scheduled, NULL,
199
- qemu_co_sleep_ns__scheduled);
200
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
201
+ qemu_co_sleep_ns__scheduled);
202
if (scheduled) {
203
fprintf(stderr,
204
"%s: Co-routine was already scheduled in '%s'\n",
205
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
206
abort();
207
}
208
209
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
210
- *sleep_state = &state;
211
+ w->to_wake = co;
212
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
213
timer_mod(&ts, qemu_clock_get_ns(type) + ns);
214
qemu_coroutine_yield();
215
timer_del(&ts);
216
217
- /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
218
- assert(*sleep_state == NULL);
219
+ /* w->to_wake is cleared before resuming this coroutine. */
220
+ assert(w->to_wake == NULL);
221
}
222
--
223
2.31.1
224
diff view generated by jsdifflib