* [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero
@ 2013-04-05 15:59 Paolo Bonzini
2013-04-06 19:00 ` Amit Shah
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Paolo Bonzini @ 2013-04-05 15:59 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori
The character backend refactoring introduced an undesirable busy wait.
The busy wait happens if can_read returns zero and there is data available
on the character device's file descriptor. Then, the I/O watch will
fire continuously and, with TCG, the CPU thread will never run.
1) Char backend asks front end if it can write
2) Front end says no
3) poll() finds the char backend's descriptor is available
4) Goto (1)
What we really want is this (note that step 3 avoids the busy wait):
1) Char backend asks front end if it can write
2) Front end says no
3) poll() goes on without char backend's descriptor
4) Goto (1) until qemu_chr_accept_input() called
5) Char backend asks front end if it can write
6) Front end says yes
7) poll() finds the char backend's descriptor is available
8) Backend handler called
After this patch, the IOWatchPoll source and the watch source are
separated. The IOWatchPoll is simply a hook that runs during the prepare
phase on each main loop iteration. The hook adds/removes the actual
source depending on the return value from can_read.
A simple reproducer is
qemu-system-i386 -serial mon:stdio
... followed by banging on the terminal as much as you can. :) Without
this patch, emulation will hang.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
v1->v2: use g_source_get_context to find if the watch was active
qemu-char.c | 62 +++++++++++++++++++------------------------------------------
1 file changed, 19 insertions(+), 43 deletions(-)
diff --git a/qemu-char.c b/qemu-char.c
index e5eb8dd..85ebcf9 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -594,65 +594,51 @@ int recv_all(int fd, void *_buf, int len1, bool single_read)
typedef struct IOWatchPoll
{
+ GSource parent;
+
GSource *src;
- int max_size;
IOCanReadHandler *fd_can_read;
void *opaque;
-
- QTAILQ_ENTRY(IOWatchPoll) node;
} IOWatchPoll;
-static QTAILQ_HEAD(, IOWatchPoll) io_watch_poll_list =
- QTAILQ_HEAD_INITIALIZER(io_watch_poll_list);
-
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
{
- IOWatchPoll *i;
-
- QTAILQ_FOREACH(i, &io_watch_poll_list, node) {
- if (i->src == source) {
- return i;
- }
- }
-
- return NULL;
+ return container_of(source, IOWatchPoll, parent);
}
static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
{
IOWatchPoll *iwp = io_watch_poll_from_source(source);
-
- iwp->max_size = iwp->fd_can_read(iwp->opaque);
- if (iwp->max_size == 0) {
+ bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
+ bool was_active = g_source_get_context(iwp->src) != NULL;
+ if (was_active == now_active) {
return FALSE;
}
- return g_io_watch_funcs.prepare(source, timeout_);
+ if (now_active) {
+ g_source_attach(iwp->src, NULL);
+ } else {
+ g_source_remove(g_source_get_id(iwp->src));
+ }
+ return FALSE;
}
static gboolean io_watch_poll_check(GSource *source)
{
- IOWatchPoll *iwp = io_watch_poll_from_source(source);
-
- if (iwp->max_size == 0) {
- return FALSE;
- }
-
- return g_io_watch_funcs.check(source);
+ return FALSE;
}
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
gpointer user_data)
{
- return g_io_watch_funcs.dispatch(source, callback, user_data);
+ abort();
}
static void io_watch_poll_finalize(GSource *source)
{
IOWatchPoll *iwp = io_watch_poll_from_source(source);
- QTAILQ_REMOVE(&io_watch_poll_list, iwp, node);
- g_io_watch_funcs.finalize(source);
+ g_source_unref(iwp->src);
}
static GSourceFuncs io_watch_poll_funcs = {
@@ -669,24 +655,14 @@ static guint io_add_watch_poll(GIOChannel *channel,
gpointer user_data)
{
IOWatchPoll *iwp;
- GSource *src;
- guint tag;
-
- src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
- g_source_set_funcs(src, &io_watch_poll_funcs);
- g_source_set_callback(src, (GSourceFunc)fd_read, user_data, NULL);
- tag = g_source_attach(src, NULL);
- g_source_unref(src);
- iwp = g_malloc0(sizeof(*iwp));
- iwp->src = src;
- iwp->max_size = 0;
+ iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll));
iwp->fd_can_read = fd_can_read;
iwp->opaque = user_data;
+ iwp->src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
+ g_source_set_callback(iwp->src, (GSourceFunc)fd_read, user_data, NULL);
- QTAILQ_INSERT_HEAD(&io_watch_poll_list, iwp, node);
-
- return tag;
+ return g_source_attach(&iwp->parent, NULL);
}
#ifndef _WIN32
--
1.8.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero
2013-04-05 15:59 [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero Paolo Bonzini
@ 2013-04-06 19:00 ` Amit Shah
2013-04-07 18:49 ` Paolo Bonzini
2013-04-07 5:09 ` Peter Crosthwaite
2013-04-08 21:55 ` Anthony Liguori
2 siblings, 1 reply; 6+ messages in thread
From: Amit Shah @ 2013-04-06 19:00 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: aliguori, qemu-devel
On (Fri) 05 Apr 2013 [17:59:33], Paolo Bonzini wrote:
> The character backend refactoring introduced an undesirable busy wait.
> The busy wait happens if can_read returns zero and there is data available
> on the character device's file descriptor. Then, the I/O watch will
> fire continuously and, with TCG, the CPU thread will never run.
>
> 1) Char backend asks front end if it can write
> 2) Front end says no
> 3) poll() finds the char backend's descriptor is available
> 4) Goto (1)
>
> What we really want is this (note that step 3 avoids the busy wait):
>
> 1) Char backend asks front end if it can write
> 2) Front end says no
> 3) poll() goes on without char backend's descriptor
> 4) Goto (1) until qemu_chr_accept_input() called
>
> 5) Char backend asks front end if it can write
> 6) Front end says yes
> 7) poll() finds the char backend's descriptor is available
> 8) Backend handler called
>
> After this patch, the IOWatchPoll source and the watch source are
> separated. The IOWatchPoll is simply a hook that runs during the prepare
> phase on each main loop iteration. The hook adds/removes the actual
> source depending on the return value from can_read.
>
> A simple reproducer is
>
> qemu-system-i386 -serial mon:stdio
>
> ... followed by banging on the terminal as much as you can. :) Without
> this patch, emulation will hang.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> v1->v2: use g_source_get_context to find if the watch was active
> static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
> {
> IOWatchPoll *iwp = io_watch_poll_from_source(source);
> -
> - iwp->max_size = iwp->fd_can_read(iwp->opaque);
> - if (iwp->max_size == 0) {
> + bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
> + bool was_active = g_source_get_context(iwp->src) != NULL;
This gives me a bunch of
(process:30075): GLib-CRITICAL **: g_source_get_context: assertion `!SOURCE_DESTROYED (source)' failed
messages
Amit
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero
2013-04-06 19:00 ` Amit Shah
@ 2013-04-07 18:49 ` Paolo Bonzini
2013-04-07 22:43 ` Peter Crosthwaite
0 siblings, 1 reply; 6+ messages in thread
From: Paolo Bonzini @ 2013-04-07 18:49 UTC (permalink / raw)
To: Amit Shah; +Cc: aliguori, qemu-devel
Il 06/04/2013 21:00, Amit Shah ha scritto:
> On (Fri) 05 Apr 2013 [17:59:33], Paolo Bonzini wrote:
>> The character backend refactoring introduced an undesirable busy wait.
>> The busy wait happens if can_read returns zero and there is data available
>> on the character device's file descriptor. Then, the I/O watch will
>> fire continuously and, with TCG, the CPU thread will never run.
>>
>> 1) Char backend asks front end if it can write
>> 2) Front end says no
>> 3) poll() finds the char backend's descriptor is available
>> 4) Goto (1)
>>
>> What we really want is this (note that step 3 avoids the busy wait):
>>
>> 1) Char backend asks front end if it can write
>> 2) Front end says no
>> 3) poll() goes on without char backend's descriptor
>> 4) Goto (1) until qemu_chr_accept_input() called
>>
>> 5) Char backend asks front end if it can write
>> 6) Front end says yes
>> 7) poll() finds the char backend's descriptor is available
>> 8) Backend handler called
>>
>> After this patch, the IOWatchPoll source and the watch source are
>> separated. The IOWatchPoll is simply a hook that runs during the prepare
>> phase on each main loop iteration. The hook adds/removes the actual
>> source depending on the return value from can_read.
>>
>> A simple reproducer is
>>
>> qemu-system-i386 -serial mon:stdio
>>
>> ... followed by banging on the terminal as much as you can. :) Without
>> this patch, emulation will hang.
>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>> v1->v2: use g_source_get_context to find if the watch was active
>
>> static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
>> {
>> IOWatchPoll *iwp = io_watch_poll_from_source(source);
>> -
>> - iwp->max_size = iwp->fd_can_read(iwp->opaque);
>> - if (iwp->max_size == 0) {
>> + bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
>> + bool was_active = g_source_get_context(iwp->src) != NULL;
>
> This gives me a bunch of
>
> (process:30075): GLib-CRITICAL **: g_source_get_context: assertion `!SOURCE_DESTROYED (source)' failed
>
> messages
This should fix it, but unfortunately Peter reports it is not enough:
diff --git a/qemu-char.c b/qemu-char.c
index 85ebcf9..c2fb985 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -610,8 +610,14 @@ static IOWatchPoll
*io_watch_poll_from_source(GSource *source)
static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
{
IOWatchPoll *iwp = io_watch_poll_from_source(source);
- bool was_active = g_source_get_context(iwp->src) != NULL;
- bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
+ bool was_active, now_active;
+
+ if (g_source_is_destroyed(iwp->src)) {
+ return FALSE;
+ }
+
+ was_active = g_source_get_context(iwp->src) != NULL;
+ now_active = iwp->fd_can_read(iwp->opaque) > 0;
if (was_active == now_active) {
return FALSE;
}
I'm not sure what is different between the microblaze and x86 cases.
Peter, please send us reproduction instructions.
Paolo
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero
2013-04-07 18:49 ` Paolo Bonzini
@ 2013-04-07 22:43 ` Peter Crosthwaite
0 siblings, 0 replies; 6+ messages in thread
From: Peter Crosthwaite @ 2013-04-07 22:43 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Amit Shah, aliguori, qemu-devel
Hi Paolo,
On Mon, Apr 8, 2013 at 4:49 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 06/04/2013 21:00, Amit Shah ha scritto:
>> On (Fri) 05 Apr 2013 [17:59:33], Paolo Bonzini wrote:
>>> The character backend refactoring introduced an undesirable busy wait.
>>> The busy wait happens if can_read returns zero and there is data available
>>> on the character device's file descriptor. Then, the I/O watch will
>>> fire continuously and, with TCG, the CPU thread will never run.
>>>
>>> 1) Char backend asks front end if it can write
>>> 2) Front end says no
>>> 3) poll() finds the char backend's descriptor is available
>>> 4) Goto (1)
>>>
>>> What we really want is this (note that step 3 avoids the busy wait):
>>>
>>> 1) Char backend asks front end if it can write
>>> 2) Front end says no
>>> 3) poll() goes on without char backend's descriptor
>>> 4) Goto (1) until qemu_chr_accept_input() called
>>>
>>> 5) Char backend asks front end if it can write
>>> 6) Front end says yes
>>> 7) poll() finds the char backend's descriptor is available
>>> 8) Backend handler called
>>>
>>> After this patch, the IOWatchPoll source and the watch source are
>>> separated. The IOWatchPoll is simply a hook that runs during the prepare
>>> phase on each main loop iteration. The hook adds/removes the actual
>>> source depending on the return value from can_read.
>>>
>>> A simple reproducer is
>>>
>>> qemu-system-i386 -serial mon:stdio
>>>
>>> ... followed by banging on the terminal as much as you can. :) Without
>>> this patch, emulation will hang.
>>>
>>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>>> ---
>>> v1->v2: use g_source_get_context to find if the watch was active
>>
>>> static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
>>> {
>>> IOWatchPoll *iwp = io_watch_poll_from_source(source);
>>> -
>>> - iwp->max_size = iwp->fd_can_read(iwp->opaque);
>>> - if (iwp->max_size == 0) {
>>> + bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
>>> + bool was_active = g_source_get_context(iwp->src) != NULL;
>>
>> This gives me a bunch of
>>
>> (process:30075): GLib-CRITICAL **: g_source_get_context: assertion `!SOURCE_DESTROYED (source)' failed
>>
>> messages
>
> This should fix it, but unfortunately Peter reports it is not enough:
>
> diff --git a/qemu-char.c b/qemu-char.c
> index 85ebcf9..c2fb985 100644
> --- a/qemu-char.c
> +++ b/qemu-char.c
> @@ -610,8 +610,14 @@ static IOWatchPoll
> *io_watch_poll_from_source(GSource *source)
> static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
> {
> IOWatchPoll *iwp = io_watch_poll_from_source(source);
> - bool was_active = g_source_get_context(iwp->src) != NULL;
> - bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
> + bool was_active, now_active;
> +
> + if (g_source_is_destroyed(iwp->src)) {
> + return FALSE;
> + }
> +
> + was_active = g_source_get_context(iwp->src) != NULL;
> + now_active = iwp->fd_can_read(iwp->opaque) > 0;
> if (was_active == now_active) {
> return FALSE;
> }
>
I too was getting the asserts. And this hunk does fix them. But the
bug persists.
>
> I'm not sure what is different between the microblaze and x86 cases.
> Peter, please send us reproduction instructions.
>
Heres a guest (Linux):
http://www.wiki.xilinx.com/file/view/image.elf/420852602/image.elf
./microblazeel-softmmu/qemu-system-microblazeel -M petalogix-ml605 -m
256 --serial mon:stdio --nographic -kernel image.elf
Let it run until you get the login prompt. Then paste 100 or so chars
into the console at once. Some will come through (before this patch
none came through), but the guest will then hang.
My configure:
./configure --target-list="microblazeel-softmmu" --disable-kvm --disable-fdt
Apply my "mainloop.c: Keep unlocking BQL during busy-wait spin-out"
and revert this patch to make it work. If you just revert this it will
work but be very slow.
Regards,
Peter
> Paolo
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero
2013-04-05 15:59 [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero Paolo Bonzini
2013-04-06 19:00 ` Amit Shah
@ 2013-04-07 5:09 ` Peter Crosthwaite
2013-04-08 21:55 ` Anthony Liguori
2 siblings, 0 replies; 6+ messages in thread
From: Peter Crosthwaite @ 2013-04-07 5:09 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: aliguori, qemu-devel
Hi Paolo,
On Sat, Apr 6, 2013 at 1:59 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> The character backend refactoring introduced an undesirable busy wait.
> The busy wait happens if can_read returns zero and there is data available
> on the character device's file descriptor. Then, the I/O watch will
> fire continuously and, with TCG, the CPU thread will never run.
>
> 1) Char backend asks front end if it can write
> 2) Front end says no
> 3) poll() finds the char backend's descriptor is available
> 4) Goto (1)
>
> What we really want is this (note that step 3 avoids the busy wait):
>
> 1) Char backend asks front end if it can write
> 2) Front end says no
> 3) poll() goes on without char backend's descriptor
> 4) Goto (1) until qemu_chr_accept_input() called
>
> 5) Char backend asks front end if it can write
> 6) Front end says yes
> 7) poll() finds the char backend's descriptor is available
> 8) Backend handler called
>
> After this patch, the IOWatchPoll source and the watch source are
> separated. The IOWatchPoll is simply a hook that runs during the prepare
> phase on each main loop iteration. The hook adds/removes the actual
> source depending on the return value from can_read.
>
> A simple reproducer is
>
> qemu-system-i386 -serial mon:stdio
>
> ... followed by banging on the terminal as much as you can. :)
Mouse wheel paste does the trick nicely for me :)
> Without this patch, emulation will hang.
>
Emulation still hangs for me with this patch. It also plays foul with
Anthonys rework of my patch. The only way I can get it to work is
either mine or Anthonys patch and a revert of this one. I think your
patch adversely affects the timeout logic that Anthonys patch relies
on.
Ping me if you want my replication instructions. I will have to send
images as Microblaze doesn't like a null guest.
Regards,
Peter
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero
2013-04-05 15:59 [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero Paolo Bonzini
2013-04-06 19:00 ` Amit Shah
2013-04-07 5:09 ` Peter Crosthwaite
@ 2013-04-08 21:55 ` Anthony Liguori
2 siblings, 0 replies; 6+ messages in thread
From: Anthony Liguori @ 2013-04-08 21:55 UTC (permalink / raw)
To: Paolo Bonzini, qemu-devel; +Cc: aliguori
Applied. Thanks.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-04-08 21:56 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-05 15:59 [Qemu-devel] [PATCH v2] qemu-char: eliminate busy waiting on can_read returning zero Paolo Bonzini
2013-04-06 19:00 ` Amit Shah
2013-04-07 18:49 ` Paolo Bonzini
2013-04-07 22:43 ` Peter Crosthwaite
2013-04-07 5:09 ` Peter Crosthwaite
2013-04-08 21:55 ` Anthony Liguori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).