qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] console: make QMP screendump use coroutine


From: Marc-André Lureau
Subject: Re: [PATCH] console: make QMP screendump use coroutine
Date: Fri, 6 Mar 2020 11:03:37 +0100

Hi

On Fri, Mar 6, 2020 at 9:44 AM Markus Armbruster <address@hidden> wrote:
>
> Marc-André Lureau <address@hidden> writes:
>
> > Hi
> >
> > On Tue, Mar 3, 2020 at 8:41 AM Markus Armbruster <address@hidden> wrote:
> [...]
> >> >> Let's take a step back.
> >> >>
> >> >> The actual problem is to find the coroutine in graphic_hw_update_done(),
> >> >> so you can wake it.
> >> >>
> >> >> Your solution stores the coroutine in the QemuConsole, because that's
> >> >> readily available in graphic_hw_update_done().
> >> >>
> >> >> However, it really, really doesn't belong there, it belongs to the
> >> >> monitor.  Works anyway only because QMP commands execute one after the
> >> >> other.
>
> As discussed in the "[PATCH v4 1/4] qapi: Add a 'coroutine' flag for
> commands" sub-thread, HMP commands may execute interleaved.  Your code
> still works, because it only ever abuses QemuConsole with QMP.  But it's
> brittle.
>
> Looks like we'll change HMP not to run interleaved.  That adds a belt to
> the suspenders.  You might argue that's robust enough.
>
> But it's not just the brittleness I dislike.  Storing per-monitor-
> command data in QemuConsole is ugly as sin.  Arguing that it works
> because commands are strictly serialized, and that burying one more
> dependence on such serialization deep in command code won't make the
> situation appreciably worse, doesn't change the fact that QemuConsole
> has no business holding per-monitor-command data.

It is data (the monitor coroutine) associated with an event handler
(graphic-update).

Someone has to hold the handler/data, and the console seems appropriate.

We could abstract this a bit, for ex, having a GHookList, but as long
as there is only one handler, it's unnecessary.

>
> >> >>
> >> >> Kevin suggested using a CoQueue to avoid this unspoken dependency.  You
> >> >> object, because it could make readers assume multiple screendump
> >> >> commands could run concurrently, which is not the case.
> >> >>
> >> >> Alright, let's KISS: since there's just one main loop, there's just one
> >> >> coroutine: @qmp_dispatcher_co.  Let's use that, so the dependency on
> >> >> "one command after the other" is explicit and obvious.
> >> >
> >> > Ugh... If you choose that this is the way to go, please add an assertion
> >> > at least that we are indeed in qmp_dispatcher_co before yielding.
> >>
> >> No objection.
> >>
> >> To apply the QMP coroutine infrastructure for 5.0, I need a user.  We
> >> have two: block_resize from Kevin, and screendump from Marc-André.
> >> Neither is quite ready, yet.  I'll wait for a respin of either one.
> >>
> >
> > Is this the change you expect?
> >
> > diff --git a/ui/console.c b/ui/console.c
> > index 57df3a5439..d6a8bf0cee 100644
> > --- a/ui/console.c
> > +++ b/ui/console.c
> > @@ -167,7 +167,7 @@ struct QemuConsole {
> >      QEMUFIFO out_fifo;
> >      uint8_t out_fifo_buf[16];
> >      QEMUTimer *kbd_timer;
> > -    Coroutine *screendump_co;
> > +    bool wake_qmp_dispatcher_on_update;
> >
> >      QTAILQ_ENTRY(QemuConsole) next;
> >  };
>
> No, because it still stores per-command data in QemuConsole.  You need
> to, because...
>
> > @@ -263,8 +263,8 @@ static void gui_setup_refresh(DisplayState *ds)
> >
> >  void graphic_hw_update_done(QemuConsole *con)
> >  {
> > -    if (con && con->screendump_co) {
> > -        aio_co_wake(con->screendump_co);
> > +    if (con->wake_qmp_dispatcher_on_update) {
> > +        aio_co_wake(qmp_dispatcher_co);
>
> ... you may call aio_co_wake() only while @qmp_dispatcher_co is waiting
> for it after yielding ...
>
> >      }
> >  }
> >
> > @@ -376,12 +376,15 @@ void qmp_screendump(const char *filename, bool
> > has_device, const char *device,
> >      }
> >
> >      if (qemu_in_coroutine()) {
> > -        assert(!con->screendump_co);
> > -        con->screendump_co = qemu_coroutine_self();
> > +        /*
> > +         * The coroutine code is generic, but we are supposed to be on
> > +         * the QMP dispatcher coroutine, and we will resume only that now.
> > +         */
> > +        assert(qemu_coroutine_self() == qmp_dispatcher_co);
> > +        con->wake_qmp_dispatcher_on_update = true;
> >          aio_bh_schedule_oneshot(qemu_get_aio_context(),
> >                                  graphic_hw_update_bh, con);
> >          qemu_coroutine_yield();
>
> ... here.  I missed that need when I suggested to use
> @qmp_dispatcher_co.  Sorry.
>
> > -        con->screendump_co = NULL;
> > +        con->wake_qmp_dispatcher_on_update = false;
> >      }
>
> Have a look at qxl, the only provider of asynchronous .gfx_update().
> The actual work is done in qxl-render.c.  qxl_render_update(),
> qxl_render_update_area_bh(), qxl_render_update_area_unlocked(),
> qxl_render_update_area_done() cooperate carefully to support multiple
> updates in flight.
>
> I guess that's necessary because we also call graphic_hw_update() from
> display code such as ui/vnc.c and ui/spice-display.c.
>
> Before your patch, none of these users waits for an asynchronous update
> to complete, as far as I can tell.  Afterwards, QMP screendump does.
> Whether more users should I can't tell.  Gerd, can you?
>
> Your patch communicates completion to screendump by making
> graphic_hw_update() wake a coroutine.  It stores the coroutine in
> QemuConsole, exploiting that only one call site actually waits for an
> asynchronous update to complete, and that caller is never reentered.
>
> This new mechanism is not usable for any other caller, unless it somehow
> synchronizes with screendump to avoid reentrance.
>
> Shouldn't we offer a more generally useful way to wait for asynchronous
> update to complete?  Kevin's idea to use a queue of waiters sounds more
> appropriate than ever to me.
>

A CoQueue is a queue of coroutine. Similarly to the GHook suggestion,
I don't see much point as long as there is a single known handler.
Covering it through those abstractions will just lead to wrong
assumptions or code harder to read imho.

-- 
Marc-André Lureau



reply via email to

[Prev in Thread] Current Thread [Next in Thread]